From cbc5ad473a58448cf81b05ddb44b55cc511a6517 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sat, 13 Apr 2024 16:23:09 +0000 Subject: [PATCH] Merge branch vnc into master --- .gitattributes | 2 +- CONTRIBUTING.md | 34 +- app/build.gradle | 5 +- app/src/main/java/io/xpipe/app/Main.java | 8 +- .../app/browser/BrowserBookmarkComp.java | 88 +--- .../app/browser/BrowserBreadcrumbBar.java | 4 +- .../xpipe/app/browser/BrowserClipboard.java | 1 + .../xpipe/app/browser/BrowserFilterComp.java | 8 +- .../app/browser/BrowserGreetingComp.java | 12 +- .../io/xpipe/app/browser/BrowserModel.java | 185 -------- .../io/xpipe/app/browser/BrowserNavBar.java | 9 +- .../app/browser/BrowserOverviewComp.java | 6 +- .../xpipe/app/browser/BrowserSavedState.java | 2 + .../app/browser/BrowserSavedStateImpl.java | 2 +- .../app/browser/BrowserSelectionListComp.java | 4 +- .../app/browser/BrowserStatusBarComp.java | 18 +- .../app/browser/BrowserTransferComp.java | 48 +- .../app/browser/BrowserTransferModel.java | 5 +- .../app/browser/BrowserTransferProgress.java | 4 +- .../xpipe/app/browser/BrowserWelcomeComp.java | 61 +-- .../app/browser/StandaloneFileBrowser.java | 73 --- .../browser/action/ApplicationPathAction.java | 4 +- .../app/browser/action/BranchAction.java | 4 +- .../app/browser/action/BrowserAction.java | 17 +- .../action/BrowserActionFormatter.java | 2 +- .../action/ExecuteApplicationAction.java | 4 +- .../xpipe/app/browser/action/LeafAction.java | 23 +- .../browser/action/MultiExecuteAction.java | 16 +- .../browser/action/ToFileCommandAction.java | 4 +- .../app/browser/{ => file}/BrowserAlerts.java | 2 +- .../{ => file}/BrowserContextMenu.java | 11 +- .../app/browser/{ => file}/BrowserEntry.java | 6 +- .../{ => file}/BrowserFileListComp.java | 51 +- .../{ => file}/BrowserFileListCompEntry.java | 4 +- .../{ => file}/BrowserFileListModel.java | 22 +- .../{ => file}/BrowserFileOverviewComp.java | 9 +- .../BrowserQuickAccessButtonComp.java | 3 +- .../BrowserQuickAccessContextMenu.java | 205 ++++---- .../browser/{ => file}/FileSystemHelper.java | 28 +- .../browser/{ => fs}/OpenFileSystemCache.java | 2 +- .../browser/{ => fs}/OpenFileSystemComp.java | 15 +- .../{ => fs}/OpenFileSystemHistory.java | 2 +- .../browser/{ => fs}/OpenFileSystemModel.java | 138 ++++-- .../{ => fs}/OpenFileSystemSavedState.java | 2 +- .../icon/BrowserIconDirectoryType.java | 20 +- .../app/browser/icon/BrowserIconFileType.java | 20 +- .../app/browser/icon/FileIconManager.java | 18 +- .../session/BrowserAbstractSessionModel.java | 43 ++ .../browser/session/BrowserChooserComp.java | 150 ++++++ .../browser/session/BrowserChooserModel.java | 106 +++++ .../browser/session/BrowserSessionComp.java | 95 ++++ .../browser/session/BrowserSessionModel.java | 107 +++++ .../session/BrowserSessionMultiTab.java | 44 ++ .../browser/session/BrowserSessionTab.java | 34 ++ .../BrowserSessionTabsComp.java} | 147 ++---- .../java/io/xpipe/app/comp/AppLayoutComp.java | 16 +- .../io/xpipe/app/comp/base/ButtonComp.java | 3 +- .../io/xpipe/app/comp/base/DropdownComp.java | 7 +- .../io/xpipe/app/comp/base/FontIconComp.java | 47 ++ .../app/comp/base/LazyTextFieldComp.java | 3 +- .../xpipe/app/comp/base/ListBoxViewComp.java | 4 +- .../io/xpipe/app/comp/base/MarkdownComp.java | 3 +- .../xpipe/app/comp/base/MultiContentComp.java | 50 +- .../io/xpipe/app/comp/base/OsLogoComp.java | 4 +- .../xpipe/app/comp/base/SideMenuBarComp.java | 25 +- .../xpipe/app/comp/base/StoreToggleComp.java | 5 +- .../xpipe/app/comp/base/SystemStateComp.java | 11 +- .../xpipe/app/comp/base/TileButtonComp.java | 14 +- .../xpipe/app/comp/base/ToggleSwitchComp.java | 2 +- .../app/comp/store/StoreCategoryWrapper.java | 38 +- .../app/comp/store/StoreCreationComp.java | 3 +- .../app/comp/store/StoreCreationMenu.java | 6 +- .../xpipe/app/comp/store/StoreEntryComp.java | 27 +- .../app/comp/store/StoreEntryListComp.java | 9 +- .../comp/store/StoreEntryListStatusComp.java | 36 +- .../xpipe/app/comp/store/StoreIntroComp.java | 16 +- .../comp/store/StoreProviderChoiceComp.java | 11 +- .../store/StoreQuickAccessButtonComp.java | 6 +- .../io/xpipe/app/comp/store/StoreSection.java | 25 +- .../app/comp/store/StoreSectionComp.java | 26 +- .../app/comp/store/StoreSectionMiniComp.java | 20 +- .../xpipe/app/comp/store/StoreViewState.java | 8 +- app/src/main/java/io/xpipe/app/core/App.java | 6 +- .../xpipe/app/core/AppExtensionManager.java | 11 +- .../java/io/xpipe/app/core/AppGreetings.java | 3 +- .../main/java/io/xpipe/app/core/AppI18n.java | 348 +++++++------- .../java/io/xpipe/app/core/AppImages.java | 8 +- .../io/xpipe/app/core/AppLayoutModel.java | 37 +- .../java/io/xpipe/app/core/AppProperties.java | 2 + .../main/java/io/xpipe/app/core/AppTheme.java | 86 +++- .../io/xpipe/app/core/AppWindowHelper.java | 18 +- .../app/core/check/AppFontLoadingCheck.java | 3 +- .../io/xpipe/app/core/check/AppPtbCheck.java | 2 +- .../xpipe/app/core/check/AppShellCheck.java | 1 + .../java/io/xpipe/app/core/mode/BaseMode.java | 5 +- .../app/exchange/LaunchExchangeImpl.java | 7 +- .../app/exchange/MessageExchangeImpls.java | 47 +- .../exchange/cli/InstanceExchangeImpl.java | 18 - .../cli/StoreProviderListExchangeImpl.java | 2 +- .../java/io/xpipe/app/ext/ActionProvider.java | 10 - .../io/xpipe/app/ext/DataStoreProvider.java | 25 +- .../io/xpipe/app/ext/DataStoreProviders.java | 58 ++- .../io/xpipe/app/ext/PrefsChoiceValue.java | 17 +- .../java/io/xpipe/app/ext/PrefsProvider.java | 10 - .../java/io/xpipe/app/ext/ScanProvider.java | 10 - .../xpipe/app/ext/XPipeServiceProviders.java | 36 -- .../main/java/io/xpipe/app/fxcomps/Comp.java | 13 +- .../fxcomps/augment/ContextMenuAugment.java | 5 +- .../io/xpipe/app/fxcomps/impl/ChoiceComp.java | 9 +- .../app/fxcomps/impl/ChoicePaneComp.java | 5 +- .../ContextualFileReferenceChoiceComp.java | 56 ++- .../fxcomps/impl/DataStoreFlowChoiceComp.java | 6 +- .../app/fxcomps/impl/FancyTooltipAugment.java | 39 -- .../io/xpipe/app/fxcomps/impl/FilterComp.java | 7 +- .../app/fxcomps/impl/PrettyImageComp.java | 3 +- .../xpipe/app/fxcomps/impl/PrettySvgComp.java | 3 +- .../app/fxcomps/impl/StoreCategoryComp.java | 31 +- .../app/fxcomps/impl/StringSourceComp.java | 62 +++ .../io/xpipe/app/fxcomps/impl/SvgView.java | 5 +- .../xpipe/app/fxcomps/impl/TextAreaComp.java | 3 +- .../xpipe/app/fxcomps/impl/TextFieldComp.java | 7 +- .../app/fxcomps/impl/ToggleGroupComp.java | 3 +- .../app/fxcomps/impl/TooltipAugment.java | 62 +++ .../app/fxcomps/util/BindingsHelper.java | 287 +----------- .../app/fxcomps/util/ListBindingsHelper.java | 190 ++++++++ .../app/fxcomps/util/PlatformThread.java | 2 - .../io/xpipe/app/fxcomps/util/Shortcuts.java | 2 +- .../fxcomps/util/SimpleChangeListener.java | 19 - .../xpipe/app/launcher/LauncherCommand.java | 2 +- .../io/xpipe/app/launcher/LauncherInput.java | 5 +- .../io/xpipe/app/prefs/AboutCategory.java | 7 +- .../java/io/xpipe/app/prefs/AppPrefs.java | 27 +- .../java/io/xpipe/app/prefs/AppPrefsComp.java | 3 +- .../xpipe/app/prefs/AppPrefsSidebarComp.java | 17 +- .../xpipe/app/prefs/AppearanceCategory.java | 22 + .../xpipe/app/prefs/CloseBehaviourAlert.java | 1 + .../xpipe/app/prefs/ExternalEditorType.java | 13 +- .../app/prefs/ExternalRdpClientType.java | 169 +++++++ .../xpipe/app/prefs/LocalShellCategory.java | 5 - .../java/io/xpipe/app/prefs/RdpCategory.java | 31 ++ .../java/io/xpipe/app/prefs/SshCategory.java | 28 ++ .../io/xpipe/app/prefs/SupportedLocale.java | 22 +- .../io/xpipe/app/prefs/TerminalCategory.java | 122 +++-- .../xpipe/app/prefs/TroubleshootCategory.java | 3 +- .../io/xpipe/app/prefs/UpdateCheckComp.java | 4 +- .../io/xpipe/app/storage/DataStoreEntry.java | 2 +- .../app/terminal/AlacrittyTerminalType.java | 60 ++- .../app/terminal/CustomTerminalType.java | 3 +- .../app/terminal/ExternalTerminalType.java | 140 +++--- .../xpipe/app/terminal/KittyTerminalType.java | 135 +++--- .../xpipe/app/terminal/TabbyTerminalType.java | 101 ++-- .../xpipe/app/terminal/WezTerminalType.java | 86 ++-- .../app/terminal/WindowsTerminalType.java | 35 +- .../app/update/UpdateAvailableAlert.java | 6 + .../xpipe/app/update/XPipeInstanceHelper.java | 84 ---- .../app/util/DataStoreCategoryChoiceComp.java | 3 +- .../io/xpipe/app/util/DesktopShortcuts.java | 7 +- .../java/io/xpipe/app/util/HostHelper.java | 8 + .../java/io/xpipe/app/util/Hyperlinks.java | 1 + .../java/io/xpipe/app/util/InputHelper.java | 16 +- .../java/io/xpipe/app/util/JfxHelper.java | 9 +- .../io/xpipe/app/util/LicenseProvider.java | 13 +- .../app/util/LicenseRequiredException.java | 8 +- .../io/xpipe/app/util/OptionsBuilder.java | 2 +- .../java/io/xpipe/app/util/PlatformState.java | 22 +- .../java/io/xpipe/app/util/RdpConfig.java | 66 +++ .../java/io/xpipe/app/util/ScanAlert.java | 3 +- .../java/io/xpipe/app/util/ScriptHelper.java | 10 +- .../java/io/xpipe/app/util/ShellTemp.java | 5 +- .../java/io/xpipe/app/util/StringSource.java | 50 ++ .../io/xpipe/app/util/TerminalLauncher.java | 20 +- .../app/util/TerminalLauncherManager.java | 25 +- .../java/io/xpipe/app/util/WindowControl.java | 55 +++ app/src/main/java/module-info.java | 12 +- .../resources/lang/translations_en.properties | 392 ---------------- .../io/xpipe/app/resources/style/bookmark.css | 2 +- .../io/xpipe/app/resources/style/browser.css | 9 + .../xpipe/app/resources/style/header-bars.css | 16 +- .../io/xpipe/app/resources/style/style.css | 12 +- .../java/io/xpipe/beacon/BeaconClient.java | 47 -- .../java/io/xpipe/beacon/XPipeInstance.java | 17 - .../beacon/exchange/cli/InstanceExchange.java | 31 -- beacon/src/main/java/module-info.java | 1 - build.gradle | 7 + .../io/xpipe/core/process/CommandBuilder.java | 12 + .../java/io/xpipe/core/process/OsType.java | 19 + .../io/xpipe/core/process/ProcessControl.java | 4 +- .../io/xpipe/core/process/ShellControl.java | 8 +- .../io/xpipe/core/process/ShellDialect.java | 8 +- .../io/xpipe/core/process/ShellDialects.java | 14 +- .../core/process/ShellLaunchCommand.java | 17 + .../process/WorkingDirectoryFunction.java | 70 +++ .../java/io/xpipe/core/store/FilePath.java | 47 +- .../io/xpipe/core/store/LaunchableStore.java | 8 +- .../java/io/xpipe/core/store/ShellStore.java | 1 - .../io/xpipe/core/util/ModuleLayerLoader.java | 17 +- .../io/xpipe/core/util/XPipeInstallation.java | 16 + dist/base.gradle | 13 + dist/build.gradle | 1 + dist/changelogs/9.0.md | 57 +++ dist/licenses/vernacular-vnc.license | 19 + dist/licenses/vernacular-vnc.properties | 4 + .../ext/base/action/BrowseStoreAction.java | 4 +- .../xpipe/ext/base/action/LaunchAction.java | 41 +- .../ext/base/action/LaunchShortcutAction.java | 55 --- .../xpipe/ext/base/action/XPipeUrlAction.java | 28 +- .../io/xpipe/ext/base/browser/BackAction.java | 10 +- .../browser/BrowseInNativeManagerAction.java | 14 +- .../xpipe/ext/base/browser/ChmodAction.java | 15 +- .../io/xpipe/ext/base/browser/CopyAction.java | 10 +- .../ext/base/browser/CopyPathAction.java | 73 ++- .../xpipe/ext/base/browser/DeleteAction.java | 17 +- .../ext/base/browser/DeleteLinkAction.java | 12 +- .../ext/base/browser/EditFileAction.java | 10 +- .../ext/base/browser/FileTypeAction.java | 4 +- .../ext/base/browser/FollowLinkAction.java | 10 +- .../xpipe/ext/base/browser/ForwardAction.java | 10 +- .../io/xpipe/ext/base/browser/JarAction.java | 14 +- .../xpipe/ext/base/browser/JavapAction.java | 10 +- .../xpipe/ext/base/browser/NewItemAction.java | 22 +- .../ext/base/browser/OpenDirectoryAction.java | 10 +- .../browser/OpenDirectoryInNewTabAction.java | 23 +- .../base/browser/OpenFileDefaultAction.java | 10 +- .../ext/base/browser/OpenFileWithAction.java | 10 +- .../browser/OpenNativeFileDetailsAction.java | 10 +- .../ext/base/browser/OpenTerminalAction.java | 10 +- .../xpipe/ext/base/browser/PasteAction.java | 10 +- .../base/browser/RefreshDirectoryAction.java | 10 +- .../xpipe/ext/base/browser/RenameAction.java | 10 +- .../io/xpipe/ext/base/browser/RunAction.java | 14 +- .../xpipe/ext/base/browser/UnzipAction.java | 10 +- .../io/xpipe/ext/base/script/ScriptStore.java | 8 +- .../base/store/LaunchableTerminalStore.java | 16 + .../resources/lang/translations_de.properties | 3 - gradle/gradle_scripts/extension.gradle | 7 +- gradle/gradle_scripts/vernacular-1.16.jar | Bin 0 -> 100150 bytes lang/README.md | 39 ++ lang/app/strings/fixed_en.properties | 59 +++ lang/app/strings/translations_de.properties | 436 ++++++++++++++++++ .../app/strings/translations_en.properties | 338 ++++++++++++-- lang/app/strings/translations_es.properties | 426 +++++++++++++++++ lang/app/strings/translations_fr.properties | 426 +++++++++++++++++ lang/app/strings/translations_it.properties | 426 +++++++++++++++++ lang/app/strings/translations_ja.properties | 426 +++++++++++++++++ lang/app/strings/translations_nl.properties | 426 +++++++++++++++++ lang/app/strings/translations_pt.properties | 426 +++++++++++++++++ lang/app/strings/translations_ru.properties | 426 +++++++++++++++++ lang/app/strings/translations_tr.properties | 426 +++++++++++++++++ lang/app/strings/translations_zh.properties | 426 +++++++++++++++++ lang/base/strings/translations_de.properties | 109 +++++ .../base/strings}/translations_en.properties | 69 +-- lang/base/strings/translations_es.properties | 108 +++++ lang/base/strings/translations_fr.properties | 108 +++++ lang/base/strings/translations_it.properties | 108 +++++ lang/base/strings/translations_ja.properties | 108 +++++ lang/base/strings/translations_nl.properties | 108 +++++ lang/base/strings/translations_pt.properties | 108 +++++ lang/base/strings/translations_ru.properties | 108 +++++ lang/base/strings/translations_tr.properties | 108 +++++ lang/base/strings/translations_zh.properties | 108 +++++ lang/base/texts/elevation_de.md | 14 + .../lang => lang/base/texts}/elevation_en.md | 0 lang/base/texts/elevation_es.md | 14 + lang/base/texts/elevation_fr.md | 14 + lang/base/texts/elevation_it.md | 14 + lang/base/texts/elevation_ja.md | 14 + lang/base/texts/elevation_nl.md | 14 + lang/base/texts/elevation_pt.md | 14 + lang/base/texts/elevation_ru.md | 14 + lang/base/texts/elevation_tr.md | 14 + lang/base/texts/elevation_zh.md | 14 + lang/base/texts/executionType_de.md | 15 + .../base/texts}/executionType_en.md | 12 +- lang/base/texts/executionType_es.md | 15 + lang/base/texts/executionType_fr.md | 15 + lang/base/texts/executionType_it.md | 15 + lang/base/texts/executionType_ja.md | 15 + lang/base/texts/executionType_nl.md | 15 + lang/base/texts/executionType_pt.md | 15 + lang/base/texts/executionType_ru.md | 15 + lang/base/texts/executionType_tr.md | 15 + lang/base/texts/executionType_zh.md | 15 + lang/base/texts/scriptCompatibility_de.md | 13 + .../base/texts}/scriptCompatibility_en.md | 2 +- lang/base/texts/scriptCompatibility_es.md | 13 + lang/base/texts/scriptCompatibility_fr.md | 13 + lang/base/texts/scriptCompatibility_it.md | 13 + lang/base/texts/scriptCompatibility_ja.md | 13 + lang/base/texts/scriptCompatibility_nl.md | 13 + lang/base/texts/scriptCompatibility_pt.md | 13 + lang/base/texts/scriptCompatibility_ru.md | 13 + lang/base/texts/scriptCompatibility_tr.md | 13 + lang/base/texts/scriptCompatibility_zh.md | 13 + lang/base/texts/scriptDependencies_de.md | 5 + .../base/texts}/scriptDependencies_en.md | 0 lang/base/texts/scriptDependencies_es.md | 5 + lang/base/texts/scriptDependencies_fr.md | 5 + lang/base/texts/scriptDependencies_it.md | 5 + lang/base/texts/scriptDependencies_ja.md | 5 + lang/base/texts/scriptDependencies_nl.md | 5 + lang/base/texts/scriptDependencies_pt.md | 5 + lang/base/texts/scriptDependencies_ru.md | 5 + lang/base/texts/scriptDependencies_tr.md | 5 + lang/base/texts/scriptDependencies_zh.md | 5 + lang/base/texts/script_de.md | 5 + .../lang => lang/base/texts}/script_en.md | 0 lang/base/texts/script_es.md | 5 + lang/base/texts/script_fr.md | 5 + lang/base/texts/script_it.md | 5 + lang/base/texts/script_ja.md | 5 + lang/base/texts/script_nl.md | 5 + lang/base/texts/script_pt.md | 5 + lang/base/texts/script_ru.md | 5 + lang/base/texts/script_tr.md | 5 + lang/base/texts/script_zh.md | 5 + lang/jdbc/strings/translations_de.properties | 20 + lang/jdbc/strings/translations_en.properties | 20 + lang/jdbc/strings/translations_es.properties | 20 + lang/jdbc/strings/translations_fr.properties | 20 + lang/jdbc/strings/translations_it.properties | 20 + lang/jdbc/strings/translations_ja.properties | 20 + lang/jdbc/strings/translations_nl.properties | 20 + lang/jdbc/strings/translations_pt.properties | 20 + lang/jdbc/strings/translations_ru.properties | 20 + lang/jdbc/strings/translations_tr.properties | 20 + lang/jdbc/strings/translations_zh.properties | 20 + lang/proc/strings/translations_de.properties | 299 ++++++++++++ lang/proc/strings/translations_en.properties | 298 ++++++++++++ lang/proc/strings/translations_es.properties | 297 ++++++++++++ lang/proc/strings/translations_fr.properties | 297 ++++++++++++ lang/proc/strings/translations_it.properties | 297 ++++++++++++ lang/proc/strings/translations_ja.properties | 297 ++++++++++++ lang/proc/strings/translations_nl.properties | 297 ++++++++++++ lang/proc/strings/translations_pt.properties | 297 ++++++++++++ lang/proc/strings/translations_ru.properties | 297 ++++++++++++ lang/proc/strings/translations_tr.properties | 297 ++++++++++++ lang/proc/strings/translations_zh.properties | 297 ++++++++++++ lang/proc/texts/elevation_de.md | 11 + lang/proc/texts/elevation_en.md | 11 + lang/proc/texts/elevation_es.md | 11 + lang/proc/texts/elevation_fr.md | 11 + lang/proc/texts/elevation_it.md | 11 + lang/proc/texts/elevation_ja.md | 11 + lang/proc/texts/elevation_nl.md | 11 + lang/proc/texts/elevation_pt.md | 11 + lang/proc/texts/elevation_ru.md | 11 + lang/proc/texts/elevation_tr.md | 11 + lang/proc/texts/elevation_zh.md | 11 + lang/proc/texts/environmentScript_de.md | 9 + lang/proc/texts/environmentScript_en.md | 9 + lang/proc/texts/environmentScript_es.md | 9 + lang/proc/texts/environmentScript_fr.md | 9 + lang/proc/texts/environmentScript_it.md | 9 + lang/proc/texts/environmentScript_ja.md | 9 + lang/proc/texts/environmentScript_nl.md | 9 + lang/proc/texts/environmentScript_pt.md | 9 + lang/proc/texts/environmentScript_ru.md | 9 + lang/proc/texts/environmentScript_tr.md | 9 + lang/proc/texts/environmentScript_zh.md | 9 + lang/proc/texts/proxmoxPassword_de.md | 3 + lang/proc/texts/proxmoxPassword_en.md | 3 + lang/proc/texts/proxmoxPassword_es.md | 3 + lang/proc/texts/proxmoxPassword_fr.md | 3 + lang/proc/texts/proxmoxPassword_it.md | 3 + lang/proc/texts/proxmoxPassword_ja.md | 3 + lang/proc/texts/proxmoxPassword_nl.md | 3 + lang/proc/texts/proxmoxPassword_pt.md | 3 + lang/proc/texts/proxmoxPassword_ru.md | 3 + lang/proc/texts/proxmoxPassword_tr.md | 3 + lang/proc/texts/proxmoxPassword_zh.md | 3 + lang/proc/texts/proxmoxUsername_de.md | 5 + lang/proc/texts/proxmoxUsername_en.md | 5 + lang/proc/texts/proxmoxUsername_es.md | 5 + lang/proc/texts/proxmoxUsername_fr.md | 5 + lang/proc/texts/proxmoxUsername_it.md | 5 + lang/proc/texts/proxmoxUsername_ja.md | 5 + lang/proc/texts/proxmoxUsername_nl.md | 5 + lang/proc/texts/proxmoxUsername_pt.md | 5 + lang/proc/texts/proxmoxUsername_ru.md | 5 + lang/proc/texts/proxmoxUsername_tr.md | 5 + lang/proc/texts/proxmoxUsername_zh.md | 5 + .../texts/rdpPasswordAuthentication_de.md | 3 + .../texts/rdpPasswordAuthentication_en.md | 3 + .../texts/rdpPasswordAuthentication_es.md | 3 + .../texts/rdpPasswordAuthentication_fr.md | 3 + .../texts/rdpPasswordAuthentication_it.md | 3 + .../texts/rdpPasswordAuthentication_ja.md | 3 + .../texts/rdpPasswordAuthentication_nl.md | 3 + .../texts/rdpPasswordAuthentication_pt.md | 3 + .../texts/rdpPasswordAuthentication_ru.md | 3 + .../texts/rdpPasswordAuthentication_tr.md | 3 + .../texts/rdpPasswordAuthentication_zh.md | 3 + lang/proc/texts/rdpTunnelHost_de.md | 5 + lang/proc/texts/rdpTunnelHost_en.md | 5 + lang/proc/texts/rdpTunnelHost_es.md | 5 + lang/proc/texts/rdpTunnelHost_fr.md | 5 + lang/proc/texts/rdpTunnelHost_it.md | 5 + lang/proc/texts/rdpTunnelHost_ja.md | 5 + lang/proc/texts/rdpTunnelHost_nl.md | 5 + lang/proc/texts/rdpTunnelHost_pt.md | 5 + lang/proc/texts/rdpTunnelHost_ru.md | 5 + lang/proc/texts/rdpTunnelHost_tr.md | 5 + lang/proc/texts/rdpTunnelHost_zh.md | 5 + lang/proc/texts/runTempContainer_de.md | 5 + lang/proc/texts/runTempContainer_en.md | 5 + lang/proc/texts/runTempContainer_es.md | 5 + lang/proc/texts/runTempContainer_fr.md | 5 + lang/proc/texts/runTempContainer_it.md | 5 + lang/proc/texts/runTempContainer_ja.md | 5 + lang/proc/texts/runTempContainer_nl.md | 5 + lang/proc/texts/runTempContainer_pt.md | 5 + lang/proc/texts/runTempContainer_ru.md | 5 + lang/proc/texts/runTempContainer_tr.md | 5 + lang/proc/texts/runTempContainer_zh.md | 5 + lang/proc/texts/shellCommand_de.md | 30 ++ lang/proc/texts/shellCommand_en.md | 30 ++ lang/proc/texts/shellCommand_es.md | 30 ++ lang/proc/texts/shellCommand_fr.md | 30 ++ lang/proc/texts/shellCommand_it.md | 30 ++ lang/proc/texts/shellCommand_ja.md | 30 ++ lang/proc/texts/shellCommand_nl.md | 30 ++ lang/proc/texts/shellCommand_pt.md | 30 ++ lang/proc/texts/shellCommand_ru.md | 30 ++ lang/proc/texts/shellCommand_tr.md | 30 ++ lang/proc/texts/shellCommand_zh.md | 30 ++ lang/proc/texts/sshConfigs_de.md | 13 + lang/proc/texts/sshConfigs_en.md | 13 + lang/proc/texts/sshConfigs_es.md | 13 + lang/proc/texts/sshConfigs_fr.md | 13 + lang/proc/texts/sshConfigs_it.md | 13 + lang/proc/texts/sshConfigs_ja.md | 13 + lang/proc/texts/sshConfigs_nl.md | 13 + lang/proc/texts/sshConfigs_pt.md | 13 + lang/proc/texts/sshConfigs_ru.md | 13 + lang/proc/texts/sshConfigs_tr.md | 13 + lang/proc/texts/sshConfigs_zh.md | 13 + .../texts/sshDontInteractWithSystem_de.md | 7 + .../texts/sshDontInteractWithSystem_en.md | 7 + .../texts/sshDontInteractWithSystem_es.md | 7 + .../texts/sshDontInteractWithSystem_fr.md | 7 + .../texts/sshDontInteractWithSystem_it.md | 7 + .../texts/sshDontInteractWithSystem_ja.md | 7 + .../texts/sshDontInteractWithSystem_nl.md | 7 + .../texts/sshDontInteractWithSystem_pt.md | 7 + .../texts/sshDontInteractWithSystem_ru.md | 7 + .../texts/sshDontInteractWithSystem_tr.md | 7 + .../texts/sshDontInteractWithSystem_zh.md | 7 + lang/proc/texts/sshDynamicTunnelBinding_de.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_en.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_es.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_fr.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_it.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_ja.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_nl.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_pt.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_ru.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_tr.md | 5 + lang/proc/texts/sshDynamicTunnelBinding_zh.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_de.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_en.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_es.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_fr.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_it.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_ja.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_nl.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_pt.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_ru.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_tr.md | 5 + lang/proc/texts/sshDynamicTunnelOrigin_zh.md | 5 + lang/proc/texts/sshForwardX11_de.md | 9 + lang/proc/texts/sshForwardX11_en.md | 9 + lang/proc/texts/sshForwardX11_es.md | 9 + lang/proc/texts/sshForwardX11_fr.md | 9 + lang/proc/texts/sshForwardX11_it.md | 9 + lang/proc/texts/sshForwardX11_ja.md | 9 + lang/proc/texts/sshForwardX11_nl.md | 9 + lang/proc/texts/sshForwardX11_pt.md | 9 + lang/proc/texts/sshForwardX11_ru.md | 9 + lang/proc/texts/sshForwardX11_tr.md | 9 + lang/proc/texts/sshForwardX11_zh.md | 9 + lang/proc/texts/sshGateway_de.md | 9 + lang/proc/texts/sshGateway_en.md | 9 + lang/proc/texts/sshGateway_es.md | 9 + lang/proc/texts/sshGateway_fr.md | 9 + lang/proc/texts/sshGateway_it.md | 9 + lang/proc/texts/sshGateway_ja.md | 9 + lang/proc/texts/sshGateway_nl.md | 9 + lang/proc/texts/sshGateway_pt.md | 9 + lang/proc/texts/sshGateway_ru.md | 9 + lang/proc/texts/sshGateway_tr.md | 9 + lang/proc/texts/sshGateway_zh.md | 9 + lang/proc/texts/sshInteraction_de.md | 5 + lang/proc/texts/sshInteraction_en.md | 5 + lang/proc/texts/sshInteraction_es.md | 5 + lang/proc/texts/sshInteraction_fr.md | 5 + lang/proc/texts/sshInteraction_it.md | 5 + lang/proc/texts/sshInteraction_ja.md | 5 + lang/proc/texts/sshInteraction_nl.md | 5 + lang/proc/texts/sshInteraction_pt.md | 5 + lang/proc/texts/sshInteraction_ru.md | 5 + lang/proc/texts/sshInteraction_tr.md | 5 + lang/proc/texts/sshInteraction_zh.md | 5 + lang/proc/texts/sshKey_de.md | 55 +++ lang/proc/texts/sshKey_en.md | 55 +++ lang/proc/texts/sshKey_es.md | 55 +++ lang/proc/texts/sshKey_fr.md | 55 +++ lang/proc/texts/sshKey_it.md | 55 +++ lang/proc/texts/sshKey_ja.md | 55 +++ lang/proc/texts/sshKey_nl.md | 55 +++ lang/proc/texts/sshKey_pt.md | 55 +++ lang/proc/texts/sshKey_ru.md | 55 +++ lang/proc/texts/sshKey_tr.md | 55 +++ lang/proc/texts/sshKey_zh.md | 55 +++ lang/proc/texts/sshLocalTunnelBinding_de.md | 5 + lang/proc/texts/sshLocalTunnelBinding_en.md | 5 + lang/proc/texts/sshLocalTunnelBinding_es.md | 5 + lang/proc/texts/sshLocalTunnelBinding_fr.md | 5 + lang/proc/texts/sshLocalTunnelBinding_it.md | 5 + lang/proc/texts/sshLocalTunnelBinding_ja.md | 5 + lang/proc/texts/sshLocalTunnelBinding_nl.md | 5 + lang/proc/texts/sshLocalTunnelBinding_pt.md | 5 + lang/proc/texts/sshLocalTunnelBinding_ru.md | 5 + lang/proc/texts/sshLocalTunnelBinding_tr.md | 5 + lang/proc/texts/sshLocalTunnelBinding_zh.md | 5 + lang/proc/texts/sshLocalTunnelOrigin_de.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_en.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_es.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_fr.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_it.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_ja.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_nl.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_pt.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_ru.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_tr.md | 7 + lang/proc/texts/sshLocalTunnelOrigin_zh.md | 7 + lang/proc/texts/sshOptions_de.md | 27 ++ lang/proc/texts/sshOptions_en.md | 27 ++ lang/proc/texts/sshOptions_es.md | 27 ++ lang/proc/texts/sshOptions_fr.md | 27 ++ lang/proc/texts/sshOptions_it.md | 27 ++ lang/proc/texts/sshOptions_ja.md | 27 ++ lang/proc/texts/sshOptions_nl.md | 27 ++ lang/proc/texts/sshOptions_pt.md | 27 ++ lang/proc/texts/sshOptions_ru.md | 27 ++ lang/proc/texts/sshOptions_tr.md | 27 ++ lang/proc/texts/sshOptions_zh.md | 27 ++ lang/proc/texts/sshRemoteTunnelBinding_de.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_en.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_es.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_fr.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_it.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_ja.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_nl.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_pt.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_ru.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_tr.md | 5 + lang/proc/texts/sshRemoteTunnelBinding_zh.md | 5 + lang/proc/texts/sshRemoteTunnelOrigin_de.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_en.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_es.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_fr.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_it.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_ja.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_nl.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_pt.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_ru.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_tr.md | 7 + lang/proc/texts/sshRemoteTunnelOrigin_zh.md | 7 + lang/proc/texts/vmwarePassword_de.md | 4 + lang/proc/texts/vmwarePassword_en.md | 4 + lang/proc/texts/vmwarePassword_es.md | 4 + lang/proc/texts/vmwarePassword_fr.md | 4 + lang/proc/texts/vmwarePassword_it.md | 4 + lang/proc/texts/vmwarePassword_ja.md | 4 + lang/proc/texts/vmwarePassword_nl.md | 4 + lang/proc/texts/vmwarePassword_pt.md | 4 + lang/proc/texts/vmwarePassword_ru.md | 4 + lang/proc/texts/vmwarePassword_tr.md | 4 + lang/proc/texts/vmwarePassword_zh.md | 4 + lang/proc/texts/vncTunnelHost_de.md | 5 + lang/proc/texts/vncTunnelHost_en.md | 5 + lang/proc/texts/vncTunnelHost_es.md | 5 + lang/proc/texts/vncTunnelHost_fr.md | 5 + lang/proc/texts/vncTunnelHost_it.md | 5 + lang/proc/texts/vncTunnelHost_ja.md | 5 + lang/proc/texts/vncTunnelHost_nl.md | 5 + lang/proc/texts/vncTunnelHost_pt.md | 5 + lang/proc/texts/vncTunnelHost_ru.md | 5 + lang/proc/texts/vncTunnelHost_tr.md | 5 + lang/proc/texts/vncTunnelHost_zh.md | 5 + lang/uacc/strings/fixed_en.properties | 4 + lang/uacc/strings/translations_de.properties | 37 ++ lang/uacc/strings/translations_en.properties | 41 ++ lang/uacc/strings/translations_es.properties | 36 ++ lang/uacc/strings/translations_fr.properties | 36 ++ lang/uacc/strings/translations_it.properties | 36 ++ lang/uacc/strings/translations_ja.properties | 36 ++ lang/uacc/strings/translations_nl.properties | 36 ++ lang/uacc/strings/translations_pt.properties | 36 ++ lang/uacc/strings/translations_ru.properties | 36 ++ lang/uacc/strings/translations_tr.properties | 36 ++ lang/uacc/strings/translations_zh.properties | 36 ++ lang/uacc/texts/contact_de.md | 6 + lang/uacc/texts/contact_en.md | 6 + lang/uacc/texts/contact_es.md | 6 + lang/uacc/texts/contact_fr.md | 6 + lang/uacc/texts/contact_it.md | 6 + lang/uacc/texts/contact_ja.md | 6 + lang/uacc/texts/contact_nl.md | 6 + lang/uacc/texts/contact_pt.md | 6 + lang/uacc/texts/contact_ru.md | 6 + lang/uacc/texts/contact_tr.md | 6 + lang/uacc/texts/contact_zh.md | 6 + lang/uacc/texts/licenseActivated_de.md | 3 + lang/uacc/texts/licenseActivated_en.md | 3 + lang/uacc/texts/licenseActivated_es.md | 3 + lang/uacc/texts/licenseActivated_fr.md | 3 + lang/uacc/texts/licenseActivated_it.md | 3 + lang/uacc/texts/licenseActivated_ja.md | 3 + lang/uacc/texts/licenseActivated_nl.md | 3 + lang/uacc/texts/licenseActivated_pt.md | 3 + lang/uacc/texts/licenseActivated_ru.md | 3 + lang/uacc/texts/licenseActivated_tr.md | 3 + lang/uacc/texts/licenseActivated_zh.md | 3 + lang/uacc/texts/preview_de.md | 11 + lang/uacc/texts/preview_en.md | 11 + lang/uacc/texts/preview_es.md | 11 + lang/uacc/texts/preview_fr.md | 11 + lang/uacc/texts/preview_it.md | 11 + lang/uacc/texts/preview_ja.md | 11 + lang/uacc/texts/preview_nl.md | 11 + lang/uacc/texts/preview_pt.md | 11 + lang/uacc/texts/preview_ru.md | 11 + lang/uacc/texts/preview_tr.md | 11 + lang/uacc/texts/preview_zh.md | 11 + version | 2 +- 636 files changed, 16725 insertions(+), 3220 deletions(-) delete mode 100644 app/src/main/java/io/xpipe/app/browser/BrowserModel.java delete mode 100644 app/src/main/java/io/xpipe/app/browser/StandaloneFileBrowser.java rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserAlerts.java (99%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserContextMenu.java (92%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserEntry.java (92%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserFileListComp.java (93%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserFileListCompEntry.java (98%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserFileListModel.java (90%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserFileOverviewComp.java (84%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserQuickAccessButtonComp.java (94%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/BrowserQuickAccessContextMenu.java (90%) rename app/src/main/java/io/xpipe/app/browser/{ => file}/FileSystemHelper.java (93%) rename app/src/main/java/io/xpipe/app/browser/{ => fs}/OpenFileSystemCache.java (95%) rename app/src/main/java/io/xpipe/app/browser/{ => fs}/OpenFileSystemComp.java (89%) rename app/src/main/java/io/xpipe/app/browser/{ => fs}/OpenFileSystemHistory.java (98%) rename app/src/main/java/io/xpipe/app/browser/{ => fs}/OpenFileSystemModel.java (85%) rename app/src/main/java/io/xpipe/app/browser/{ => fs}/OpenFileSystemSavedState.java (99%) create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserSessionMultiTab.java create mode 100644 app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTab.java rename app/src/main/java/io/xpipe/app/browser/{BrowserComp.java => session/BrowserSessionTabsComp.java} (57%) create mode 100644 app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/ext/XPipeServiceProviders.java delete mode 100644 app/src/main/java/io/xpipe/app/fxcomps/impl/FancyTooltipAugment.java create mode 100644 app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java create mode 100644 app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java create mode 100644 app/src/main/java/io/xpipe/app/fxcomps/util/ListBindingsHelper.java delete mode 100644 app/src/main/java/io/xpipe/app/fxcomps/util/SimpleChangeListener.java create mode 100644 app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java create mode 100644 app/src/main/java/io/xpipe/app/prefs/RdpCategory.java create mode 100644 app/src/main/java/io/xpipe/app/prefs/SshCategory.java delete mode 100644 app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java create mode 100644 app/src/main/java/io/xpipe/app/util/RdpConfig.java create mode 100644 app/src/main/java/io/xpipe/app/util/StringSource.java create mode 100644 app/src/main/java/io/xpipe/app/util/WindowControl.java delete mode 100644 app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties delete mode 100644 beacon/src/main/java/io/xpipe/beacon/XPipeInstance.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/InstanceExchange.java create mode 100644 core/src/main/java/io/xpipe/core/process/ShellLaunchCommand.java create mode 100644 core/src/main/java/io/xpipe/core/process/WorkingDirectoryFunction.java create mode 100644 dist/changelogs/9.0.md create mode 100644 dist/licenses/vernacular-vnc.license create mode 100644 dist/licenses/vernacular-vnc.properties delete mode 100644 ext/base/src/main/java/io/xpipe/ext/base/action/LaunchShortcutAction.java create mode 100644 ext/base/src/main/java/io/xpipe/ext/base/store/LaunchableTerminalStore.java delete mode 100644 ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_de.properties create mode 100644 gradle/gradle_scripts/vernacular-1.16.jar create mode 100644 lang/README.md create mode 100644 lang/app/strings/fixed_en.properties create mode 100644 lang/app/strings/translations_de.properties rename app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties => lang/app/strings/translations_en.properties (55%) create mode 100644 lang/app/strings/translations_es.properties create mode 100644 lang/app/strings/translations_fr.properties create mode 100644 lang/app/strings/translations_it.properties create mode 100644 lang/app/strings/translations_ja.properties create mode 100644 lang/app/strings/translations_nl.properties create mode 100644 lang/app/strings/translations_pt.properties create mode 100644 lang/app/strings/translations_ru.properties create mode 100644 lang/app/strings/translations_tr.properties create mode 100644 lang/app/strings/translations_zh.properties create mode 100644 lang/base/strings/translations_de.properties rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/strings}/translations_en.properties (64%) create mode 100644 lang/base/strings/translations_es.properties create mode 100644 lang/base/strings/translations_fr.properties create mode 100644 lang/base/strings/translations_it.properties create mode 100644 lang/base/strings/translations_ja.properties create mode 100644 lang/base/strings/translations_nl.properties create mode 100644 lang/base/strings/translations_pt.properties create mode 100644 lang/base/strings/translations_ru.properties create mode 100644 lang/base/strings/translations_tr.properties create mode 100644 lang/base/strings/translations_zh.properties create mode 100644 lang/base/texts/elevation_de.md rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/texts}/elevation_en.md (100%) create mode 100644 lang/base/texts/elevation_es.md create mode 100644 lang/base/texts/elevation_fr.md create mode 100644 lang/base/texts/elevation_it.md create mode 100644 lang/base/texts/elevation_ja.md create mode 100644 lang/base/texts/elevation_nl.md create mode 100644 lang/base/texts/elevation_pt.md create mode 100644 lang/base/texts/elevation_ru.md create mode 100644 lang/base/texts/elevation_tr.md create mode 100644 lang/base/texts/elevation_zh.md create mode 100644 lang/base/texts/executionType_de.md rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/texts}/executionType_en.md (56%) create mode 100644 lang/base/texts/executionType_es.md create mode 100644 lang/base/texts/executionType_fr.md create mode 100644 lang/base/texts/executionType_it.md create mode 100644 lang/base/texts/executionType_ja.md create mode 100644 lang/base/texts/executionType_nl.md create mode 100644 lang/base/texts/executionType_pt.md create mode 100644 lang/base/texts/executionType_ru.md create mode 100644 lang/base/texts/executionType_tr.md create mode 100644 lang/base/texts/executionType_zh.md create mode 100644 lang/base/texts/scriptCompatibility_de.md rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/texts}/scriptCompatibility_en.md (82%) create mode 100644 lang/base/texts/scriptCompatibility_es.md create mode 100644 lang/base/texts/scriptCompatibility_fr.md create mode 100644 lang/base/texts/scriptCompatibility_it.md create mode 100644 lang/base/texts/scriptCompatibility_ja.md create mode 100644 lang/base/texts/scriptCompatibility_nl.md create mode 100644 lang/base/texts/scriptCompatibility_pt.md create mode 100644 lang/base/texts/scriptCompatibility_ru.md create mode 100644 lang/base/texts/scriptCompatibility_tr.md create mode 100644 lang/base/texts/scriptCompatibility_zh.md create mode 100644 lang/base/texts/scriptDependencies_de.md rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/texts}/scriptDependencies_en.md (100%) create mode 100644 lang/base/texts/scriptDependencies_es.md create mode 100644 lang/base/texts/scriptDependencies_fr.md create mode 100644 lang/base/texts/scriptDependencies_it.md create mode 100644 lang/base/texts/scriptDependencies_ja.md create mode 100644 lang/base/texts/scriptDependencies_nl.md create mode 100644 lang/base/texts/scriptDependencies_pt.md create mode 100644 lang/base/texts/scriptDependencies_ru.md create mode 100644 lang/base/texts/scriptDependencies_tr.md create mode 100644 lang/base/texts/scriptDependencies_zh.md create mode 100644 lang/base/texts/script_de.md rename {ext/base/src/main/resources/io/xpipe/ext/base/resources/lang => lang/base/texts}/script_en.md (100%) create mode 100644 lang/base/texts/script_es.md create mode 100644 lang/base/texts/script_fr.md create mode 100644 lang/base/texts/script_it.md create mode 100644 lang/base/texts/script_ja.md create mode 100644 lang/base/texts/script_nl.md create mode 100644 lang/base/texts/script_pt.md create mode 100644 lang/base/texts/script_ru.md create mode 100644 lang/base/texts/script_tr.md create mode 100644 lang/base/texts/script_zh.md create mode 100644 lang/jdbc/strings/translations_de.properties create mode 100644 lang/jdbc/strings/translations_en.properties create mode 100644 lang/jdbc/strings/translations_es.properties create mode 100644 lang/jdbc/strings/translations_fr.properties create mode 100644 lang/jdbc/strings/translations_it.properties create mode 100644 lang/jdbc/strings/translations_ja.properties create mode 100644 lang/jdbc/strings/translations_nl.properties create mode 100644 lang/jdbc/strings/translations_pt.properties create mode 100644 lang/jdbc/strings/translations_ru.properties create mode 100644 lang/jdbc/strings/translations_tr.properties create mode 100644 lang/jdbc/strings/translations_zh.properties create mode 100644 lang/proc/strings/translations_de.properties create mode 100644 lang/proc/strings/translations_en.properties create mode 100644 lang/proc/strings/translations_es.properties create mode 100644 lang/proc/strings/translations_fr.properties create mode 100644 lang/proc/strings/translations_it.properties create mode 100644 lang/proc/strings/translations_ja.properties create mode 100644 lang/proc/strings/translations_nl.properties create mode 100644 lang/proc/strings/translations_pt.properties create mode 100644 lang/proc/strings/translations_ru.properties create mode 100644 lang/proc/strings/translations_tr.properties create mode 100644 lang/proc/strings/translations_zh.properties create mode 100644 lang/proc/texts/elevation_de.md create mode 100644 lang/proc/texts/elevation_en.md create mode 100644 lang/proc/texts/elevation_es.md create mode 100644 lang/proc/texts/elevation_fr.md create mode 100644 lang/proc/texts/elevation_it.md create mode 100644 lang/proc/texts/elevation_ja.md create mode 100644 lang/proc/texts/elevation_nl.md create mode 100644 lang/proc/texts/elevation_pt.md create mode 100644 lang/proc/texts/elevation_ru.md create mode 100644 lang/proc/texts/elevation_tr.md create mode 100644 lang/proc/texts/elevation_zh.md create mode 100644 lang/proc/texts/environmentScript_de.md create mode 100644 lang/proc/texts/environmentScript_en.md create mode 100644 lang/proc/texts/environmentScript_es.md create mode 100644 lang/proc/texts/environmentScript_fr.md create mode 100644 lang/proc/texts/environmentScript_it.md create mode 100644 lang/proc/texts/environmentScript_ja.md create mode 100644 lang/proc/texts/environmentScript_nl.md create mode 100644 lang/proc/texts/environmentScript_pt.md create mode 100644 lang/proc/texts/environmentScript_ru.md create mode 100644 lang/proc/texts/environmentScript_tr.md create mode 100644 lang/proc/texts/environmentScript_zh.md create mode 100644 lang/proc/texts/proxmoxPassword_de.md create mode 100644 lang/proc/texts/proxmoxPassword_en.md create mode 100644 lang/proc/texts/proxmoxPassword_es.md create mode 100644 lang/proc/texts/proxmoxPassword_fr.md create mode 100644 lang/proc/texts/proxmoxPassword_it.md create mode 100644 lang/proc/texts/proxmoxPassword_ja.md create mode 100644 lang/proc/texts/proxmoxPassword_nl.md create mode 100644 lang/proc/texts/proxmoxPassword_pt.md create mode 100644 lang/proc/texts/proxmoxPassword_ru.md create mode 100644 lang/proc/texts/proxmoxPassword_tr.md create mode 100644 lang/proc/texts/proxmoxPassword_zh.md create mode 100644 lang/proc/texts/proxmoxUsername_de.md create mode 100644 lang/proc/texts/proxmoxUsername_en.md create mode 100644 lang/proc/texts/proxmoxUsername_es.md create mode 100644 lang/proc/texts/proxmoxUsername_fr.md create mode 100644 lang/proc/texts/proxmoxUsername_it.md create mode 100644 lang/proc/texts/proxmoxUsername_ja.md create mode 100644 lang/proc/texts/proxmoxUsername_nl.md create mode 100644 lang/proc/texts/proxmoxUsername_pt.md create mode 100644 lang/proc/texts/proxmoxUsername_ru.md create mode 100644 lang/proc/texts/proxmoxUsername_tr.md create mode 100644 lang/proc/texts/proxmoxUsername_zh.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_de.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_en.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_es.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_fr.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_it.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_ja.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_nl.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_pt.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_ru.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_tr.md create mode 100644 lang/proc/texts/rdpPasswordAuthentication_zh.md create mode 100644 lang/proc/texts/rdpTunnelHost_de.md create mode 100644 lang/proc/texts/rdpTunnelHost_en.md create mode 100644 lang/proc/texts/rdpTunnelHost_es.md create mode 100644 lang/proc/texts/rdpTunnelHost_fr.md create mode 100644 lang/proc/texts/rdpTunnelHost_it.md create mode 100644 lang/proc/texts/rdpTunnelHost_ja.md create mode 100644 lang/proc/texts/rdpTunnelHost_nl.md create mode 100644 lang/proc/texts/rdpTunnelHost_pt.md create mode 100644 lang/proc/texts/rdpTunnelHost_ru.md create mode 100644 lang/proc/texts/rdpTunnelHost_tr.md create mode 100644 lang/proc/texts/rdpTunnelHost_zh.md create mode 100644 lang/proc/texts/runTempContainer_de.md create mode 100644 lang/proc/texts/runTempContainer_en.md create mode 100644 lang/proc/texts/runTempContainer_es.md create mode 100644 lang/proc/texts/runTempContainer_fr.md create mode 100644 lang/proc/texts/runTempContainer_it.md create mode 100644 lang/proc/texts/runTempContainer_ja.md create mode 100644 lang/proc/texts/runTempContainer_nl.md create mode 100644 lang/proc/texts/runTempContainer_pt.md create mode 100644 lang/proc/texts/runTempContainer_ru.md create mode 100644 lang/proc/texts/runTempContainer_tr.md create mode 100644 lang/proc/texts/runTempContainer_zh.md create mode 100644 lang/proc/texts/shellCommand_de.md create mode 100644 lang/proc/texts/shellCommand_en.md create mode 100644 lang/proc/texts/shellCommand_es.md create mode 100644 lang/proc/texts/shellCommand_fr.md create mode 100644 lang/proc/texts/shellCommand_it.md create mode 100644 lang/proc/texts/shellCommand_ja.md create mode 100644 lang/proc/texts/shellCommand_nl.md create mode 100644 lang/proc/texts/shellCommand_pt.md create mode 100644 lang/proc/texts/shellCommand_ru.md create mode 100644 lang/proc/texts/shellCommand_tr.md create mode 100644 lang/proc/texts/shellCommand_zh.md create mode 100644 lang/proc/texts/sshConfigs_de.md create mode 100644 lang/proc/texts/sshConfigs_en.md create mode 100644 lang/proc/texts/sshConfigs_es.md create mode 100644 lang/proc/texts/sshConfigs_fr.md create mode 100644 lang/proc/texts/sshConfigs_it.md create mode 100644 lang/proc/texts/sshConfigs_ja.md create mode 100644 lang/proc/texts/sshConfigs_nl.md create mode 100644 lang/proc/texts/sshConfigs_pt.md create mode 100644 lang/proc/texts/sshConfigs_ru.md create mode 100644 lang/proc/texts/sshConfigs_tr.md create mode 100644 lang/proc/texts/sshConfigs_zh.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_de.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_en.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_es.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_fr.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_it.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_ja.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_nl.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_pt.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_ru.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_tr.md create mode 100644 lang/proc/texts/sshDontInteractWithSystem_zh.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_de.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_en.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_es.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_fr.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_it.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_ja.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_nl.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_pt.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_ru.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_tr.md create mode 100644 lang/proc/texts/sshDynamicTunnelBinding_zh.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_de.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_en.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_es.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_fr.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_it.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_ja.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_nl.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_pt.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_ru.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_tr.md create mode 100644 lang/proc/texts/sshDynamicTunnelOrigin_zh.md create mode 100644 lang/proc/texts/sshForwardX11_de.md create mode 100644 lang/proc/texts/sshForwardX11_en.md create mode 100644 lang/proc/texts/sshForwardX11_es.md create mode 100644 lang/proc/texts/sshForwardX11_fr.md create mode 100644 lang/proc/texts/sshForwardX11_it.md create mode 100644 lang/proc/texts/sshForwardX11_ja.md create mode 100644 lang/proc/texts/sshForwardX11_nl.md create mode 100644 lang/proc/texts/sshForwardX11_pt.md create mode 100644 lang/proc/texts/sshForwardX11_ru.md create mode 100644 lang/proc/texts/sshForwardX11_tr.md create mode 100644 lang/proc/texts/sshForwardX11_zh.md create mode 100644 lang/proc/texts/sshGateway_de.md create mode 100644 lang/proc/texts/sshGateway_en.md create mode 100644 lang/proc/texts/sshGateway_es.md create mode 100644 lang/proc/texts/sshGateway_fr.md create mode 100644 lang/proc/texts/sshGateway_it.md create mode 100644 lang/proc/texts/sshGateway_ja.md create mode 100644 lang/proc/texts/sshGateway_nl.md create mode 100644 lang/proc/texts/sshGateway_pt.md create mode 100644 lang/proc/texts/sshGateway_ru.md create mode 100644 lang/proc/texts/sshGateway_tr.md create mode 100644 lang/proc/texts/sshGateway_zh.md create mode 100644 lang/proc/texts/sshInteraction_de.md create mode 100644 lang/proc/texts/sshInteraction_en.md create mode 100644 lang/proc/texts/sshInteraction_es.md create mode 100644 lang/proc/texts/sshInteraction_fr.md create mode 100644 lang/proc/texts/sshInteraction_it.md create mode 100644 lang/proc/texts/sshInteraction_ja.md create mode 100644 lang/proc/texts/sshInteraction_nl.md create mode 100644 lang/proc/texts/sshInteraction_pt.md create mode 100644 lang/proc/texts/sshInteraction_ru.md create mode 100644 lang/proc/texts/sshInteraction_tr.md create mode 100644 lang/proc/texts/sshInteraction_zh.md create mode 100644 lang/proc/texts/sshKey_de.md create mode 100644 lang/proc/texts/sshKey_en.md create mode 100644 lang/proc/texts/sshKey_es.md create mode 100644 lang/proc/texts/sshKey_fr.md create mode 100644 lang/proc/texts/sshKey_it.md create mode 100644 lang/proc/texts/sshKey_ja.md create mode 100644 lang/proc/texts/sshKey_nl.md create mode 100644 lang/proc/texts/sshKey_pt.md create mode 100644 lang/proc/texts/sshKey_ru.md create mode 100644 lang/proc/texts/sshKey_tr.md create mode 100644 lang/proc/texts/sshKey_zh.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_de.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_en.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_es.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_fr.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_it.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_ja.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_nl.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_pt.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_ru.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_tr.md create mode 100644 lang/proc/texts/sshLocalTunnelBinding_zh.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_de.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_en.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_es.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_fr.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_it.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_ja.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_nl.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_pt.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_ru.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_tr.md create mode 100644 lang/proc/texts/sshLocalTunnelOrigin_zh.md create mode 100644 lang/proc/texts/sshOptions_de.md create mode 100644 lang/proc/texts/sshOptions_en.md create mode 100644 lang/proc/texts/sshOptions_es.md create mode 100644 lang/proc/texts/sshOptions_fr.md create mode 100644 lang/proc/texts/sshOptions_it.md create mode 100644 lang/proc/texts/sshOptions_ja.md create mode 100644 lang/proc/texts/sshOptions_nl.md create mode 100644 lang/proc/texts/sshOptions_pt.md create mode 100644 lang/proc/texts/sshOptions_ru.md create mode 100644 lang/proc/texts/sshOptions_tr.md create mode 100644 lang/proc/texts/sshOptions_zh.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_de.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_en.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_es.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_fr.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_it.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_ja.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_nl.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_pt.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_ru.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_tr.md create mode 100644 lang/proc/texts/sshRemoteTunnelBinding_zh.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_de.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_en.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_es.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_fr.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_it.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_ja.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_nl.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_pt.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_ru.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_tr.md create mode 100644 lang/proc/texts/sshRemoteTunnelOrigin_zh.md create mode 100644 lang/proc/texts/vmwarePassword_de.md create mode 100644 lang/proc/texts/vmwarePassword_en.md create mode 100644 lang/proc/texts/vmwarePassword_es.md create mode 100644 lang/proc/texts/vmwarePassword_fr.md create mode 100644 lang/proc/texts/vmwarePassword_it.md create mode 100644 lang/proc/texts/vmwarePassword_ja.md create mode 100644 lang/proc/texts/vmwarePassword_nl.md create mode 100644 lang/proc/texts/vmwarePassword_pt.md create mode 100644 lang/proc/texts/vmwarePassword_ru.md create mode 100644 lang/proc/texts/vmwarePassword_tr.md create mode 100644 lang/proc/texts/vmwarePassword_zh.md create mode 100644 lang/proc/texts/vncTunnelHost_de.md create mode 100644 lang/proc/texts/vncTunnelHost_en.md create mode 100644 lang/proc/texts/vncTunnelHost_es.md create mode 100644 lang/proc/texts/vncTunnelHost_fr.md create mode 100644 lang/proc/texts/vncTunnelHost_it.md create mode 100644 lang/proc/texts/vncTunnelHost_ja.md create mode 100644 lang/proc/texts/vncTunnelHost_nl.md create mode 100644 lang/proc/texts/vncTunnelHost_pt.md create mode 100644 lang/proc/texts/vncTunnelHost_ru.md create mode 100644 lang/proc/texts/vncTunnelHost_tr.md create mode 100644 lang/proc/texts/vncTunnelHost_zh.md create mode 100644 lang/uacc/strings/fixed_en.properties create mode 100644 lang/uacc/strings/translations_de.properties create mode 100644 lang/uacc/strings/translations_en.properties create mode 100644 lang/uacc/strings/translations_es.properties create mode 100644 lang/uacc/strings/translations_fr.properties create mode 100644 lang/uacc/strings/translations_it.properties create mode 100644 lang/uacc/strings/translations_ja.properties create mode 100644 lang/uacc/strings/translations_nl.properties create mode 100644 lang/uacc/strings/translations_pt.properties create mode 100644 lang/uacc/strings/translations_ru.properties create mode 100644 lang/uacc/strings/translations_tr.properties create mode 100644 lang/uacc/strings/translations_zh.properties create mode 100644 lang/uacc/texts/contact_de.md create mode 100644 lang/uacc/texts/contact_en.md create mode 100644 lang/uacc/texts/contact_es.md create mode 100644 lang/uacc/texts/contact_fr.md create mode 100644 lang/uacc/texts/contact_it.md create mode 100644 lang/uacc/texts/contact_ja.md create mode 100644 lang/uacc/texts/contact_nl.md create mode 100644 lang/uacc/texts/contact_pt.md create mode 100644 lang/uacc/texts/contact_ru.md create mode 100644 lang/uacc/texts/contact_tr.md create mode 100644 lang/uacc/texts/contact_zh.md create mode 100644 lang/uacc/texts/licenseActivated_de.md create mode 100644 lang/uacc/texts/licenseActivated_en.md create mode 100644 lang/uacc/texts/licenseActivated_es.md create mode 100644 lang/uacc/texts/licenseActivated_fr.md create mode 100644 lang/uacc/texts/licenseActivated_it.md create mode 100644 lang/uacc/texts/licenseActivated_ja.md create mode 100644 lang/uacc/texts/licenseActivated_nl.md create mode 100644 lang/uacc/texts/licenseActivated_pt.md create mode 100644 lang/uacc/texts/licenseActivated_ru.md create mode 100644 lang/uacc/texts/licenseActivated_tr.md create mode 100644 lang/uacc/texts/licenseActivated_zh.md create mode 100644 lang/uacc/texts/preview_de.md create mode 100644 lang/uacc/texts/preview_en.md create mode 100644 lang/uacc/texts/preview_es.md create mode 100644 lang/uacc/texts/preview_fr.md create mode 100644 lang/uacc/texts/preview_it.md create mode 100644 lang/uacc/texts/preview_ja.md create mode 100644 lang/uacc/texts/preview_nl.md create mode 100644 lang/uacc/texts/preview_pt.md create mode 100644 lang/uacc/texts/preview_ru.md create mode 100644 lang/uacc/texts/preview_tr.md create mode 100644 lang/uacc/texts/preview_zh.md diff --git a/.gitattributes b/.gitattributes index ff4558cd2..1c18a0a4d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -* text=auto +* text=auto eol=lf *.sh text eol=lf *.bat text eol=crlf *.png binary diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b0618d89..aef303d4f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,19 +14,6 @@ There are no real formal contribution guidelines right now, they will maybe come - [dist](dist) - Tools to create a distributable package of XPipe - [ext](ext) - Available XPipe extensions. Essentially every concrete feature implementation is implemented as an extension -## Modularity - -All XPipe components target [Java 21](https://openjdk.java.net/projects/jdk/20/) and make full use of the Java Module System (JPMS). -All components are modularized, including all their dependencies. -In case a dependency is (sadly) not modularized yet, module information is manually added using [extra-java-module-info](https://github.com/gradlex-org/extra-java-module-info). -Further, note that as this is a pretty complicated Java project that fully utilizes modularity, -many IDEs still have problems building this project properly. - -For example, you can't build this project in eclipse or vscode as it will complain about missing modules. -The tested and recommended IDE is IntelliJ. -When setting up the project in IntelliJ, make sure that the correct JDK (Java 21) -is selected both for the project and for gradle itself. - ## Development Setup You need to have an up-to-date version of XPipe installed on your local system in order to properly @@ -39,9 +26,9 @@ Note that in case the current master branch is ahead of the latest release, it m It is therefore recommended to always check out the matching version tag for your local repository and local XPipe installation. You can find the available version tags at https://github.com/xpipe-io/xpipe/tags -You need to have GraalVM Community Edition for Java 21 installed as a JDK to compile the project. +You need to have JDK for Java 22 installed to compile the project. If you are on Linux or macOS, you can easily accomplish that by running the `setup.sh` script. -On Windows, you have to manually install the JDK. +On Windows, you have to manually install a JDK, e.g. from [Adoptium](https://adoptium.net/temurin/releases/?version=22). ## Building and Running @@ -58,6 +45,19 @@ You are also able to properly debug the built production application through two Note that when any unit test is run using a debugger, the XPipe daemon process that is started will also attempt to connect to that debugger through [AttachMe](https://plugins.jetbrains.com/plugin/13263-attachme) as well. +## Modularity and IDEs + +All XPipe components target [Java 22](https://openjdk.java.net/projects/jdk/22/) and make full use of the Java Module System (JPMS). +All components are modularized, including all their dependencies. +In case a dependency is (sadly) not modularized yet, module information is manually added using [extra-java-module-info](https://github.com/gradlex-org/extra-java-module-info). +Further, note that as this is a pretty complicated Java project that fully utilizes modularity, +many IDEs still have problems building this project properly. + +For example, you can't build this project in eclipse or vscode as it will complain about missing modules. +The tested and recommended IDE is IntelliJ. +When setting up the project in IntelliJ, make sure that the correct JDK (Java 22) +is selected both for the project and for gradle itself. + ## Contributing guide Especially when starting out, it might be a good idea to start with easy tasks first. Here's a selection of suitable common tasks that are very easy to implement: @@ -96,3 +96,7 @@ The [sample action](https://github.com/xpipe-io/xpipe/blob/master/ext/base/src/m ### Implementing something else if you want to work on something that was not listed here, you can still do so of course. You can reach out on the [Discord server](https://discord.gg/8y89vS8cRb) to discuss any development plans and get you started. + +### Translations + +See the [translation guide](/lang/README.md) for details. diff --git a/app/build.gradle b/app/build.gradle index 724e050fb..123edacd7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,11 +39,12 @@ dependencies { api 'com.vladsch.flexmark:flexmark-util-visitor:0.64.8' api files("$rootDir/gradle/gradle_scripts/markdowngenerator-1.3.1.1.jar") + api files("$rootDir/gradle/gradle_scripts/vernacular-1.16.jar") api 'info.picocli:picocli:4.7.5' api 'org.kohsuke:github-api:1.321' - api 'io.sentry:sentry:7.6.0' + api 'io.sentry:sentry:7.8.0' api 'org.ocpsoft.prettytime:prettytime:5.0.7.Final' - api 'commons-io:commons-io:2.15.1' + api 'commons-io:commons-io:2.16.1' api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.0" api group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: "2.17.0" api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.17.0" diff --git a/app/src/main/java/io/xpipe/app/Main.java b/app/src/main/java/io/xpipe/app/Main.java index 25c6cadc6..39716c264 100644 --- a/app/src/main/java/io/xpipe/app/Main.java +++ b/app/src/main/java/io/xpipe/app/Main.java @@ -12,11 +12,13 @@ public class Main { return; } - // Since this is not marked as a console application, it will not print anything when you run it in a console on Windows + // Since this is not marked as a console application, it will not print anything when you run it in a console on + // Windows if (args.length == 1 && args[0].equals("--help")) { - System.out.println(""" + System.out.println( + """ The daemon executable xpiped does not accept any command-line arguments. - + For a reference on what you can do from the CLI, take a look at the xpipe CLI executable instead. """); return; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java index 2be82c138..a5b602c96 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java @@ -12,72 +12,46 @@ import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.FilterComp; import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.util.BooleanScope; +import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.DataStoreCategoryChoiceComp; -import io.xpipe.app.util.FixedHierarchyStore; -import io.xpipe.app.util.ThreadHelper; -import io.xpipe.core.store.DataStore; -import io.xpipe.core.store.ShellStore; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import javafx.css.PseudoClass; -import javafx.geometry.Point2D; import javafx.scene.control.Button; -import javafx.scene.input.DragEvent; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.function.Predicate; -final class BrowserBookmarkComp extends SimpleComp { +public final class BrowserBookmarkComp extends SimpleComp { - public static final Timer DROP_TIMER = new Timer("dnd", true); private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); - private final BrowserModel model; - private Point2D lastOver = new Point2D(-1, -1); - private TimerTask activeTask; + private final ObservableValue selected; + private final Predicate applicable; + private final BiConsumer action; - BrowserBookmarkComp(BrowserModel model) { - this.model = model; + public BrowserBookmarkComp( + ObservableValue selected, + Predicate applicable, + BiConsumer action) { + this.selected = selected; + this.applicable = applicable; + this.action = action; } @Override protected Region createSimple() { var filterText = new SimpleStringProperty(); - var open = PlatformThread.sync(model.getSelected()); - Predicate applicable = storeEntryWrapper -> { - return (storeEntryWrapper.getEntry().getStore() instanceof ShellStore - || storeEntryWrapper.getEntry().getStore() instanceof FixedHierarchyStore) - && storeEntryWrapper.getEntry().getValidity().isUsable(); - }; var selectedCategory = new SimpleObjectProperty<>( StoreViewState.get().getActiveCategory().getValue()); BooleanProperty busy = new SimpleBooleanProperty(false); - Consumer action = w -> { - ThreadHelper.runFailableAsync(() -> { - var entry = w.getEntry(); - if (!entry.getValidity().isUsable()) { - return; - } - - if (entry.getStore() instanceof ShellStore fileSystem) { - model.openFileSystemAsync(entry.ref(), null, busy); - } else if (entry.getStore() instanceof FixedHierarchyStore) { - BooleanScope.execute(busy, () -> { - w.refreshChildren(); - }); - } - }); - }; BiConsumer>> augment = (s, comp) -> { comp.disable(Bindings.createBooleanBinding( () -> { @@ -85,14 +59,15 @@ final class BrowserBookmarkComp extends SimpleComp { }, busy)); comp.apply(struc -> { - open.addListener((observable, oldValue, newValue) -> { - struc.get() - .pseudoClassStateChanged( - SELECTED, - newValue != null - && newValue.getEntry() - .get() - .equals(s.getWrapper().getEntry())); + selected.addListener((observable, oldValue, newValue) -> { + PlatformThread.runLaterIfNeeded(() -> { + struc.get() + .pseudoClassStateChanged( + SELECTED, + newValue != null + && newValue.equals( + s.getWrapper().getEntry())); + }); }); }); }; @@ -101,7 +76,7 @@ final class BrowserBookmarkComp extends SimpleComp { StoreSection.createTopLevel( StoreViewState.get().getAllEntries(), storeEntryWrapper -> true, filterText, selectedCategory), augment, - action, + entryWrapper -> action.accept(entryWrapper, busy), true); var category = new DataStoreCategoryChoiceComp( StoreViewState.get().getAllConnectionsCategory(), @@ -125,21 +100,4 @@ final class BrowserBookmarkComp extends SimpleComp { content.getStyleClass().add("bookmark-list"); return content; } - - private void handleHoverTimer(DataStore store, DragEvent event) { - if (lastOver.getX() == event.getX() && lastOver.getY() == event.getY()) { - return; - } - - lastOver = (new Point2D(event.getX(), event.getY())); - activeTask = new TimerTask() { - @Override - public void run() { - if (activeTask != this) {} - - // Platform.runLater(() -> model.openExistingFileSystemIfPresent(store.asNeeded())); - } - }; - DROP_TIMER.schedule(activeTask, 500); - } } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java index ac4b455fc..b2a1f2850 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java @@ -1,9 +1,9 @@ package io.xpipe.app.browser; import atlantafx.base.controls.Breadcrumbs; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.core.store.FileNames; import javafx.scene.Node; import javafx.scene.control.Button; @@ -40,7 +40,7 @@ public class BrowserBreadcrumbBar extends SimpleComp { var breadcrumbs = new Breadcrumbs(); breadcrumbs.setMinWidth(0); - SimpleChangeListener.apply(PlatformThread.sync(model.getCurrentPath()), val -> { + PlatformThread.sync(model.getCurrentPath()).subscribe(val -> { if (val == null) { breadcrumbs.setSelectedCrumb(null); return; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java b/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java index d3a09b826..6010fe912 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java @@ -1,5 +1,6 @@ package io.xpipe.app.browser; +import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.ProcessControlProvider; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java index f1846e14e..65cbbd66a 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java @@ -1,11 +1,11 @@ package io.xpipe.app.browser; import atlantafx.base.theme.Styles; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; import io.xpipe.app.fxcomps.impl.TextFieldComp; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Pos; @@ -29,7 +29,7 @@ public class BrowserFilterComp extends Comp { var expanded = new SimpleBooleanProperty(); var text = new TextFieldComp(filterString, false).createRegion(); var button = new Button(); - new FancyTooltipAugment<>("app.search").augment(button); + new TooltipAugment<>("app.search").augment(button); text.focusedProperty().addListener((observable, oldValue, newValue) -> { if (!newValue && filterString.getValue() == null) { if (button.isFocused()) { @@ -47,7 +47,7 @@ public class BrowserFilterComp extends Comp { text.setMinWidth(0); Styles.toggleStyleClass(text, Styles.LEFT_PILL); - SimpleChangeListener.apply(filterString, val -> { + filterString.subscribe(val -> { if (val == null) { text.getStyleClass().remove(Styles.SUCCESS); } else { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserGreetingComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserGreetingComp.java index 009382a98..3fe6ba9fe 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserGreetingComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserGreetingComp.java @@ -2,8 +2,10 @@ package io.xpipe.app.browser; import atlantafx.base.theme.Styles; import io.xpipe.app.core.AppFont; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.scene.control.Label; import javafx.scene.layout.Region; @@ -15,7 +17,9 @@ public class BrowserGreetingComp extends SimpleComp { protected Region createSimple() { var r = new Label(getText()); AppLayoutModel.get().getSelected().addListener((observableValue, entry, t1) -> { - r.setText(getText()); + PlatformThread.runLaterIfNeeded(() -> { + r.setText(getText()); + }); }); AppFont.setSize(r, 7); r.getStyleClass().add(Styles.TEXT_BOLD); @@ -27,11 +31,11 @@ public class BrowserGreetingComp extends SimpleComp { var hour = ldt.getHour(); String text; if (hour > 18 || hour < 5) { - text = "Good evening"; + text = AppI18n.get("goodEvening"); } else if (hour < 12) { - text = "Good morning"; + text = AppI18n.get("goodMorning"); } else { - text = "Good afternoon"; + text = AppI18n.get("goodAfternoon"); } return text; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserModel.java deleted file mode 100644 index 82d47c21c..000000000 --- a/app/src/main/java/io/xpipe/app/browser/BrowserModel.java +++ /dev/null @@ -1,185 +0,0 @@ -package io.xpipe.app.browser; - -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.app.util.BooleanScope; -import io.xpipe.app.util.FileReference; -import io.xpipe.app.util.ThreadHelper; -import io.xpipe.core.store.FileNames; -import io.xpipe.core.store.FileSystemStore; -import io.xpipe.core.util.FailableFunction; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.Property; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import lombok.Getter; -import lombok.Setter; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -@Getter -public class BrowserModel { - - public static final BrowserModel DEFAULT = new BrowserModel(Mode.BROWSER, BrowserSavedStateImpl.load()); - - private final Mode mode; - private final ObservableList openFileSystems = FXCollections.observableArrayList(); - private final Property selected = new SimpleObjectProperty<>(); - private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this); - private final ObservableList selection = FXCollections.observableArrayList(); - private final BrowserSavedState savedState; - - @Setter - private Consumer> onFinish; - - public BrowserModel(Mode mode, BrowserSavedState savedState) { - this.mode = mode; - this.savedState = savedState; - - selected.addListener((observable, oldValue, newValue) -> { - if (newValue == null) { - selection.clear(); - return; - } - - BindingsHelper.bindContent(selection, newValue.getFileList().getSelection()); - }); - } - - public void restoreState(BrowserSavedState state) { - ThreadHelper.runAsync(() -> { - state.getEntries().forEach(e -> { - restoreStateAsync(e, null); - // Don't try to run everything in parallel as that can be taxing - ThreadHelper.sleep(1000); - }); - }); - } - - public void restoreStateAsync(BrowserSavedState.Entry e, BooleanProperty busy) { - var storageEntry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); - storageEntry.ifPresent(entry -> { - openFileSystemAsync(entry.ref(), model -> e.getPath(), busy); - }); - } - - public void reset() { - synchronized (BrowserModel.this) { - for (OpenFileSystemModel o : new ArrayList<>(openFileSystems)) { - // Don't close busy connections gracefully - // as we otherwise might lock up - if (o.isBusy()) { - continue; - } - - closeFileSystemSync(o); - } - if (savedState != null) { - savedState.save(); - } - } - - // Delete all files - localTransfersStage.clear(); - } - - public void finishChooser() { - if (!getMode().isChooser()) { - throw new IllegalStateException(); - } - - var chosen = new ArrayList<>(selection); - - synchronized (BrowserModel.this) { - for (OpenFileSystemModel openFileSystem : openFileSystems) { - closeFileSystemAsync(openFileSystem); - } - } - - if (chosen.size() == 0) { - return; - } - - var stores = chosen.stream() - .map(entry -> new FileReference( - selected.getValue().getEntry(), entry.getRawFileEntry().getPath())) - .toList(); - onFinish.accept(stores); - } - - public void closeFileSystemAsync(OpenFileSystemModel open) { - ThreadHelper.runAsync(() -> { - closeFileSystemSync(open); - }); - } - - private void closeFileSystemSync(OpenFileSystemModel open) { - if (DataStorage.get().getStoreEntries().contains(open.getEntry().get()) - && savedState != null - && open.getCurrentPath().get() != null) { - savedState.add(new BrowserSavedState.Entry( - open.getEntry().get().getUuid(), open.getCurrentPath().get())); - } - open.closeSync(); - synchronized (BrowserModel.this) { - openFileSystems.remove(open); - } - } - - public void openFileSystemAsync( - DataStoreEntryRef store, - FailableFunction path, - BooleanProperty externalBusy) { - if (store == null) { - return; - } - - ThreadHelper.runFailableAsync(() -> { - OpenFileSystemModel model; - - try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { - model = new OpenFileSystemModel(this, store); - model.initFileSystem(); - model.initSavedState(); - // Prevent multiple calls from interfering with each other - synchronized (BrowserModel.this) { - openFileSystems.add(model); - // The tab pane doesn't automatically select new tabs - selected.setValue(model); - } - } - if (path != null) { - model.initWithGivenDirectory(FileNames.toDirectory(path.apply(model))); - } else { - model.initWithDefaultDirectory(); - } - }); - } - - @Getter - public enum Mode { - BROWSER(false, true, true, true), - SINGLE_FILE_CHOOSER(true, false, true, false), - SINGLE_FILE_SAVE(true, false, true, false), - MULTIPLE_FILE_CHOOSER(true, true, true, false), - SINGLE_DIRECTORY_CHOOSER(true, false, false, true), - MULTIPLE_DIRECTORY_CHOOSER(true, true, false, true); - - private final boolean chooser; - private final boolean multiple; - private final boolean acceptsFiles; - private final boolean acceptsDirectories; - - Mode(boolean chooser, boolean multiple, boolean acceptsFiles, boolean acceptsDirectories) { - this.chooser = chooser; - this.multiple = multiple; - this.acceptsFiles = acceptsFiles; - this.acceptsDirectories = acceptsDirectories; - } - } -} diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java index 3fffcc61e..d77f573dd 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java @@ -1,6 +1,8 @@ package io.xpipe.app.browser; import atlantafx.base.theme.Styles; +import io.xpipe.app.browser.file.BrowserContextMenu; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.FileIconManager; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; @@ -10,7 +12,6 @@ import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.TextFieldComp; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ThreadHelper; import javafx.application.Platform; @@ -42,7 +43,7 @@ public class BrowserNavBar extends SimpleComp { @Override protected Region createSimple() { var path = new SimpleStringProperty(model.getCurrentPath().get()); - SimpleChangeListener.apply(model.getCurrentPath(), (newValue) -> { + model.getCurrentPath().subscribe((newValue) -> { path.set(newValue); }); path.addListener((observable, oldValue, newValue) -> { @@ -58,7 +59,7 @@ public class BrowserNavBar extends SimpleComp { .styleClass(Styles.CENTER_PILL) .styleClass("path-text") .apply(struc -> { - SimpleChangeListener.apply(struc.get().focusedProperty(), val -> { + struc.get().focusedProperty().subscribe(val -> { struc.get() .pseudoClassStateChanged( INVISIBLE, @@ -71,7 +72,7 @@ public class BrowserNavBar extends SimpleComp { } }); - SimpleChangeListener.apply(model.getInOverview(), val -> { + model.getInOverview().subscribe(val -> { // Pseudo classes do not apply if set instantly before shown // If we start a new tab with a directory set, we have to set the pseudo class one pulse later Platform.runLater(() -> { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java index 4622876b7..e4522d3ad 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java @@ -1,10 +1,12 @@ package io.xpipe.app.browser; +import io.xpipe.app.browser.file.BrowserFileOverviewComp; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.comp.base.SimpleTitledPaneComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.VerticalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.ShellControl; @@ -66,7 +68,7 @@ public class BrowserOverviewComp extends SimpleComp { var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots), false); var rootsPane = new SimpleTitledPaneComp(AppI18n.observable("roots"), rootsOverview); - var recent = BindingsHelper.mappedContentBinding( + var recent = ListBindingsHelper.mappedContentBinding( model.getSavedState().getRecentDirectories(), s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory())); var recentOverview = new BrowserFileOverviewComp(model, recent, true); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSavedState.java b/app/src/main/java/io/xpipe/app/browser/BrowserSavedState.java index 396a45486..0d0794f0d 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSavedState.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSavedState.java @@ -1,6 +1,7 @@ package io.xpipe.app.browser; import javafx.collections.ObservableList; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Value; import lombok.extern.jackson.Jacksonized; @@ -18,6 +19,7 @@ public interface BrowserSavedState { @Value @Jacksonized @Builder + @AllArgsConstructor class Entry { UUID uuid; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java b/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java index 55d498c79..15bdb8c3d 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java @@ -27,7 +27,7 @@ public class BrowserSavedStateImpl implements BrowserSavedState { this.lastSystems = FXCollections.observableArrayList(lastSystems); } - static BrowserSavedStateImpl load() { + public static BrowserSavedStateImpl load() { return AppCache.get("browser-state", BrowserSavedStateImpl.class, () -> { return new BrowserSavedStateImpl(FXCollections.observableArrayList()); }); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java index cee9a506b..e339be87a 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java @@ -52,9 +52,9 @@ public class BrowserSelectionListComp extends SimpleComp { protected Region createSimple() { var c = new ListBoxViewComp<>(list, list, entry -> { return Comp.of(() -> { - var wv = PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(entry, false), 20) + var image = PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(entry, false), 24) .createRegion(); - var l = new Label(null, wv); + var l = new Label(null, image); l.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS); l.textProperty().bind(PlatformThread.sync(nameTransformation.apply(entry))); return l; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java index 963334774..c6a320798 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java @@ -1,6 +1,9 @@ package io.xpipe.app.browser; import atlantafx.base.controls.Spacer; +import io.xpipe.app.browser.file.BrowserContextMenu; +import io.xpipe.app.browser.file.BrowserFileListCompEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.core.AppFont; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; @@ -11,6 +14,7 @@ import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.util.HumanReadableFormat; import javafx.beans.binding.Bindings; import javafx.scene.control.ToolBar; +import javafx.scene.input.MouseButton; import javafx.scene.layout.Region; import lombok.EqualsAndHashCode; import lombok.Value; @@ -59,7 +63,7 @@ public class BrowserStatusBarComp extends SimpleComp { private Comp createClipboardStatus() { var cc = BrowserClipboard.currentCopyClipboard; - var ccCount = (BindingsHelper.persist(Bindings.createStringBinding( + var ccCount = Bindings.createStringBinding( () -> { if (cc.getValue() != null && cc.getValue().getEntries().size() > 0) { return cc.getValue().getEntries().size() + " file" @@ -68,7 +72,7 @@ public class BrowserStatusBarComp extends SimpleComp { return null; } }, - cc))); + cc); return new LabelComp(ccCount); } @@ -86,7 +90,7 @@ public class BrowserStatusBarComp extends SimpleComp { .count(); }, model.getFileList().getAll()); - var selectedComp = new LabelComp(BindingsHelper.persist(Bindings.createStringBinding( + var selectedComp = new LabelComp(Bindings.createStringBinding( () -> { if (selectedCount.getValue().intValue() == 0) { return null; @@ -95,7 +99,7 @@ public class BrowserStatusBarComp extends SimpleComp { } }, selectedCount, - allCount))); + allCount)); return selectedComp; } @@ -124,6 +128,10 @@ public class BrowserStatusBarComp extends SimpleComp { }); // Use status bar as an extension of file list - new ContextMenuAugment<>(mouseEvent -> mouseEvent.isSecondaryButtonDown(), null, () -> new BrowserContextMenu(model, null)).augment(new SimpleCompStructure<>(r)); + new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + null, + () -> new BrowserContextMenu(model, null)) + .augment(new SimpleCompStructure<>(r)); } } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java index 29b9b2c37..652431b1c 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -1,12 +1,13 @@ package io.xpipe.app.browser; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.comp.base.LoadingOverlayComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.augment.DragOverPseudoClassAugment; import io.xpipe.app.fxcomps.impl.*; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.storage.DataStorage; import io.xpipe.core.process.OsType; @@ -37,18 +38,22 @@ public class BrowserTransferComp extends SimpleComp { @Override protected Region createSimple() { + var syncItems = PlatformThread.sync(model.getItems()); + var syncDownloaded = PlatformThread.sync(model.getDownloading()); + var syncAllDownloaded = PlatformThread.sync(model.getAllDownloaded()); + var background = new LabelComp(AppI18n.observable("transferDescription")) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) - .visible(BindingsHelper.persist(Bindings.isEmpty(model.getItems()))); + .visible(Bindings.isEmpty(syncItems)); var backgroundStack = new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); - var binding = BindingsHelper.mappedContentBinding(model.getItems(), item -> item.getFileEntry()); + var binding = ListBindingsHelper.mappedContentBinding(syncItems, item -> item.getFileEntry()); var list = new BrowserSelectionListComp( binding, entry -> Bindings.createStringBinding( () -> { - var sourceItem = model.getItems().stream() + var sourceItem = syncItems.stream() .filter(item -> item.getFileEntry() == entry) .findAny(); if (sourceItem.isEmpty()) { @@ -63,27 +68,27 @@ public class BrowserTransferComp extends SimpleComp { .orElse("?"); return FileNames.getFileName(entry.getPath()) + " (" + name + ")"; }, - model.getAllDownloaded())) + syncAllDownloaded)) .apply(struc -> struc.get().setMinHeight(150)) .grow(false, true); - var dragNotice = new LabelComp(model.getAllDownloaded() + var dragNotice = new LabelComp(syncAllDownloaded .flatMap(aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles"))) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left"))) - .hide(PlatformThread.sync(BindingsHelper.persist(Bindings.isEmpty(model.getItems())))) + .hide(Bindings.isEmpty(syncItems)) .grow(true, false) .apply(struc -> struc.get().setPadding(new Insets(8))); var downloadButton = new IconButtonComp("mdi2d-download", () -> { model.download(); }) - .hide(BindingsHelper.persist(Bindings.isEmpty(model.getItems()))) - .disable(PlatformThread.sync(model.getAllDownloaded())) - .apply(new FancyTooltipAugment<>("downloadStageDescription")); + .hide(Bindings.isEmpty(syncItems)) + .disable(syncAllDownloaded) + .apply(new TooltipAugment<>("downloadStageDescription")); var clearButton = new IconButtonComp("mdi2c-close", () -> { model.clear(); }) - .hide(BindingsHelper.persist(Bindings.isEmpty(model.getItems()))); + .hide(Bindings.isEmpty(syncItems)); var clearPane = Comp.derive( new HorizontalComp(List.of(downloadButton, clearButton)) .apply(struc -> struc.get().setSpacing(10)), @@ -122,12 +127,15 @@ public class BrowserTransferComp extends SimpleComp { return; } + if (!(model.getBrowserSessionModel() + .getSelectedEntry() + .getValue() + instanceof OpenFileSystemModel fileSystemModel)) { + return; + } + var files = drag.getEntries(); - model.drop( - model.getBrowserModel() - .getSelected() - .getValue(), - files); + model.drop(fileSystemModel, files); event.setDropCompleted(true); event.consume(); } @@ -140,11 +148,11 @@ public class BrowserTransferComp extends SimpleComp { } }); struc.get().setOnDragDetected(event -> { - if (model.getDownloading().get()) { + if (syncDownloaded.getValue()) { return; } - var selected = model.getItems().stream() + var selected = syncItems.stream() .map(BrowserTransferModel.Item::getFileEntry) .toList(); Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY); @@ -154,7 +162,7 @@ public class BrowserTransferComp extends SimpleComp { return; } - var files = model.getItems().stream() + var files = syncItems.stream() .filter(item -> item.downloadFinished().get()) .map(item -> { try { @@ -191,7 +199,7 @@ public class BrowserTransferComp extends SimpleComp { event.consume(); }); }), - PlatformThread.sync(model.getDownloading())); + syncDownloaded); return stack.styleClass("transfer").createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java index 23e686fa1..e403aceec 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java @@ -1,5 +1,8 @@ package io.xpipe.app.browser; +import io.xpipe.app.browser.file.FileSystemHelper; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ShellTemp; @@ -36,7 +39,7 @@ public class BrowserTransferModel { t.setName("file downloader"); return t; }); - BrowserModel browserModel; + BrowserSessionModel browserSessionModel; ObservableList items = FXCollections.observableArrayList(); BooleanProperty downloading = new SimpleBooleanProperty(); BooleanProperty allDownloaded = new SimpleBooleanProperty(); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java index 6dc36aed6..738606419 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java @@ -9,7 +9,7 @@ public class BrowserTransferProgress { long transferred; long total; - static BrowserTransferProgress empty() { + public static BrowserTransferProgress empty() { return new BrowserTransferProgress(null, 0, 0); } @@ -17,7 +17,7 @@ public class BrowserTransferProgress { return new BrowserTransferProgress(name, 0, size); } - static BrowserTransferProgress finished(String name, long size) { + public static BrowserTransferProgress finished(String name, long size) { return new BrowserTransferProgress(name, size, size); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java index 3700cbf38..a13742ae2 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java @@ -1,10 +1,12 @@ package io.xpipe.app.browser; import atlantafx.base.controls.Spacer; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.TileButtonComp; import io.xpipe.app.core.AppFont; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.HorizontalComp; @@ -12,6 +14,7 @@ import io.xpipe.app.fxcomps.impl.LabelComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.PrettySvgComp; import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.ThreadHelper; import javafx.beans.binding.Bindings; @@ -31,9 +34,9 @@ import java.util.List; public class BrowserWelcomeComp extends SimpleComp { - private final BrowserModel model; + private final BrowserSessionModel model; - public BrowserWelcomeComp(BrowserModel model) { + public BrowserWelcomeComp(BrowserSessionModel model) { this.model = model; } @@ -54,13 +57,14 @@ public class BrowserWelcomeComp extends SimpleComp { hbox.setSpacing(15); if (state == null) { - var header = new Label("Here you will be able to see where you left off last time."); + var header = new Label(); + header.textProperty().bind(AppI18n.observable("browserWelcomeEmpty")); vbox.getChildren().add(header); hbox.setPadding(new Insets(40, 40, 40, 50)); return new VBox(hbox); } - var list = BindingsHelper.filteredContentBinding(state.getEntries(), e -> { + var list = ListBindingsHelper.filteredContentBinding(state.getEntries(), e -> { var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); if (entry.isEmpty()) { return false; @@ -74,14 +78,14 @@ public class BrowserWelcomeComp extends SimpleComp { }); var empty = Bindings.createBooleanBinding(() -> list.isEmpty(), list); - var header = new LabelComp(Bindings.createStringBinding( - () -> { - return !empty.get() - ? "You were recently connected to the following systems:" - : "Here you will be able to see where you left off last time."; - }, - empty)) - .createRegion(); + var headerBinding = BindingsHelper.flatMap(empty, b -> { + if (b) { + return AppI18n.observable("browserWelcomeEmpty"); + } else { + return AppI18n.observable("browserWelcomeSystems"); + } + }); + var header = new LabelComp(headerBinding).createRegion(); AppFont.setSize(header, 1); vbox.getChildren().add(header); @@ -89,10 +93,13 @@ public class BrowserWelcomeComp extends SimpleComp { storeList.setSpacing(8); var listBox = new ListBoxViewComp<>(list, list, e -> { - var disable = new SimpleBooleanProperty(); + var disable = new SimpleBooleanProperty(); var entryButton = entryButton(e, disable); var dirButton = dirButton(e, disable); - return new HorizontalComp(List.of(entryButton, dirButton)); + return new HorizontalComp(List.of(entryButton, dirButton)).apply(struc -> { + ((Region) struc.get().getChildren().get(0)).prefHeightProperty().bind(struc.get().heightProperty()); + ((Region) struc.get().getChildren().get(1)).prefHeightProperty().bind(struc.get().heightProperty()); + }); }) .apply(struc -> { VBox vBox = (VBox) struc.get().getContent(); @@ -125,15 +132,17 @@ public class BrowserWelcomeComp extends SimpleComp { private Comp entryButton(BrowserSavedState.Entry e, BooleanProperty disable) { var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); - var graphic = entry.get() - .getProvider() - .getDisplayIconFileName(entry.get().getStore()); + var graphic = + entry.get().getProvider().getDisplayIconFileName(entry.get().getStore()); var view = PrettyImageHelper.ofFixedSize(graphic, 30, 24); - return new ButtonComp(new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())), view.createRegion(), () -> { - ThreadHelper.runAsync(() -> { - model.restoreStateAsync(e, disable); - }); - }) + return new ButtonComp( + new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())), + view.createRegion(), + () -> { + ThreadHelper.runAsync(() -> { + model.restoreStateAsync(e, disable); + }); + }) .minWidth(250) .accessibleText(DataStorage.get().getStoreDisplayName(entry.get())) .disable(disable) @@ -144,10 +153,10 @@ public class BrowserWelcomeComp extends SimpleComp { private Comp dirButton(BrowserSavedState.Entry e, BooleanProperty disable) { var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); return new ButtonComp(new SimpleStringProperty(e.getPath()), null, () -> { - ThreadHelper.runAsync(() -> { - model.restoreStateAsync(e, disable); - }); - }) + ThreadHelper.runAsync(() -> { + model.restoreStateAsync(e, disable); + }); + }) .accessibleText(e.getPath()) .disable(disable) .styleClass("directory-button") diff --git a/app/src/main/java/io/xpipe/app/browser/StandaloneFileBrowser.java b/app/src/main/java/io/xpipe/app/browser/StandaloneFileBrowser.java deleted file mode 100644 index 35e70e95f..000000000 --- a/app/src/main/java/io/xpipe/app/browser/StandaloneFileBrowser.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.xpipe.app.browser; - -import io.xpipe.app.core.AppFont; -import io.xpipe.app.core.AppI18n; -import io.xpipe.app.core.AppWindowHelper; -import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.app.util.FileReference; -import io.xpipe.core.store.FileSystemStore; -import javafx.beans.property.Property; -import javafx.stage.FileChooser; -import javafx.stage.Window; - -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class StandaloneFileBrowser { - - public static void localOpenFileChooser( - Property fileStoreProperty, Window owner, Map> extensions) { - PlatformThread.runLaterIfNeeded(() -> { - FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle(AppI18n.get("browseFileTitle")); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(AppI18n.get("anyFile"), "*")); - extensions.forEach((key, value) -> { - fileChooser - .getExtensionFilters() - .add(new FileChooser.ExtensionFilter( - key, value.stream().map(v -> "*." + v).toArray(String[]::new))); - }); - - File file = fileChooser.showOpenDialog(owner); - if (file != null && file.exists()) { - fileStoreProperty.setValue(FileReference.local(file.toPath())); - } - }); - } - - public static void openSingleFile( - Supplier> store, Consumer file) { - PlatformThread.runLaterIfNeeded(() -> { - var model = new BrowserModel(BrowserModel.Mode.SINGLE_FILE_CHOOSER, null); - var comp = new BrowserComp(model) - .apply(struc -> struc.get().setPrefSize(1200, 700)) - .apply(struc -> AppFont.normal(struc.get())); - var window = AppWindowHelper.sideWindow(AppI18n.get("openFileTitle"), stage -> comp, false, null); - model.setOnFinish(fileStores -> { - file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null); - window.close(); - }); - window.show(); - model.openFileSystemAsync(store.get(), null, null); - }); - } - - public static void saveSingleFile(Property file) { - PlatformThread.runLaterIfNeeded(() -> { - var model = new BrowserModel(BrowserModel.Mode.SINGLE_FILE_SAVE, null); - var comp = new BrowserComp(model) - .apply(struc -> struc.get().setPrefSize(1200, 700)) - .apply(struc -> AppFont.normal(struc.get())); - var window = AppWindowHelper.sideWindow(AppI18n.get("saveFileTitle"), stage -> comp, true, null); - model.setOnFinish(fileStores -> { - file.setValue(fileStores.size() > 0 ? fileStores.getFirst() : null); - window.close(); - }); - window.show(); - }); - } -} diff --git a/app/src/main/java/io/xpipe/app/browser/action/ApplicationPathAction.java b/app/src/main/java/io/xpipe/app/browser/action/ApplicationPathAction.java index 005cab2fa..be7385715 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/ApplicationPathAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/ApplicationPathAction.java @@ -1,7 +1,7 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import java.util.List; diff --git a/app/src/main/java/io/xpipe/app/browser/action/BranchAction.java b/app/src/main/java/io/xpipe/app/browser/action/BranchAction.java index 31e7a4ce1..6d77f5a5a 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/BranchAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/BranchAction.java @@ -1,7 +1,7 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import java.util.List; diff --git a/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java b/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java index a024c04e8..a496962ea 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java @@ -1,9 +1,10 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.util.ModuleLayerLoader; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCombination; @@ -53,7 +54,7 @@ public interface BrowserAction { return false; } - String getName(OpenFileSystemModel model, List entries); + ObservableValue getName(OpenFileSystemModel model, List entries); default boolean isApplicable(OpenFileSystemModel model, List entries) { return true; @@ -91,15 +92,5 @@ public interface BrowserAction { }) .toList()); } - - @Override - public boolean requiresFullDaemon() { - return true; - } - - @Override - public boolean prioritizeLoading() { - return false; - } } } diff --git a/app/src/main/java/io/xpipe/app/browser/action/BrowserActionFormatter.java b/app/src/main/java/io/xpipe/app/browser/action/BrowserActionFormatter.java index bb8111ca3..39a8cddb0 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/BrowserActionFormatter.java +++ b/app/src/main/java/io/xpipe/app/browser/action/BrowserActionFormatter.java @@ -1,6 +1,6 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; +import io.xpipe.app.browser.file.BrowserEntry; import java.util.List; diff --git a/app/src/main/java/io/xpipe/app/browser/action/ExecuteApplicationAction.java b/app/src/main/java/io/xpipe/app/browser/action/ExecuteApplicationAction.java index 7153cc596..4d1fec818 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/ExecuteApplicationAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/ExecuteApplicationAction.java @@ -1,7 +1,7 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.core.process.ShellControl; import java.util.List; diff --git a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java index 4c7764890..5813546aa 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java @@ -1,19 +1,17 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.Shortcuts; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.ThreadHelper; -import javafx.beans.property.SimpleStringProperty; import javafx.scene.control.Button; import javafx.scene.control.MenuItem; import org.kordamp.ikonli.javafx.FontIcon; import java.util.List; -import java.util.function.UnaryOperator; public interface LeafAction extends BrowserAction { @@ -23,7 +21,7 @@ public interface LeafAction extends BrowserAction { var b = new Button(); b.setOnAction(event -> { // Only accept shortcut actions in the current tab - if (!model.equals(model.getBrowserModel().getSelected().getValue())) { + if (!model.equals(model.getBrowserModel().getSelectedEntry().getValue())) { return; } @@ -39,13 +37,14 @@ public interface LeafAction extends BrowserAction { if (getShortcut() != null) { Shortcuts.addShortcut(b, getShortcut()); } - new FancyTooltipAugment<>(new SimpleStringProperty(getName(model, selected))).augment(b); + var name = getName(model, selected); + new TooltipAugment<>(name).augment(b); var graphic = getIcon(model, selected); if (graphic != null) { b.setGraphic(graphic); } b.setMnemonicParsing(false); - b.setAccessibleText(getName(model, selected)); + b.accessibleTextProperty().bind(name); b.setDisable(!isActive(model, selected)); model.getCurrentPath().addListener((observable, oldValue, newValue) -> { @@ -61,10 +60,10 @@ public interface LeafAction extends BrowserAction { return b; } - default MenuItem toMenuItem( - OpenFileSystemModel model, List selected, UnaryOperator nameFunc) { - var name = nameFunc.apply(getName(model, selected)); - var mi = new MenuItem(name); + default MenuItem toMenuItem(OpenFileSystemModel model, List selected) { + var name = getName(model, selected); + var mi = new MenuItem(); + mi.textProperty().bind(name); mi.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { BooleanScope.execute(model.getBusy(), () -> { diff --git a/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java b/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java index d5312186d..acd027940 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java @@ -1,11 +1,13 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.TerminalLauncher; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.ShellControl; +import javafx.beans.value.ObservableValue; import org.apache.commons.io.FilenameUtils; import java.util.List; @@ -39,9 +41,11 @@ public abstract class MultiExecuteAction implements BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { var t = AppPrefs.get().terminalType().getValue(); - return "in " + (t != null ? t.toTranslatedString().getValue() : "?"); + return AppI18n.observable( + "executeInTerminal", + t != null ? t.toTranslatedString().getValue() : "?"); } @Override @@ -66,8 +70,8 @@ public abstract class MultiExecuteAction implements BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "in background"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("executeInBackground"); } }); } diff --git a/app/src/main/java/io/xpipe/app/browser/action/ToFileCommandAction.java b/app/src/main/java/io/xpipe/app/browser/action/ToFileCommandAction.java index 3202aae99..a14311e3d 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/ToFileCommandAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/ToFileCommandAction.java @@ -1,7 +1,7 @@ package io.xpipe.app.browser.action; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.util.FileOpener; import io.xpipe.core.process.ShellControl; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserAlerts.java similarity index 99% rename from app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserAlerts.java index 487dbd46f..f7b359ec9 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserAlerts.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserAlerts.java @@ -1,4 +1,4 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppWindowHelper; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java similarity index 92% rename from app/src/main/java/io/xpipe/app/browser/BrowserContextMenu.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java index a31eb56e9..edfd9cf14 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java @@ -1,8 +1,9 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.core.AppFont; import io.xpipe.app.util.LicenseProvider; import javafx.scene.control.ContextMenu; @@ -13,7 +14,7 @@ import org.kordamp.ikonli.javafx.FontIcon; import java.util.ArrayList; import java.util.List; -final class BrowserContextMenu extends ContextMenu { +public final class BrowserContextMenu extends ContextMenu { private final OpenFileSystemModel model; private final BrowserEntry source; @@ -74,17 +75,17 @@ final class BrowserContextMenu extends ContextMenu { for (BrowserAction a : all) { var used = resolveIfNeeded(a, selected); if (a instanceof LeafAction la) { - getItems().add(la.toMenuItem(model, used, s -> s)); + getItems().add(la.toMenuItem(model, used)); } if (a instanceof BranchAction la) { - var m = new Menu(a.getName(model, used) + " ..."); + var m = new Menu(a.getName(model, used).getValue() + " ..."); for (LeafAction sub : la.getBranchingActions(model, used)) { var subUsed = resolveIfNeeded(sub, selected); if (!sub.isApplicable(model, subUsed)) { continue; } - m.getItems().add(sub.toMenuItem(model, subUsed, s -> s)); + m.getItems().add(sub.toMenuItem(model, subUsed)); } var graphic = a.getIcon(model, used); if (graphic != null) { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java similarity index 92% rename from app/src/main/java/io/xpipe/app/browser/BrowserEntry.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java index 253f684ce..49f90ae74 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java @@ -1,4 +1,4 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; import io.xpipe.app.browser.icon.BrowserIconDirectoryType; import io.xpipe.app.browser.icon.BrowserIconFileType; @@ -29,7 +29,7 @@ public class BrowserEntry { return null; } - for (var f : BrowserIconFileType.ALL) { + for (var f : BrowserIconFileType.getAll()) { if (f.matches(rawFileEntry)) { return f; } @@ -43,7 +43,7 @@ public class BrowserEntry { return null; } - for (var f : BrowserIconDirectoryType.ALL) { + for (var f : BrowserIconDirectoryType.getAll()) { if (f.matches(rawFileEntry)) { return f; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java similarity index 93% rename from app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java index f26090f42..71941f01e 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java @@ -1,15 +1,15 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; import atlantafx.base.controls.Spacer; import atlantafx.base.theme.Styles; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.icon.FileIconManager; import io.xpipe.app.comp.base.LazyTextFieldComp; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.HumanReadableFormat; @@ -48,7 +48,7 @@ import java.util.Objects; import static io.xpipe.app.util.HumanReadableFormat.byteCount; import static javafx.scene.control.TableColumn.SortType.ASCENDING; -final class BrowserFileListComp extends SimpleComp { +public final class BrowserFileListComp extends SimpleComp { private static final PseudoClass HIDDEN = PseudoClass.getPseudoClass("hidden"); private static final PseudoClass EMPTY = PseudoClass.getPseudoClass("empty"); @@ -71,7 +71,8 @@ final class BrowserFileListComp extends SimpleComp { @SuppressWarnings("unchecked") private TableView createTable() { - var filenameCol = new TableColumn("Name"); + var filenameCol = new TableColumn(); + filenameCol.textProperty().bind(AppI18n.observable("name")); filenameCol.setCellValueFactory(param -> new SimpleStringProperty( param.getValue() != null ? FileNames.getFileName( @@ -81,17 +82,20 @@ final class BrowserFileListComp extends SimpleComp { filenameCol.setSortType(ASCENDING); filenameCol.setCellFactory(col -> new FilenameCell(fileList.getEditing())); - var sizeCol = new TableColumn("Size"); + var sizeCol = new TableColumn(); + sizeCol.textProperty().bind(AppI18n.observable("size")); sizeCol.setCellValueFactory(param -> new SimpleLongProperty( param.getValue().getRawFileEntry().resolved().getSize())); sizeCol.setCellFactory(col -> new FileSizeCell()); - var mtimeCol = new TableColumn("Modified"); + var mtimeCol = new TableColumn(); + mtimeCol.textProperty().bind(AppI18n.observable("modified")); mtimeCol.setCellValueFactory(param -> new SimpleObjectProperty<>( param.getValue().getRawFileEntry().resolved().getDate())); mtimeCol.setCellFactory(col -> new FileTimeCell()); - var modeCol = new TableColumn("Attributes"); + var modeCol = new TableColumn(); + modeCol.textProperty().bind(AppI18n.observable("attributes")); modeCol.setCellValueFactory(param -> new SimpleObjectProperty<>( param.getValue().getRawFileEntry().resolved().getMode())); modeCol.setCellFactory(col -> new FileModeCell()); @@ -122,7 +126,7 @@ final class BrowserFileListComp extends SimpleComp { } private void prepareTableSelectionModel(TableView table) { - if (!fileList.getMode().isMultiple()) { + if (!fileList.getSelectionMode().isMultiple()) { table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); } else { table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); @@ -142,9 +146,9 @@ final class BrowserFileListComp extends SimpleComp { .getPath())); // Remove unsuitable selection toSelect.removeIf(browserEntry -> (browserEntry.getRawFileEntry().getKind() == FileKind.DIRECTORY - && !fileList.getMode().isAcceptsDirectories()) + && !fileList.getSelectionMode().isAcceptsDirectories()) || (browserEntry.getRawFileEntry().getKind() != FileKind.DIRECTORY - && !fileList.getMode().isAcceptsFiles())); + && !fileList.getSelectionMode().isAcceptsFiles())); fileList.getSelection().setAll(toSelect); Platform.runLater(() -> { @@ -268,7 +272,7 @@ final class BrowserFileListComp extends SimpleComp { return false; }, - null, + null, () -> { if (row.getItem() != null && row.getItem().isSynthetic()) { return null; @@ -505,16 +509,21 @@ final class BrowserFileListComp extends SimpleComp { .get(); var quickAccess = new BrowserQuickAccessButtonComp( () -> getTableRow().getItem(), fileList.getFileSystemModel()) - .hide(BindingsHelper.persist(Bindings.createBooleanBinding( - () -> { - var item = getTableRow().getItem(); - var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY; - var isParentLink = item - .getRawFileEntry() - .equals(fileList.getFileSystemModel().getCurrentParentDirectory()); - return notDir || isParentLink; - }, - itemProperty()))) + .hide(Bindings.createBooleanBinding( + () -> { + var item = getTableRow().getItem(); + var notDir = item.getRawFileEntry() + .resolved() + .getKind() + != FileKind.DIRECTORY; + var isParentLink = item.getRawFileEntry() + .equals(fileList.getFileSystemModel() + .getCurrentParentDirectory()); + return notDir || isParentLink; + }, + itemProperty()) + .not() + .not()) .createRegion(); editing.addListener((observable, oldValue, newValue) -> { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java similarity index 98% rename from app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java index 3a04eb42a..97dd5eefa 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java @@ -1,5 +1,7 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; +import io.xpipe.app.browser.BrowserClipboard; +import io.xpipe.app.browser.BrowserSelectionListComp; import io.xpipe.core.store.FileKind; import javafx.geometry.Point2D; import javafx.scene.Node; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java similarity index 90% rename from app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java index ac21ec5d2..2510bbc10 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java @@ -1,6 +1,7 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileNames; @@ -25,6 +26,8 @@ public final class BrowserFileListModel { static final Comparator FILE_TYPE_COMPARATOR = Comparator.comparing(path -> path.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY); + private final OpenFileSystemModel.SelectionMode selectionMode; + private final OpenFileSystemModel fileSystemModel; private final Property> comparatorProperty = new SimpleObjectProperty<>(FILE_TYPE_COMPARATOR); @@ -33,13 +36,14 @@ public final class BrowserFileListModel { private final ObservableList previousSelection = FXCollections.observableArrayList(); private final ObservableList selection = FXCollections.observableArrayList(); private final ObservableList selectedRaw = - BindingsHelper.mappedContentBinding(selection, entry -> entry.getRawFileEntry()); + ListBindingsHelper.mappedContentBinding(selection, entry -> entry.getRawFileEntry()); private final Property draggedOverDirectory = new SimpleObjectProperty<>(); private final Property draggedOverEmpty = new SimpleBooleanProperty(); private final Property editing = new SimpleObjectProperty<>(); - public BrowserFileListModel(OpenFileSystemModel fileSystemModel) { + public BrowserFileListModel(OpenFileSystemModel.SelectionMode selectionMode, OpenFileSystemModel fileSystemModel) { + this.selectionMode = selectionMode; this.fileSystemModel = fileSystemModel; fileSystemModel.getFilter().addListener((observable, oldValue, newValue) -> { @@ -51,10 +55,6 @@ public final class BrowserFileListModel { }); } - public BrowserModel.Mode getMode() { - return fileSystemModel.getBrowserModel().getMode(); - } - public void setAll(Stream newFiles) { try (var s = newFiles) { var parent = fileSystemModel.getCurrentParentDirectory(); @@ -135,12 +135,6 @@ public final class BrowserFileListModel { } public void onDoubleClick(BrowserEntry entry) { - if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY - && getMode().equals(BrowserModel.Mode.SINGLE_FILE_CHOOSER)) { - getFileSystemModel().getBrowserModel().finishChooser(); - return; - } - if (entry.getRawFileEntry().resolved().getKind() == FileKind.DIRECTORY) { fileSystemModel.cdAsync(entry.getRawFileEntry().resolved().getPath()); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java similarity index 84% rename from app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java index 87d70f23a..1f263631b 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java @@ -1,5 +1,6 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIcons; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.VBoxViewComp; @@ -31,8 +32,10 @@ public class BrowserFileOverviewComp extends SimpleComp { Function> factory = entry -> { return Comp.of(() -> { var icon = BrowserIcons.createIcon(entry); - var graphic = new HorizontalComp(List.of(icon, - new BrowserQuickAccessButtonComp(() -> new BrowserEntry(entry, model.getFileList(),false),model))); + var graphic = new HorizontalComp(List.of( + icon, + new BrowserQuickAccessButtonComp( + () -> new BrowserEntry(entry, model.getFileList(), false), model))); var l = new Button(entry.getPath(), graphic.createRegion()); l.setGraphicTextGap(1); l.setOnAction(event -> { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java similarity index 94% rename from app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessButtonComp.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java index fe992ced5..3a2fcbe8c 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java @@ -1,5 +1,6 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.util.InputHelper; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java similarity index 90% rename from app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessContextMenu.java rename to app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java index d56216e5d..382b6cced 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserQuickAccessContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java @@ -1,5 +1,6 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.FileIconManager; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.util.BooleanAnimationTimer; @@ -28,18 +29,105 @@ import java.util.stream.Collectors; public class BrowserQuickAccessContextMenu extends ContextMenu { + private final Supplier base; + private final OpenFileSystemModel model; + private ContextMenu shownBrowserActionsMenu; + private boolean expandBrowserActionMenuKey; + private boolean keyBasedNavigation; + private boolean closeBrowserActionMenuKey; + public BrowserQuickAccessContextMenu(Supplier base, OpenFileSystemModel model) { + this.base = base; + this.model = model; + + addEventFilter(Menu.ON_SHOWING, e -> { + Node content = getSkin().getNode(); + if (content instanceof Region r) { + r.setMaxWidth(500); + } + }); + addEventFilter(Menu.ON_SHOWN, e -> { + Platform.runLater(() -> { + getItems().getFirst().getStyleableNode().requestFocus(); + }); + }); + InputHelper.onLeft(this, false, e -> { + hide(); + e.consume(); + }); + setAutoHide(true); + getStyleClass().add("condensed"); + } + + public void showMenu(Node anchor) { + getItems().clear(); + ThreadHelper.runFailableAsync(() -> { + var entry = base.get(); + if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) { + return; + } + + var actionsMenu = new AtomicReference(); + var r = new Menu(); + var newItems = updateMenuItems(r, entry, true); + Platform.runLater(() -> { + getItems().addAll(r.getItems()); + show(anchor, Side.RIGHT, 0, 0); + }); + }); + } + + private MenuItem createItem(BrowserEntry browserEntry) { + return new QuickAccessMenu(browserEntry).getMenu(); + } + + private List updateMenuItems(Menu m, BrowserEntry entry, boolean updateInstantly) throws Exception { + var newFiles = model.getFileSystem() + .listFiles(entry.getRawFileEntry().resolved().getPath()); + try (var s = newFiles) { + var list = s.map(fileEntry -> fileEntry.resolved()).toList(); + // Wait until all files are listed, i.e. do not skip the stream elements + list = list.subList(0, Math.min(list.size(), 150)); + + var newItems = new ArrayList(); + if (list.isEmpty()) { + var empty = new Menu(""); + empty.getStyleClass().add("leaf"); + newItems.add(empty); + } else { + var browserEntries = list.stream() + .map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false)) + .toList(); + var menus = browserEntries.stream() + .sorted(model.getFileList().order()) + .collect(Collectors.toMap(e -> e, e -> createItem(e), (v1, v2) -> v2, LinkedHashMap::new)); + var dirs = browserEntries.stream() + .filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY) + .toList(); + if (dirs.size() == 1) { + updateMenuItems((Menu) menus.get(dirs.getFirst()), dirs.getFirst(), true); + } + newItems.addAll(menus.values()); + } + if (updateInstantly) { + m.getItems().setAll(newItems); + } + return newItems; + } + } + @Getter class QuickAccessMenu { private final BrowserEntry browserEntry; - private ContextMenu browserActionMenu; private final Menu menu; + private ContextMenu browserActionMenu; public QuickAccessMenu(BrowserEntry browserEntry) { this.browserEntry = browserEntry; this.menu = new Menu( // Use original name, not the link target browserEntry.getRawFileEntry().getName(), - PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24) + PrettyImageHelper.ofFixedSizeSquare( + FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24) .createRegion()); createMenu(); addInputListeners(); @@ -48,7 +136,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { private void createMenu() { var fileEntry = browserEntry.getRawFileEntry(); if (fileEntry.resolved().getKind() != FileKind.DIRECTORY) { - createFileMenu(); + createFileMenu(); } else { createDirectoryMenu(); } @@ -140,8 +228,9 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { } }); new BooleanAnimationTimer(hover, 100, () -> { - expandDirectoryMenu(empty); - }).start(); + expandDirectoryMenu(empty); + }) + .start(); } private void addInputListeners() { @@ -154,13 +243,15 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { } else { expandBrowserActionMenuKey = false; } - if (event.getCode().equals(KeyCode.LEFT) && browserActionMenu != null && browserActionMenu.isShowing()) { + if (event.getCode().equals(KeyCode.LEFT) + && browserActionMenu != null + && browserActionMenu.isShowing()) { closeBrowserActionMenuKey = true; } else { closeBrowserActionMenuKey = false; } }); - contextMenu.addEventFilter(MouseEvent.ANY,event -> { + contextMenu.addEventFilter(MouseEvent.ANY, event -> { keyBasedNavigation = false; }); } @@ -216,102 +307,4 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { }); } } - - private final Supplier base; - private final OpenFileSystemModel model; - private ContextMenu shownBrowserActionsMenu; - - private boolean expandBrowserActionMenuKey; - private boolean keyBasedNavigation; - private boolean closeBrowserActionMenuKey; - - public BrowserQuickAccessContextMenu(Supplier base, OpenFileSystemModel model) { - this.base = base; - this.model = model; - - addEventFilter(Menu.ON_SHOWING, e -> { - Node content = getSkin().getNode(); - if (content instanceof Region r) { - r.setMaxWidth(500); - } - }); - addEventFilter(Menu.ON_SHOWN, e -> { - Platform.runLater(() -> { - getItems().getFirst().getStyleableNode().requestFocus(); - }); - }); - InputHelper.onLeft(this, false, e -> { - hide(); - e.consume(); - }); - setAutoHide(true); - getStyleClass().add("condensed"); - } - - public void showMenu(Node anchor) { - getItems().clear(); - ThreadHelper.runFailableAsync(() -> { - var entry = base.get(); - if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) { - return; - } - - var actionsMenu = new AtomicReference(); - var r = new Menu(); - var newItems = updateMenuItems(r, entry, true); - Platform.runLater(() -> { - getItems().addAll(r.getItems()); - show(anchor, Side.RIGHT, 0, 0); - }); - }); - } - - private MenuItem createItem(BrowserEntry browserEntry) { - return new QuickAccessMenu(browserEntry).getMenu(); - } - - private List updateMenuItems( - Menu m, - BrowserEntry entry, - boolean updateInstantly) - throws Exception { - var newFiles = model.getFileSystem().listFiles(entry.getRawFileEntry().resolved().getPath()); - try (var s = newFiles) { - var list = s.map(fileEntry -> fileEntry.resolved()).toList(); - // Wait until all files are listed, i.e. do not skip the stream elements - list = list.subList(0, Math.min(list.size(), 150)); - - var newItems = new ArrayList(); - if (list.isEmpty()) { - var empty = new Menu(""); - empty.getStyleClass().add("leaf"); - newItems.add(empty); - } else { - var browserEntries = list.stream() - .map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false)) - .toList(); - var menus = browserEntries.stream() - .sorted(model.getFileList().order()) - .collect(Collectors.toMap( - e -> e, - e -> createItem(e), - (v1, v2) -> v2, - LinkedHashMap::new)); - var dirs = browserEntries.stream() - .filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY) - .toList(); - if (dirs.size() == 1) { - updateMenuItems( - (Menu) menus.get(dirs.getFirst()), - dirs.getFirst(), - true); - } - newItems.addAll(menus.values()); - } - if (updateInstantly) { - m.getItems().setAll(newItems); - } - return newItems; - } - } } diff --git a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java similarity index 93% rename from app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java rename to app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java index 809a1fca4..6698b962c 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java @@ -1,17 +1,17 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.file; +import io.xpipe.app.browser.BrowserTransferProgress; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.process.OsType; -import io.xpipe.core.store.FileKind; -import io.xpipe.core.store.FileNames; -import io.xpipe.core.store.FileSystem; -import io.xpipe.core.store.LocalStore; +import io.xpipe.core.store.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -151,6 +151,18 @@ public class FileSystemHelper { Files.isDirectory(file) ? FileKind.DIRECTORY : FileKind.FILE); } + public static FileSystem.FileEntry getRemoteWrapper(FileSystem fileSystem, String file) throws Exception { + return new FileSystem.FileEntry( + fileSystem, + file, + Instant.now(), + false, + false, + fileSystem.getFileSize(file), + null, + fileSystem.directoryExists(file) ? FileKind.DIRECTORY : FileKind.FILE); + } + public static void dropLocalFilesInto( FileSystem.FileEntry entry, List files, @@ -278,7 +290,8 @@ public class FileSystemHelper { var baseRelative = FileNames.toDirectory(FileNames.getParent(source.getPath())); List list = source.getFileSystem().listFilesRecursively(source.getPath()); for (FileSystem.FileEntry fileEntry : list) { - flatFiles.put(fileEntry, FileNames.toUnix(FileNames.relativize(baseRelative, fileEntry.getPath()))); + var rel = FileNames.toUnix(FileNames.relativize(baseRelative, fileEntry.getPath())); + flatFiles.put(fileEntry, rel); if (fileEntry.getKind() == FileKind.FILE) { // This one is up-to-date and does not need to be recalculated totalSize.addAndGet(fileEntry.getSize()); @@ -293,7 +306,8 @@ public class FileSystemHelper { AtomicLong transferred = new AtomicLong(); for (var e : flatFiles.entrySet()) { var sourceFile = e.getKey(); - var targetFile = FileNames.join(target.getPath(), e.getValue()); + var fixedRelPath = new FilePath(e.getValue()).fileSystemCompatible(target.getFileSystem().getShell().orElseThrow().getOsType()); + var targetFile = FileNames.join(target.getPath(), fixedRelPath.toString()); if (sourceFile.getFileSystem().equals(target.getFileSystem())) { throw new IllegalStateException(); } diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemCache.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemCache.java similarity index 95% rename from app/src/main/java/io/xpipe/app/browser/OpenFileSystemCache.java rename to app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemCache.java index 2ec81bf6e..d3f7b9f4c 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemCache.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemCache.java @@ -1,4 +1,4 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.fs; import io.xpipe.app.util.ShellControlCache; import io.xpipe.core.process.ShellControl; diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java similarity index 89% rename from app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java rename to app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java index b2b15698f..70990781f 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java @@ -1,7 +1,13 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.fs; import atlantafx.base.controls.Spacer; +import io.xpipe.app.browser.BrowserFilterComp; +import io.xpipe.app.browser.BrowserNavBar; +import io.xpipe.app.browser.BrowserOverviewComp; +import io.xpipe.app.browser.BrowserStatusBarComp; import io.xpipe.app.browser.action.BrowserAction; +import io.xpipe.app.browser.file.BrowserContextMenu; +import io.xpipe.app.browser.file.BrowserFileListComp; import io.xpipe.app.comp.base.ModalOverlayComp; import io.xpipe.app.comp.base.MultiContentComp; import io.xpipe.app.fxcomps.Comp; @@ -9,7 +15,6 @@ import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.impl.VerticalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.Shortcuts; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -55,7 +60,9 @@ public class OpenFileSystemComp extends SimpleComp { var menuButton = new MenuButton(null, new FontIcon("mdral-folder_open")); new ContextMenuAugment<>( - event -> event.getButton() == MouseButton.PRIMARY, null, () -> new BrowserContextMenu(model, null)) + event -> event.getButton() == MouseButton.PRIMARY, + null, + () -> new BrowserContextMenu(model, null)) .augment(new SimpleCompStructure<>(menuButton)); menuButton.disableProperty().bind(model.getInOverview()); menuButton.setAccessibleText("Directory options"); @@ -97,7 +104,7 @@ public class OpenFileSystemComp extends SimpleComp { home, model.getCurrentPath().isNull(), fileList, - BindingsHelper.persist(model.getCurrentPath().isNull().not()))); + model.getCurrentPath().isNull().not())); return stack.createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemHistory.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemHistory.java similarity index 98% rename from app/src/main/java/io/xpipe/app/browser/OpenFileSystemHistory.java rename to app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemHistory.java index 0b841fe6a..ede908c1b 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemHistory.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemHistory.java @@ -1,4 +1,4 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.fs; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java similarity index 85% rename from app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java rename to app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java index ed601c4ab..094e84b01 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java @@ -1,7 +1,15 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.fs; +import io.xpipe.app.browser.BrowserSavedState; +import io.xpipe.app.browser.BrowserTransferProgress; import io.xpipe.app.browser.action.BrowserAction; +import io.xpipe.app.browser.file.BrowserFileListModel; +import io.xpipe.app.browser.file.FileSystemHelper; +import io.xpipe.app.browser.session.BrowserAbstractSessionModel; +import io.xpipe.app.browser.session.BrowserSessionModel; +import io.xpipe.app.browser.session.BrowserSessionTab; import io.xpipe.app.comp.base.ModalOverlayComp; +import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; @@ -27,45 +35,90 @@ import java.util.Optional; import java.util.stream.Stream; @Getter -public final class OpenFileSystemModel { +public final class OpenFileSystemModel extends BrowserSessionTab { - private final DataStoreEntryRef entry; private final Property filter = new SimpleStringProperty(); private final BrowserFileListModel fileList; private final ReadOnlyObjectWrapper currentPath = new ReadOnlyObjectWrapper<>(); private final OpenFileSystemHistory history = new OpenFileSystemHistory(); - private final BooleanProperty busy = new SimpleBooleanProperty(); - private final BrowserModel browserModel; private final Property overlay = new SimpleObjectProperty<>(); private final BooleanProperty inOverview = new SimpleBooleanProperty(); - private final String name; - private final String tooltip; private final Property progress = new SimpleObjectProperty<>(BrowserTransferProgress.empty()); private FileSystem fileSystem; private OpenFileSystemSavedState savedState; private OpenFileSystemCache cache; - public OpenFileSystemModel(BrowserModel browserModel, DataStoreEntryRef entry) { - this.browserModel = browserModel; - this.entry = entry; - this.name = DataStorage.get().getStoreDisplayName(entry.get()); - this.tooltip = DataStorage.get().getId(entry.getEntry()).toString(); + public OpenFileSystemModel( + BrowserAbstractSessionModel model, + DataStoreEntryRef entry, + SelectionMode selectionMode) { + super(model, entry); this.inOverview.bind(Bindings.createBooleanBinding( () -> { return currentPath.get() == null; }, currentPath)); - fileList = new BrowserFileListModel(this); + fileList = new BrowserFileListModel(selectionMode, this); } - public boolean isBusy() { + @Override + public Comp comp() { + return new OpenFileSystemComp(this); + } + + @Override + public boolean canImmediatelyClose() { return !progress.getValue().done() || (fileSystem != null && fileSystem.getShell().isPresent() && fileSystem.getShell().get().getLock().isLocked()); } + @Override + public void init() throws Exception { + BooleanScope.execute(busy, () -> { + var fs = entry.getStore().createFileSystem(); + if (fs.getShell().isPresent()) { + ProcessControlProvider.get().withDefaultScripts(fs.getShell().get()); + fs.getShell().get().onKill(() -> { + browserModel.closeAsync(this); + }); + } + fs.open(); + this.fileSystem = fs; + + this.cache = new OpenFileSystemCache(this); + for (BrowserAction b : BrowserAction.ALL) { + b.init(this); + } + }); + this.savedState = OpenFileSystemSavedState.loadForStore(this); + } + + @Override + public void close() { + if (fileSystem == null) { + return; + } + + if (DataStorage.get().getStoreEntries().contains(getEntry().get()) + && savedState != null + && getCurrentPath().get() != null) { + if (getBrowserModel() instanceof BrowserSessionModel bm) { + bm.getSavedState() + .add(new BrowserSavedState.Entry( + getEntry().get().getUuid(), getCurrentPath().get())); + } + } + try { + fileSystem.close(); + } catch (IOException e) { + ErrorEvent.fromThrowable(e).handle(); + } + fileSystem = null; + } + private void startIfNeeded() throws Exception { if (fileSystem == null) { return; @@ -185,7 +238,7 @@ public final class OpenFileSystemModel { var name = adjustedPath + " - " + entry.get().getName(); ThreadHelper.runFailableAsync(() -> { if (ShellDialects.getStartableDialects().stream() - .anyMatch(dialect -> adjustedPath.startsWith(dialect.getOpenCommand(null)))) { + .anyMatch(dialect -> adjustedPath.toLowerCase().startsWith(dialect.getExecutableName().toLowerCase()))) { TerminalLauncher.open( entry.getEntry(), name, @@ -369,42 +422,10 @@ public final class OpenFileSystemModel { }); } - void closeSync() { - if (fileSystem == null) { - return; - } - - try { - fileSystem.close(); - } catch (IOException e) { - ErrorEvent.fromThrowable(e).handle(); - } - fileSystem = null; - } - public boolean isClosed() { return fileSystem == null; } - public void initFileSystem() throws Exception { - BooleanScope.execute(busy, () -> { - var fs = entry.getStore().createFileSystem(); - if (fs.getShell().isPresent()) { - ProcessControlProvider.get().withDefaultScripts(fs.getShell().get()); - fs.getShell().get().onKill(() -> { - browserModel.closeFileSystemAsync(this); - }); - } - fs.open(); - this.fileSystem = fs; - - this.cache = new OpenFileSystemCache(this); - for (BrowserAction b : BrowserAction.ALL) { - b.init(this); - } - }); - } - public void initWithGivenDirectory(String dir) throws Exception { cdSyncWithoutCheck(dir); } @@ -414,10 +435,6 @@ public final class OpenFileSystemModel { history.updateCurrent(null); } - void initSavedState() { - this.savedState = OpenFileSystemSavedState.loadForStore(this); - } - public void openTerminalAsync(String directory) { ThreadHelper.runFailableAsync(() -> { if (fileSystem == null) { @@ -445,4 +462,23 @@ public final class OpenFileSystemModel { public void forthSync(int i) throws Exception { cdSyncWithoutCheck(history.forth(i)); } + + @Getter + public enum SelectionMode { + SINGLE_FILE(false, true, false), + MULTIPLE_FILE(true, true, false), + SINGLE_DIRECTORY(false, false, true), + MULTIPLE_DIRECTORY(true, false, true), + ALL(true, true, true); + + private final boolean multiple; + private final boolean acceptsFiles; + private final boolean acceptsDirectories; + + SelectionMode(boolean multiple, boolean acceptsFiles, boolean acceptsDirectories) { + this.multiple = multiple; + this.acceptsFiles = acceptsFiles; + this.acceptsDirectories = acceptsDirectories; + } + } } diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemSavedState.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java similarity index 99% rename from app/src/main/java/io/xpipe/app/browser/OpenFileSystemSavedState.java rename to app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java index 780fae2b0..580c480f7 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemSavedState.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java @@ -1,4 +1,4 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.fs; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; diff --git a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconDirectoryType.java b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconDirectoryType.java index 565b1baa5..f947ccca9 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconDirectoryType.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconDirectoryType.java @@ -15,18 +15,18 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -public interface BrowserIconDirectoryType { +public abstract class BrowserIconDirectoryType { - List ALL = new ArrayList<>(); + private static final List ALL = new ArrayList<>(); - static BrowserIconDirectoryType byId(String id) { + public static synchronized BrowserIconDirectoryType byId(String id) { return ALL.stream() .filter(fileType -> fileType.getId().equals(id)) .findAny() .orElseThrow(); } - static void loadDefinitions() { + public static synchronized void loadDefinitions() { ALL.add(new BrowserIconDirectoryType() { @Override @@ -74,13 +74,17 @@ public interface BrowserIconDirectoryType { }); } - String getId(); + public static synchronized List getAll() { + return ALL; + } - boolean matches(FileSystem.FileEntry entry); + public abstract String getId(); - String getIcon(FileSystem.FileEntry entry, boolean open); + public abstract boolean matches(FileSystem.FileEntry entry); - class Simple implements BrowserIconDirectoryType { + public abstract String getIcon(FileSystem.FileEntry entry, boolean open); + + public static class Simple extends BrowserIconDirectoryType { @Getter private final String id; diff --git a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java index 171ead239..3d23c0337 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java @@ -12,18 +12,18 @@ import java.nio.file.Files; import java.util.*; import java.util.stream.Collectors; -public interface BrowserIconFileType { +public abstract class BrowserIconFileType { - List ALL = new ArrayList<>(); + private static final List ALL = new ArrayList<>(); - static BrowserIconFileType byId(String id) { + public static synchronized BrowserIconFileType byId(String id) { return ALL.stream() .filter(fileType -> fileType.getId().equals(id)) .findAny() .orElseThrow(); } - static void loadDefinitions() { + public static synchronized void loadDefinitions() { AppResources.with(AppResources.XPIPE_MODULE, "file_list.txt", path -> { try (var reader = new BufferedReader(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))) { @@ -53,14 +53,18 @@ public interface BrowserIconFileType { }); } - String getId(); + public static synchronized List getAll() { + return ALL; + } - boolean matches(FileSystem.FileEntry entry); + public abstract String getId(); - String getIcon(); + public abstract boolean matches(FileSystem.FileEntry entry); + + public abstract String getIcon(); @Getter - class Simple implements BrowserIconFileType { + public static class Simple extends BrowserIconFileType { private final String id; private final IconVariant icon; diff --git a/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java b/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java index 56f03ea4c..32904253c 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/FileIconManager.java @@ -11,29 +11,27 @@ public class FileIconManager { public static synchronized void loadIfNecessary() { if (!loaded) { - AppImages.loadDirectory(AppResources.XPIPE_MODULE, "browser_icons"); + AppImages.loadDirectory(AppResources.XPIPE_MODULE, "browser_icons", true, false); loaded = true; } } - public static String getFileIcon(FileSystem.FileEntry entry, boolean open) { + public static synchronized String getFileIcon(FileSystem.FileEntry entry, boolean open) { if (entry == null) { return null; } - loadIfNecessary(); - var r = entry.resolved(); if (r.getKind() != FileKind.DIRECTORY) { - for (var f : BrowserIconFileType.ALL) { + for (var f : BrowserIconFileType.getAll()) { if (f.matches(r)) { - return getIconPath(f.getIcon()); + return f.getIcon(); } } } else { - for (var f : BrowserIconDirectoryType.ALL) { + for (var f : BrowserIconDirectoryType.getAll()) { if (f.matches(r)) { - return getIconPath(f.getIcon(r, open)); + return f.getIcon(r, open); } } } @@ -42,8 +40,4 @@ public class FileIconManager { ? (open ? "default_folder_opened.svg" : "default_folder.svg") : "default_file.svg"; } - - private static String getIconPath(String name) { - return name; - } } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java new file mode 100644 index 000000000..562f1e062 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java @@ -0,0 +1,43 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.util.BooleanScope; +import io.xpipe.app.util.ThreadHelper; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import lombok.Getter; + +@Getter +public class BrowserAbstractSessionModel> { + + protected final ObservableList sessionEntries = FXCollections.observableArrayList(); + protected final Property selectedEntry = new SimpleObjectProperty<>(); + + public void closeAsync(BrowserSessionTab e) { + ThreadHelper.runAsync(() -> { + closeSync(e); + }); + } + + public void openSync(T e, BooleanProperty externalBusy) throws Exception { + try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { + e.init(); + // Prevent multiple calls from interfering with each other + synchronized (this) { + sessionEntries.add(e); + // The tab pane doesn't automatically select new tabs + selectedEntry.setValue(e); + } + } + } + + void closeSync(BrowserSessionTab e) { + e.close(); + synchronized (BrowserAbstractSessionModel.this) { + this.sessionEntries.remove(e); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java new file mode 100644 index 000000000..4654cd89a --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java @@ -0,0 +1,150 @@ +package io.xpipe.app.browser.session; + +import atlantafx.base.controls.Spacer; +import io.xpipe.app.browser.BrowserBookmarkComp; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemComp; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.comp.base.SideSplitPaneComp; +import io.xpipe.app.comp.store.StoreEntryWrapper; +import io.xpipe.app.core.AppFont; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.AppLayoutModel; +import io.xpipe.app.core.AppWindowHelper; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.PlatformThread; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.FileReference; +import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.store.FileSystemStore; +import io.xpipe.core.store.ShellStore; +import javafx.beans.property.BooleanProperty; +import javafx.collections.ListChangeListener; +import javafx.geometry.Insets; +import javafx.geometry.Orientation; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.*; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class BrowserChooserComp extends SimpleComp { + + private final BrowserChooserModel model; + + public BrowserChooserComp(BrowserChooserModel model) { + this.model = model; + } + + public static void openSingleFile( + Supplier> store, Consumer file, boolean save) { + PlatformThread.runLaterIfNeeded(() -> { + var model = new BrowserChooserModel(OpenFileSystemModel.SelectionMode.SINGLE_FILE); + var comp = new BrowserChooserComp(model) + .apply(struc -> struc.get().setPrefSize(1200, 700)) + .apply(struc -> AppFont.normal(struc.get())); + var window = AppWindowHelper.sideWindow( + AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null); + model.setOnFinish(fileStores -> { + file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null); + window.close(); + }); + window.show(); + ThreadHelper.runAsync(() -> { + model.openFileSystemAsync(store.get(), null, null); + }); + }); + } + + @Override + protected Region createSimple() { + Predicate applicable = storeEntryWrapper -> { + return (storeEntryWrapper.getEntry().getStore() instanceof ShellStore) + && storeEntryWrapper.getEntry().getValidity().isUsable(); + }; + BiConsumer action = (w, busy) -> { + ThreadHelper.runFailableAsync(() -> { + var entry = w.getEntry(); + if (!entry.getValidity().isUsable()) { + return; + } + + if (entry.getStore() instanceof ShellStore fileSystem) { + model.openFileSystemAsync(entry.ref(), null, busy); + } + }); + }; + + var bookmarksList = new BrowserBookmarkComp( + BindingsHelper.map( + model.getSelectedEntry(), v -> v.getEntry().get()), + applicable, + action) + .vgrow(); + var stack = Comp.of(() -> { + var s = new StackPane(); + model.getSelectedEntry().subscribe(selected -> { + PlatformThread.runLaterIfNeeded(() -> { + if (selected != null) { + s.getChildren().setAll(new OpenFileSystemComp(selected).createRegion()); + } else { + s.getChildren().clear(); + } + }); + }); + return s; + }); + var splitPane = new SideSplitPaneComp(bookmarksList, stack) + .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) + .withOnDividerChange(AppLayoutModel.get().getSavedState()::setBrowserConnectionsWidth) + .apply(struc -> { + struc.getLeft().setMinWidth(200); + struc.getLeft().setMaxWidth(500); + }); + var r = addBottomBar(splitPane.createRegion()); + r.getStyleClass().add("browser"); + return r; + } + + private Region addBottomBar(Region r) { + var selectedLabel = new Label("Selected: "); + selectedLabel.setAlignment(Pos.CENTER); + var selected = new HBox(); + selected.setAlignment(Pos.CENTER_LEFT); + selected.setSpacing(10); + model.getFileSelection().addListener((ListChangeListener) c -> { + PlatformThread.runLaterIfNeeded(() -> { + selected.getChildren() + .setAll(c.getList().stream() + .map(s -> { + var field = + new TextField(s.getRawFileEntry().getPath()); + field.setEditable(false); + field.setPrefWidth(500); + return field; + }) + .toList()); + }); + }); + var spacer = new Spacer(Orientation.HORIZONTAL); + var button = new Button("Select"); + button.setPadding(new Insets(5, 10, 5, 10)); + button.setOnAction(event -> model.finishChooser()); + button.setDefaultButton(true); + var bottomBar = new HBox(selectedLabel, selected, spacer, button); + HBox.setHgrow(selected, Priority.ALWAYS); + bottomBar.setAlignment(Pos.CENTER); + bottomBar.getStyleClass().add("chooser-bar"); + + var layout = new VBox(r, bottomBar); + VBox.setVgrow(r, Priority.ALWAYS); + return layout; + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java new file mode 100644 index 000000000..c93b65009 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java @@ -0,0 +1,106 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.browser.icon.BrowserIconDirectoryType; +import io.xpipe.app.browser.icon.BrowserIconFileType; +import io.xpipe.app.browser.icon.FileIconManager; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.BooleanScope; +import io.xpipe.app.util.FileReference; +import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.store.FileNames; +import io.xpipe.core.store.FileSystemStore; +import io.xpipe.core.util.FailableFunction; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +@Getter +public class BrowserChooserModel extends BrowserAbstractSessionModel { + + private final OpenFileSystemModel.SelectionMode selectionMode; + private final ObservableList fileSelection = FXCollections.observableArrayList(); + + @Setter + private Consumer> onFinish; + + public BrowserChooserModel(OpenFileSystemModel.SelectionMode selectionMode) { + this.selectionMode = selectionMode; + selectedEntry.addListener((observable, oldValue, newValue) -> { + if (newValue == null) { + fileSelection.clear(); + return; + } + + ListBindingsHelper.bindContent(fileSelection, newValue.getFileList().getSelection()); + }); + } + + public void finishChooser() { + var chosen = new ArrayList<>(fileSelection); + + synchronized (BrowserChooserModel.this) { + var open = selectedEntry.getValue(); + if (open != null) { + ThreadHelper.runAsync(() -> { + open.close(); + }); + } + } + + if (chosen.size() == 0) { + return; + } + + var stores = chosen.stream() + .map(entry -> new FileReference( + selectedEntry.getValue().getEntry(), + entry.getRawFileEntry().getPath())) + .toList(); + onFinish.accept(stores); + } + + public void openFileSystemAsync( + DataStoreEntryRef store, + FailableFunction path, + BooleanProperty externalBusy) { + if (store == null) { + return; + } + + // Only load icons when a file system is opened + ThreadHelper.runAsync(() -> { + BrowserIconFileType.loadDefinitions(); + BrowserIconDirectoryType.loadDefinitions(); + FileIconManager.loadIfNecessary(); + }); + + ThreadHelper.runFailableAsync(() -> { + OpenFileSystemModel model; + + try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { + model = new OpenFileSystemModel(this, store, selectionMode); + model.init(); + // Prevent multiple calls from interfering with each other + synchronized (BrowserChooserModel.this) { + selectedEntry.setValue(model); + sessionEntries.add(model); + } + if (path != null) { + model.initWithGivenDirectory(FileNames.toDirectory(path.apply(model))); + } else { + model.initWithDefaultDirectory(); + } + } + }); + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java new file mode 100644 index 000000000..066ccba37 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java @@ -0,0 +1,95 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.browser.BrowserBookmarkComp; +import io.xpipe.app.browser.BrowserTransferComp; +import io.xpipe.app.comp.base.SideSplitPaneComp; +import io.xpipe.app.comp.store.StoreEntryWrapper; +import io.xpipe.app.core.AppLayoutModel; +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.impl.VerticalComp; +import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.PlatformThread; +import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.store.ShellStore; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.scene.layout.Region; + +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +public class BrowserSessionComp extends SimpleComp { + + private final BrowserSessionModel model; + + public BrowserSessionComp(BrowserSessionModel model) { + this.model = model; + } + + @Override + protected Region createSimple() { + Predicate applicable = storeEntryWrapper -> { + if (!storeEntryWrapper.getEntry().getValidity().isUsable()) { + return false; + } + + if (storeEntryWrapper.getEntry().getStore() instanceof ShellStore) { + return true; + } + + return storeEntryWrapper.getEntry().getProvider().browserAction(model,storeEntryWrapper.getEntry(), null) != null; + }; + BiConsumer action = (w, busy) -> { + ThreadHelper.runFailableAsync(() -> { + var entry = w.getEntry(); + if (!entry.getValidity().isUsable()) { + return; + } + + if (entry.getStore() instanceof ShellStore fileSystem) { + model.openFileSystemAsync(entry.ref(), null, busy); + } + + var a = entry.getProvider().browserAction(model, entry, busy); + if (a != null) { + a.execute(); + } + }); + }; + + var bookmarksList = new BrowserBookmarkComp( + BindingsHelper.map( + model.getSelectedEntry(), v -> v.getEntry().get()), + applicable, + action) + .vgrow(); + var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage()) + .hide(PlatformThread.sync(Bindings.createBooleanBinding( + () -> { + if (model.getSessionEntries().size() == 0) { + return true; + } + + return false; + }, + model.getSessionEntries(), + model.getSelectedEntry()))); + localDownloadStage.prefHeight(200); + localDownloadStage.maxHeight(200); + var vertical = new VerticalComp(List.of(bookmarksList, localDownloadStage)); + + var tabs = new BrowserSessionTabsComp(model); + var splitPane = new SideSplitPaneComp(vertical, tabs) + .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) + .withOnDividerChange(AppLayoutModel.get().getSavedState()::setBrowserConnectionsWidth) + .apply(struc -> { + struc.getLeft().setMinWidth(200); + struc.getLeft().setMaxWidth(500); + }); + var r = splitPane.createRegion(); + r.getStyleClass().add("browser"); + + return r; + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java new file mode 100644 index 000000000..931cb10d9 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java @@ -0,0 +1,107 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.browser.BrowserSavedState; +import io.xpipe.app.browser.BrowserSavedStateImpl; +import io.xpipe.app.browser.BrowserTransferModel; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.browser.icon.BrowserIconDirectoryType; +import io.xpipe.app.browser.icon.BrowserIconFileType; +import io.xpipe.app.browser.icon.FileIconManager; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.BooleanScope; +import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.store.FileNames; +import io.xpipe.core.store.FileSystemStore; +import io.xpipe.core.util.FailableFunction; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import lombok.Getter; + +import java.util.ArrayList; + +@Getter +public class BrowserSessionModel extends BrowserAbstractSessionModel> { + + public static final BrowserSessionModel DEFAULT = new BrowserSessionModel(BrowserSavedStateImpl.load()); + + private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this); + private final BrowserSavedState savedState; + + public BrowserSessionModel(BrowserSavedState savedState) { + this.savedState = savedState; + } + + public void restoreState(BrowserSavedState state) { + ThreadHelper.runAsync(() -> { + state.getEntries().forEach(e -> { + restoreStateAsync(e, null); + // Don't try to run everything in parallel as that can be taxing + ThreadHelper.sleep(1000); + }); + }); + } + + public void restoreStateAsync(BrowserSavedState.Entry e, BooleanProperty busy) { + var storageEntry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); + storageEntry.ifPresent(entry -> { + openFileSystemAsync(entry.ref(), model -> e.getPath(), busy); + }); + } + + public void reset() { + synchronized (BrowserSessionModel.this) { + for (var o : new ArrayList<>(sessionEntries)) { + // Don't close busy connections gracefully + // as we otherwise might lock up + if (o.canImmediatelyClose()) { + continue; + } + + closeSync(o); + } + if (savedState != null) { + savedState.save(); + } + } + + // Delete all files + localTransfersStage.clear(); + } + + public void openFileSystemAsync( + DataStoreEntryRef store, + FailableFunction path, + BooleanProperty externalBusy) { + if (store == null) { + return; + } + + // Only load icons when a file system is opened + ThreadHelper.runAsync(() -> { + BrowserIconFileType.loadDefinitions(); + BrowserIconDirectoryType.loadDefinitions(); + FileIconManager.loadIfNecessary(); + }); + + ThreadHelper.runFailableAsync(() -> { + OpenFileSystemModel model; + + try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { + model = new OpenFileSystemModel(this, store, OpenFileSystemModel.SelectionMode.ALL); + model.init(); + // Prevent multiple calls from interfering with each other + synchronized (BrowserSessionModel.this) { + sessionEntries.add(model); + // The tab pane doesn't automatically select new tabs + selectedEntry.setValue(model); + } + } + if (path != null) { + model.initWithGivenDirectory(FileNames.toDirectory(path.apply(model))); + } else { + model.initWithDefaultDirectory(); + } + }); + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionMultiTab.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionMultiTab.java new file mode 100644 index 000000000..d8359fafc --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionMultiTab.java @@ -0,0 +1,44 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.comp.base.MultiContentComp; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.core.store.DataStore; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import lombok.Getter; + +@Getter +public class BrowserSessionMultiTab extends BrowserSessionTab { + + protected final Property> currentTab = new SimpleObjectProperty<>(); + private final ObservableList> allTabs = FXCollections.observableArrayList(); + + public BrowserSessionMultiTab(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { + super(browserModel, entry); + } + + public Comp comp() { + var map = FXCollections., ObservableValue>observableHashMap(); + allTabs.addListener((ListChangeListener>) c -> { + for (BrowserSessionTab a : c.getAddedSubList()) { + map.put(a.comp(), BindingsHelper.map(currentTab, browserSessionTab -> a.equals(browserSessionTab))); + } + }); + var mt = new MultiContentComp(map); + return mt; + } + + public boolean canImmediatelyClose() { + return true; + } + + public void init() throws Exception {} + + public void close() {} +} diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTab.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTab.java new file mode 100644 index 000000000..7afc6346f --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTab.java @@ -0,0 +1,34 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.core.store.DataStore; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import lombok.Getter; + +@Getter +public abstract class BrowserSessionTab { + + protected final DataStoreEntryRef entry; + protected final BooleanProperty busy = new SimpleBooleanProperty(); + protected final BrowserAbstractSessionModel browserModel; + protected final String name; + protected final String tooltip; + + public BrowserSessionTab(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { + this.browserModel = browserModel; + this.entry = entry; + this.name = DataStorage.get().getStoreDisplayName(entry.get()); + this.tooltip = DataStorage.get().getId(entry.getEntry()).toString(); + } + + public abstract Comp comp(); + + public abstract boolean canImmediatelyClose(); + + public abstract void init() throws Exception; + + public abstract void close(); +} diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java similarity index 57% rename from app/src/main/java/io/xpipe/app/browser/BrowserComp.java rename to app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java index f9a35de3b..ecce9a155 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java @@ -1,40 +1,31 @@ -package io.xpipe.app.browser; +package io.xpipe.app.browser.session; import atlantafx.base.controls.RingProgressIndicator; -import atlantafx.base.controls.Spacer; import atlantafx.base.theme.Styles; -import io.xpipe.app.browser.icon.BrowserIconDirectoryType; -import io.xpipe.app.browser.icon.BrowserIconFileType; -import io.xpipe.app.browser.icon.FileIconManager; +import io.xpipe.app.browser.BrowserWelcomeComp; import io.xpipe.app.comp.base.MultiContentComp; -import io.xpipe.app.comp.base.SideSplitPaneComp; -import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; -import io.xpipe.app.fxcomps.impl.VerticalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.BooleanScope; -import io.xpipe.app.util.ThreadHelper; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; -import javafx.geometry.Insets; -import javafx.geometry.Orientation; import javafx.geometry.Pos; -import javafx.scene.control.*; +import javafx.scene.control.Label; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; import javafx.scene.input.DragEvent; -import javafx.scene.layout.*; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.UUID; @@ -42,106 +33,25 @@ import static atlantafx.base.theme.Styles.DENSE; import static atlantafx.base.theme.Styles.toggleStyleClass; import static javafx.scene.control.TabPane.TabClosingPolicy.ALL_TABS; -public class BrowserComp extends SimpleComp { +public class BrowserSessionTabsComp extends SimpleComp { - private final BrowserModel model; + private final BrowserSessionModel model; - public BrowserComp(BrowserModel model) { + public BrowserSessionTabsComp(BrowserSessionModel model) { this.model = model; } - @Override - protected Region createSimple() { - BrowserIconFileType.loadDefinitions(); - BrowserIconDirectoryType.loadDefinitions(); - ThreadHelper.runAsync(() -> { - FileIconManager.loadIfNecessary(); - }); - - var bookmarksList = new BrowserBookmarkComp(model).vgrow(); - var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage()) - .hide(PlatformThread.sync(Bindings.createBooleanBinding( - () -> { - if (model.getOpenFileSystems().size() == 0) { - return true; - } - - if (model.getMode().isChooser()) { - return true; - } - - return false; - }, - model.getOpenFileSystems(), - model.getSelected()))); - localDownloadStage.prefHeight(200); - localDownloadStage.maxHeight(200); - var vertical = new VerticalComp(List.of(bookmarksList, localDownloadStage)); - - var splitPane = new SideSplitPaneComp(vertical, createTabs()) - .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) - .withOnDividerChange(AppLayoutModel.get().getSavedState()::setBrowserConnectionsWidth) - .apply(struc -> { - struc.getLeft().setMinWidth(200); - struc.getLeft().setMaxWidth(500); - }); - var r = addBottomBar(splitPane.createRegion()); - r.getStyleClass().add("browser"); - // AppFont.small(r); - return r; - } - - private Region addBottomBar(Region r) { - if (!model.getMode().isChooser()) { - return r; - } - - var selectedLabel = new Label("Selected: "); - selectedLabel.setAlignment(Pos.CENTER); - var selected = new HBox(); - selected.setAlignment(Pos.CENTER_LEFT); - selected.setSpacing(10); - model.getSelection().addListener((ListChangeListener) c -> { - PlatformThread.runLaterIfNeeded(() -> { - selected.getChildren() - .setAll(c.getList().stream() - .map(s -> { - var field = - new TextField(s.getRawFileEntry().getPath()); - field.setEditable(false); - field.setPrefWidth(500); - return field; - }) - .toList()); - }); - }); - var spacer = new Spacer(Orientation.HORIZONTAL); - var button = new Button("Select"); - button.setPadding(new Insets(5, 10, 5, 10)); - button.setOnAction(event -> model.finishChooser()); - button.setDefaultButton(true); - var bottomBar = new HBox(selectedLabel, selected, spacer, button); - HBox.setHgrow(selected, Priority.ALWAYS); - bottomBar.setAlignment(Pos.CENTER); - bottomBar.getStyleClass().add("chooser-bar"); - - var layout = new VBox(r, bottomBar); - VBox.setVgrow(r, Priority.ALWAYS); - return layout; - } - - private Comp createTabs() { + public Region createSimple() { var multi = new MultiContentComp(Map., ObservableValue>of( Comp.of(() -> createTabPane()), - BindingsHelper.persist(Bindings.isNotEmpty(model.getOpenFileSystems())), + Bindings.isNotEmpty(model.getSessionEntries()), new BrowserWelcomeComp(model).apply(struc -> StackPane.setAlignment(struc.get(), Pos.CENTER_LEFT)), Bindings.createBooleanBinding( () -> { - return model.getOpenFileSystems().size() == 0 - && !model.getMode().isChooser(); + return model.getSessionEntries().size() == 0; }, - model.getOpenFileSystems()))); - return multi; + model.getSessionEntries()))); + return multi.createRegion(); } private TabPane createTabPane() { @@ -153,16 +63,17 @@ public class BrowserComp extends SimpleComp { Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING); toggleStyleClass(tabs, DENSE); - var map = new HashMap(); + var map = new HashMap, Tab>(); // Restore state - model.getOpenFileSystems().forEach(v -> { + model.getSessionEntries().forEach(v -> { var t = createTab(tabs, v); map.put(v, t); tabs.getTabs().add(t); }); tabs.getSelectionModel() - .select(model.getOpenFileSystems().indexOf(model.getSelected().getValue())); + .select(model.getSessionEntries() + .indexOf(model.getSelectedEntry().getValue())); // Used for ignoring changes by the tabpane when new tabs are added. We want to perform the selections manually! var modifying = new SimpleBooleanProperty(); @@ -174,7 +85,7 @@ public class BrowserComp extends SimpleComp { } if (newValue == null) { - model.getSelected().setValue(null); + model.getSelectedEntry().setValue(null); return; } @@ -184,11 +95,11 @@ public class BrowserComp extends SimpleComp { .findAny() .map(Map.Entry::getKey) .orElse(null); - model.getSelected().setValue(source); + model.getSelectedEntry().setValue(source); }); // Handle selection from model - model.getSelected().addListener((observable, oldValue, newValue) -> { + model.getSelectedEntry().addListener((observable, oldValue, newValue) -> { PlatformThread.runLaterIfNeeded(() -> { if (newValue == null) { tabs.getSelectionModel().select(null); @@ -210,7 +121,7 @@ public class BrowserComp extends SimpleComp { }); }); - model.getOpenFileSystems().addListener((ListChangeListener) c -> { + model.getSessionEntries().addListener((ListChangeListener) c -> { while (c.next()) { for (var r : c.getRemoved()) { PlatformThread.runLaterIfNeeded(() -> { @@ -247,14 +158,14 @@ public class BrowserComp extends SimpleComp { continue; } - model.closeFileSystemAsync(source.getKey()); + model.closeAsync(source.getKey()); } } }); return tabs; } - private Tab createTab(TabPane tabs, OpenFileSystemModel model) { + private Tab createTab(TabPane tabs, BrowserSessionTab model) { var tab = new Tab(); var ring = new RingProgressIndicator(0, false); @@ -279,12 +190,12 @@ public class BrowserComp extends SimpleComp { PlatformThread.sync(model.getBusy()))); tab.setText(model.getName()); - tab.setContent(new OpenFileSystemComp(model).createSimple()); + tab.setContent(model.comp().createRegion()); var id = UUID.randomUUID().toString(); tab.setId(id); - SimpleChangeListener.apply(tabs.skinProperty(), newValue -> { + tabs.skinProperty().subscribe(newValue -> { if (newValue != null) { Platform.runLater(() -> { Label l = (Label) tabs.lookup("#" + id + " .tab-label"); @@ -303,7 +214,7 @@ public class BrowserComp extends SimpleComp { if (color != null) { c.getStyleClass().add(color.getId()); } - new FancyTooltipAugment<>(new SimpleStringProperty(model.getTooltip())).augment(c); + new TooltipAugment<>(new SimpleStringProperty(model.getTooltip())).augment(c); c.addEventHandler( DragEvent.DRAG_ENTERED, mouseEvent -> Platform.runLater( diff --git a/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java b/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java index 53503c7d4..ca1991628 100644 --- a/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java @@ -7,13 +7,15 @@ import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableValue; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; +import java.util.Map; import java.util.stream.Collectors; public class AppLayoutComp extends Comp> { @@ -22,18 +24,20 @@ public class AppLayoutComp extends Comp> { @Override public CompStructure createBase() { - var multi = new MultiContentComp(model.getEntries().stream() + Map, ObservableValue> map = model.getEntries().stream() .collect(Collectors.toMap( entry -> entry.comp(), - entry -> PlatformThread.sync(Bindings.createBooleanBinding( + entry -> Bindings.createBooleanBinding( () -> { return model.getSelected().getValue().equals(entry); }, - model.getSelected()))))); + model.getSelected()))); + var multi = new MultiContentComp(map); var pane = new BorderPane(); - var sidebar = new SideMenuBarComp(model.getSelectedInternal(), model.getEntries()); - pane.setCenter(multi.createRegion()); + var sidebar = new SideMenuBarComp(model.getSelected(), model.getEntries()); + StackPane multiR = (StackPane) multi.createRegion(); + pane.setCenter(multiR); pane.setRight(sidebar.createRegion()); pane.getStyleClass().add("background"); model.getSelected().addListener((c, o, n) -> { diff --git a/app/src/main/java/io/xpipe/app/comp/base/ButtonComp.java b/app/src/main/java/io/xpipe/app/comp/base/ButtonComp.java index cd6136a8e..dbaa87a16 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ButtonComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ButtonComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.comp.base; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; @@ -50,7 +49,7 @@ public class ButtonComp extends Comp> { var graphic = getGraphic(); if (graphic instanceof FontIcon f) { // f.iconColorProperty().bind(button.textFillProperty()); - SimpleChangeListener.apply(button.fontProperty(), c -> { + button.fontProperty().subscribe(c -> { f.setIconSize((int) new Size(c.getSize(), SizeUnits.PT).pixels()); }); } diff --git a/app/src/main/java/io/xpipe/app/comp/base/DropdownComp.java b/app/src/main/java/io/xpipe/app/comp/base/DropdownComp.java index 183088c1b..1834bf104 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/DropdownComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/DropdownComp.java @@ -4,8 +4,7 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import javafx.css.Size; import javafx.css.SizeUnits; import javafx.scene.control.Button; @@ -38,12 +37,12 @@ public class DropdownComp extends Comp> { .createRegion(); button.visibleProperty() - .bind(BindingsHelper.anyMatch(cm.getItems().stream() + .bind(ListBindingsHelper.anyMatch(cm.getItems().stream() .map(menuItem -> menuItem.getGraphic().visibleProperty()) .toList())); var graphic = new FontIcon("mdi2c-chevron-double-down"); - SimpleChangeListener.apply(button.fontProperty(), c -> { + button.fontProperty().subscribe(c -> { graphic.setIconSize((int) new Size(c.getSize(), SizeUnits.PT).pixels()); }); diff --git a/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java b/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java new file mode 100644 index 000000000..462e05ca7 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java @@ -0,0 +1,47 @@ +package io.xpipe.app.comp.base; + +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.CompStructure; +import io.xpipe.app.fxcomps.util.PlatformThread; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; +import javafx.scene.layout.StackPane; +import lombok.AllArgsConstructor; +import lombok.Value; +import org.kordamp.ikonli.javafx.FontIcon; + +@AllArgsConstructor +public class FontIconComp extends Comp { + + private final ObservableValue icon; + + public FontIconComp(String icon) { + this.icon = new SimpleStringProperty(icon); + } + + @Override + public FontIconComp.Structure createBase() { + var fi = new FontIcon(); + var obs = PlatformThread.sync(icon); + icon.subscribe(val -> { + PlatformThread.runLaterIfNeeded(() -> { + fi.setIconLiteral(val); + }); + }); + + var pane = new StackPane(fi); + return new FontIconComp.Structure(fi, pane); + } + + @Value + public static class Structure implements CompStructure { + + FontIcon icon; + StackPane pane; + + @Override + public StackPane get() { + return pane; + } + } +} diff --git a/app/src/main/java/io/xpipe/app/comp/base/LazyTextFieldComp.java b/app/src/main/java/io/xpipe/app/comp/base/LazyTextFieldComp.java index 6cd7c4178..9ca87049d 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/LazyTextFieldComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/LazyTextFieldComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.comp.base; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; import javafx.scene.control.TextField; @@ -65,7 +64,7 @@ public class LazyTextFieldComp extends Comp { sp.prefHeightProperty().bind(r.prefHeightProperty()); r.setDisable(true); - SimpleChangeListener.apply(currentValue, n -> { + currentValue.subscribe(n -> { PlatformThread.runLaterIfNeeded(() -> { // Check if control value is the same. Then don't set it as that might cause bugs if (Objects.equals(r.getText(), n) || (n == null && r.getText().isEmpty())) { diff --git a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java index 5cefd9877..f5210c6a3 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java @@ -3,7 +3,7 @@ package io.xpipe.app.comp.base; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.application.Platform; import javafx.collections.ListChangeListener; @@ -88,7 +88,7 @@ public class ListBoxViewComp extends Comp> { } if (!listView.getChildren().equals(newShown)) { - BindingsHelper.setContent(listView.getChildren(), newShown); + ListBindingsHelper.setContent(listView.getChildren(), newShown); } }; diff --git a/app/src/main/java/io/xpipe/app/comp/base/MarkdownComp.java b/app/src/main/java/io/xpipe/app/comp/base/MarkdownComp.java index da75f6565..41dbf7835 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/MarkdownComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/MarkdownComp.java @@ -6,7 +6,6 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.Hyperlinks; @@ -59,7 +58,7 @@ public class MarkdownComp extends Comp> { var url = AppResources.getResourceURL(AppResources.XPIPE_MODULE, theme).orElseThrow(); wv.getEngine().setUserStyleSheetLocation(url.toString()); - SimpleChangeListener.apply(PlatformThread.sync(markdown), val -> { + PlatformThread.sync(markdown).subscribe(val -> { // Workaround for https://bugs.openjdk.org/browse/JDK-8199014 try { var file = Files.createTempFile(null, ".html"); diff --git a/app/src/main/java/io/xpipe/app/comp/base/MultiContentComp.java b/app/src/main/java/io/xpipe/app/comp/base/MultiContentComp.java index 852b08438..acdd98d87 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/MultiContentComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/MultiContentComp.java @@ -3,8 +3,10 @@ package io.xpipe.app.comp.base; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableMap; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; @@ -12,24 +14,54 @@ import java.util.Map; public class MultiContentComp extends SimpleComp { - private final Map, ObservableValue> content; + private final ObservableMap, ObservableValue> content; public MultiContentComp(Map, ObservableValue> content) { + this.content = FXCollections.observableMap(content); + } + + public MultiContentComp(ObservableMap, ObservableValue> content) { this.content = content; } @Override protected Region createSimple() { + ObservableMap, Region> m = FXCollections.observableHashMap(); + content.addListener((MapChangeListener, ? super ObservableValue>) change -> { + if (change.wasAdded()) { + var r = change.getKey().createRegion(); + change.getValueAdded().subscribe(val -> { + PlatformThread.runLaterIfNeeded(() -> { + r.setManaged(val); + r.setVisible(val); + }); + }); + m.put(change.getKey(), r); + } else { + m.remove(change.getKey()); + } + }); + var stack = new StackPane(); - stack.setPickOnBounds(false); - for (Map.Entry, ObservableValue> entry : content.entrySet()) { - var region = entry.getKey().createRegion(); - stack.getChildren().add(region); - SimpleChangeListener.apply(PlatformThread.sync(entry.getValue()), val -> { - region.setManaged(val); - region.setVisible(val); + m.addListener((MapChangeListener, Region>) change -> { + if (change.wasAdded()) { + stack.getChildren().add(change.getValueAdded()); + } else { + stack.getChildren().remove(change.getValueRemoved()); + } + }); + + for (Map.Entry, ObservableValue> e : content.entrySet()) { + var r = e.getKey().createRegion(); + e.getValue().subscribe(val -> { + PlatformThread.runLaterIfNeeded(() -> { + r.setManaged(val); + r.setVisible(val); + }); }); + m.put(e.getKey(), r); } + return stack; } } diff --git a/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java b/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java index a6d27f68b..b54fd38cb 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java @@ -37,7 +37,7 @@ public class OsLogoComp extends SimpleComp { @Override protected Region createSimple() { - var img = BindingsHelper.persist(Bindings.createObjectBinding( + var img = Bindings.createObjectBinding( () -> { if (state.getValue() != SystemStateComp.State.SUCCESS) { return null; @@ -51,7 +51,7 @@ public class OsLogoComp extends SimpleComp { return getImage(ons.getOsName()); }, wrapper.getPersistentState(), - state)); + state); var hide = BindingsHelper.map(img, s -> s != null); return new StackComp( List.of(new SystemStateComp(state).hide(hide), new PrettyImageComp(img, 24, 24).visible(hide))) diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java index 3dcea999e..91c7b7d11 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java @@ -7,8 +7,8 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.Augment; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; import io.xpipe.app.fxcomps.impl.IconButtonComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.UserReportComp; @@ -73,7 +73,7 @@ public class SideMenuBarComp extends Comp> { var e = entries.get(i); var b = new IconButtonComp(e.icon(), () -> value.setValue(e)); b.shortcut(new KeyCodeCombination(KeyCode.values()[KeyCode.DIGIT1.ordinal() + i])); - b.apply(new FancyTooltipAugment<>(e.name())); + b.apply(new TooltipAugment<>(e.name())); b.apply(struc -> { AppFont.setSize(struc.get(), 2); struc.get().pseudoClassStateChanged(selected, value.getValue().equals(e)); @@ -133,7 +133,7 @@ public class SideMenuBarComp extends Comp> { UserReportComp.show(event.build()); }) .shortcut(new KeyCodeCombination(KeyCode.values()[KeyCode.DIGIT1.ordinal() + entries.size()])) - .apply(new FancyTooltipAugment<>("reportIssue")) + .apply(new TooltipAugment<>("reportIssue")) .apply(simpleBorders) .accessibleTextKey("reportIssue"); b.apply(struc -> { @@ -145,7 +145,7 @@ public class SideMenuBarComp extends Comp> { { var b = new IconButtonComp("mdi2g-github", () -> Hyperlinks.open(Hyperlinks.GITHUB)) .shortcut(new KeyCodeCombination(KeyCode.values()[KeyCode.DIGIT1.ordinal() + entries.size() + 1])) - .apply(new FancyTooltipAugment<>("visitGithubRepository")) + .apply(new TooltipAugment<>("visitGithubRepository")) .apply(simpleBorders) .accessibleTextKey("visitGithubRepository"); b.apply(struc -> { @@ -157,7 +157,7 @@ public class SideMenuBarComp extends Comp> { { var b = new IconButtonComp("mdi2d-discord", () -> Hyperlinks.open(Hyperlinks.DISCORD)) .shortcut(new KeyCodeCombination(KeyCode.values()[KeyCode.DIGIT1.ordinal() + entries.size() + 2])) - .apply(new FancyTooltipAugment<>("discord")) + .apply(new TooltipAugment<>("discord")) .apply(simpleBorders) .accessibleTextKey("discord"); b.apply(struc -> { @@ -167,9 +167,20 @@ public class SideMenuBarComp extends Comp> { } { - var b = new IconButtonComp("mdi2u-update", () -> UpdateAvailableAlert.showIfNeeded()) + var b = new IconButtonComp("mdi2t-translate", () -> Hyperlinks.open(Hyperlinks.TRANSLATE)) .shortcut(new KeyCodeCombination(KeyCode.values()[KeyCode.DIGIT1.ordinal() + entries.size() + 3])) - .apply(new FancyTooltipAugment<>("updateAvailableTooltip")) + .apply(new TooltipAugment<>("translate")) + .apply(simpleBorders) + .accessibleTextKey("translate"); + b.apply(struc -> { + AppFont.setSize(struc.get(), 2); + }); + vbox.getChildren().add(b.createRegion()); + } + + { + var b = new IconButtonComp("mdi2u-update", () -> UpdateAvailableAlert.showIfNeeded()) + .apply(new TooltipAugment<>("updateAvailableTooltip")) .accessibleTextKey("updateAvailableTooltip"); b.apply(struc -> { AppFont.setSize(struc.get(), 2); diff --git a/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java b/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java index 1d2e52ead..9aa03175b 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.comp.base; import io.xpipe.app.comp.store.StoreSection; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; import javafx.beans.binding.Bindings; @@ -32,13 +31,13 @@ public class StoreToggleComp extends SimpleComp { @Override protected Region createSimple() { var disable = section.getWrapper().getValidity().map(state -> state != DataStoreEntry.Validity.COMPLETE); - var visible = BindingsHelper.persist(Bindings.createBooleanBinding( + var visible = Bindings.createBooleanBinding( () -> { return section.getWrapper().getValidity().getValue() == DataStoreEntry.Validity.COMPLETE && section.getShowDetails().get(); }, section.getWrapper().getValidity(), - section.getShowDetails())); + section.getShowDetails()); var t = new ToggleSwitchComp(value, AppI18n.observable(nameKey)) .visible(visible) .disable(disable); diff --git a/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java b/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java index 34669005e..16b9f17ed 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java @@ -5,7 +5,6 @@ import io.xpipe.app.comp.store.StoreEntryWrapper; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.core.process.ShellStoreState; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; @@ -35,7 +34,7 @@ public class SystemStateComp extends SimpleComp { state)); var fi = new FontIcon(); fi.getStyleClass().add("inner-icon"); - SimpleChangeListener.apply(icon, val -> fi.setIconLiteral(val)); + icon.subscribe(val -> fi.setIconLiteral(val)); var border = new FontIcon("mdi2c-circle-outline"); border.getStyleClass().add("outer-icon"); @@ -63,9 +62,11 @@ public class SystemStateComp extends SimpleComp { """; pane.getStylesheets().add(Styles.toDataURI(dataClass1)); - SimpleChangeListener.apply(PlatformThread.sync(state), val -> { - pane.getStylesheets().removeAll(success, failure, other); - pane.getStylesheets().add(val == State.SUCCESS ? success : val == State.FAILURE ? failure : other); + state.subscribe(val -> { + PlatformThread.runLaterIfNeeded(() -> { + pane.getStylesheets().removeAll(success, failure, other); + pane.getStylesheets().add(val == State.SUCCESS ? success : val == State.FAILURE ? failure : other); + }); }); return pane; diff --git a/app/src/main/java/io/xpipe/app/comp/base/TileButtonComp.java b/app/src/main/java/io/xpipe/app/comp/base/TileButtonComp.java index 836e2d45c..8b7867566 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/TileButtonComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/TileButtonComp.java @@ -5,7 +5,6 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -13,7 +12,6 @@ import javafx.event.ActionEvent; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import lombok.AllArgsConstructor; import lombok.Builder; @@ -56,12 +54,8 @@ public class TileButtonComp extends Comp { var text = new VBox(header, desc); text.setSpacing(2); - var fi = new FontIcon(); - SimpleChangeListener.apply(PlatformThread.sync(icon), val -> { - fi.setIconLiteral(val); - }); - - var pane = new StackPane(fi); + var fi = new FontIconComp(icon).createStructure(); + var pane = fi.getPane(); var hbox = new HBox(pane, text); hbox.setSpacing(8); pane.prefWidthProperty() @@ -76,11 +70,11 @@ public class TileButtonComp extends Comp { desc.heightProperty())); pane.prefHeightProperty().addListener((c, o, n) -> { var size = Math.min(n.intValue(), 100); - fi.setIconSize((int) (size * 0.55)); + fi.getIcon().setIconSize((int) (size * 0.55)); }); bt.setGraphic(hbox); return Structure.builder() - .graphic(fi) + .graphic(fi.getIcon()) .button(bt) .content(hbox) .name(header) diff --git a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java index 69bfb3794..110897b1f 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java @@ -22,7 +22,7 @@ public class ToggleSwitchComp extends SimpleComp { @Override protected Region createSimple() { var s = new ToggleSwitch(); - s.addEventFilter(KeyEvent.KEY_PRESSED,event -> { + s.addEventFilter(KeyEvent.KEY_PRESSED, event -> { if (event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) { s.setSelected(!s.isSelected()); event.consume(); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java index d09c643bc..9d48725a0 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java @@ -1,5 +1,6 @@ package io.xpipe.app.comp.store; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; @@ -80,6 +81,10 @@ public class StoreCategoryWrapper { private void setupListeners() { name.addListener((c, o, n) -> { + if (n.equals(translatedName(category.getName()))) { + return; + } + category.setName(n); }); @@ -91,6 +96,10 @@ public class StoreCategoryWrapper { update(); }); + AppPrefs.get().language().addListener((observable, oldValue, newValue) -> { + update(); + }); + sortMode.addListener((observable, oldValue, newValue) -> { category.setSortMode(newValue); }); @@ -112,8 +121,9 @@ public class StoreCategoryWrapper { public void update() { // Avoid reupdating name when changed from the name property! - if (!category.getName().equals(name.getValue())) { - name.setValue(category.getName()); + var catName = translatedName(category.getName()); + if (!catName.equals(name.getValue())) { + name.setValue(catName); } lastAccess.setValue(category.getLastAccess().minus(Duration.ofMillis(500))); @@ -140,18 +150,30 @@ public class StoreCategoryWrapper { }); } - public String getName() { - return name.getValue(); + private String translatedName(String original) { + if (original.equals("All connections")) { + return AppI18n.get("allConnections"); + } + if (original.equals("All scripts")) { + return AppI18n.get("allScripts"); + } + if (original.equals("Predefined")) { + return AppI18n.get("predefined"); + } + if (original.equals("Custom")) { + return AppI18n.get("custom"); + } + if (original.equals("Default")) { + return AppI18n.get("default"); + } + + return original; } public Property nameProperty() { return name; } - public Instant getLastAccess() { - return lastAccess.getValue(); - } - public Property lastAccessProperty() { return lastAccess; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java index 76dc1dfb5..9a32e93f4 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java @@ -12,7 +12,6 @@ import io.xpipe.app.ext.DataStoreProviders; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.augment.GrowAugment; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ExceptionConverter; import io.xpipe.app.issue.TrackEvent; @@ -381,7 +380,7 @@ public class StoreCreationComp extends DialogComp { providerChoice.apply(GrowAugment.create(true, false)); providerChoice.onSceneAssign(struc -> struc.get().requestFocus()); - SimpleChangeListener.apply(provider, n -> { + provider.subscribe(n -> { if (n != null) { var d = n.guiDialog(existingEntry, store); var propVal = new SimpleValidator(); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java index da11e6bce..e9d0a86d1 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java @@ -26,6 +26,9 @@ public class StoreCreationMenu { menu.getItems().add(category("addHost", "mdi2h-home-plus", DataStoreProvider.CreationCategory.HOST, "ssh")); + menu.getItems() + .add(category("addVisual", "mdi2c-camera-plus", DataStoreProvider.CreationCategory.VISUAL, null)); + menu.getItems() .add(category("addShell", "mdi2t-text-box-multiple", DataStoreProvider.CreationCategory.SHELL, null)); @@ -81,7 +84,8 @@ public class StoreCreationMenu { event.consume(); }); sub.forEach(dataStoreProvider -> { - var item = new MenuItem(dataStoreProvider.getDisplayName()); + var item = new MenuItem(); + item.textProperty().bind(dataStoreProvider.displayName()); item.setGraphic(PrettyImageHelper.ofFixedSizeSquare(dataStoreProvider.getDisplayIconFileName(null), 16) .createRegion()); item.setOnAction(event -> { diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index 9f66920d2..e08790469 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -13,9 +13,7 @@ import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.augment.GrowAugment; import io.xpipe.app.fxcomps.impl.*; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreColor; @@ -97,12 +95,15 @@ public abstract class StoreEntryComp extends SimpleComp { wrapper.executeDefaultAction(); }); }); - new ContextMenuAugment<>(mouseEvent -> mouseEvent.isSecondaryButtonDown(), null, () -> this.createContextMenu()).augment(new SimpleCompStructure<>(button)); + new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + null, + () -> this.createContextMenu()) + .augment(button); var loading = LoadingOverlayComp.noProgress( Comp.of(() -> button), - BindingsHelper.persist( - wrapper.getInRefresh().and(wrapper.getObserving().not()))); + wrapper.getInRefresh().and(wrapper.getObserving().not())); return loading.createRegion(); } @@ -138,7 +139,7 @@ public abstract class StoreEntryComp extends SimpleComp { } protected void applyState(Node node) { - SimpleChangeListener.apply(PlatformThread.sync(wrapper.getValidity()), val -> { + PlatformThread.sync(wrapper.getValidity()).subscribe(val -> { switch (val) { case LOAD_FAILED -> { node.pseudoClassStateChanged(FAILED, true); @@ -174,8 +175,7 @@ public abstract class StoreEntryComp extends SimpleComp { var imageComp = PrettyImageHelper.ofFixedSize(img, w, h); var storeIcon = imageComp.createRegion(); if (wrapper.getValidity().getValue().isUsable()) { - new FancyTooltipAugment<>(new SimpleStringProperty( - wrapper.getEntry().getProvider().getDisplayName())) + new TooltipAugment<>(wrapper.getEntry().getProvider().displayName()) .augment(storeIcon); } @@ -212,7 +212,7 @@ public abstract class StoreEntryComp extends SimpleComp { }); button.accessibleText( actionProvider.getName(wrapper.getEntry().ref()).getValue()); - button.apply(new FancyTooltipAugment<>( + button.apply(new TooltipAugment<>( actionProvider.getName(wrapper.getEntry().ref()))); if (actionProvider.activeType() == ActionProvider.DataStoreCallSite.ActiveType.ONLY_SHOW_IF_ENABLED) { button.hide(Bindings.not(p.getValue())); @@ -247,8 +247,10 @@ public abstract class StoreEntryComp extends SimpleComp { settingsButton.styleClass("settings"); settingsButton.accessibleText("More"); settingsButton.apply(new ContextMenuAugment<>( - event -> event.getButton() == MouseButton.PRIMARY, null, () -> StoreEntryComp.this.createContextMenu())); - settingsButton.apply(new FancyTooltipAugment<>("more")); + event -> event.getButton() == MouseButton.PRIMARY, + null, + () -> StoreEntryComp.this.createContextMenu())); + settingsButton.apply(new TooltipAugment<>("more")); return settingsButton; } @@ -371,7 +373,8 @@ public abstract class StoreEntryComp extends SimpleComp { StoreViewState.get() .getSortedCategories(wrapper.getCategory().getValue().getRoot()) .forEach(storeCategoryWrapper -> { - MenuItem m = new MenuItem(storeCategoryWrapper.getName()); + MenuItem m = new MenuItem(); + m.textProperty().bind(storeCategoryWrapper.nameProperty()); m.setOnAction(event -> { wrapper.moveTo(storeCategoryWrapper.getCategory()); event.consume(); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java index 2973a396a..979e8903f 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java @@ -5,7 +5,6 @@ import io.xpipe.app.comp.base.MultiContentComp; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.HorizontalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; import javafx.geometry.Insets; @@ -50,16 +49,16 @@ public class StoreEntryListComp extends SimpleComp { var map = new LinkedHashMap, ObservableValue>(); map.put( createList(), - BindingsHelper.persist(Bindings.not(Bindings.isEmpty( - StoreViewState.get().getCurrentTopLevelSection().getShownChildren())))); + Bindings.not(Bindings.isEmpty( + StoreViewState.get().getCurrentTopLevelSection().getShownChildren()))); map.put(new StoreIntroComp(), showIntro); map.put( new StoreNotFoundComp(), - BindingsHelper.persist(Bindings.and( + Bindings.and( Bindings.not(Bindings.isEmpty(StoreViewState.get().getAllEntries())), Bindings.isEmpty( - StoreViewState.get().getCurrentTopLevelSection().getShownChildren())))); + StoreViewState.get().getCurrentTopLevelSection().getShownChildren()))); return new MultiContentComp(map).createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java index 5eb91dee0..f667c6079 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java @@ -5,11 +5,11 @@ import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; import io.xpipe.app.fxcomps.impl.FilterComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.OsType; import javafx.beans.binding.Bindings; @@ -36,7 +36,7 @@ public class StoreEntryListStatusComp extends SimpleComp { public StoreEntryListStatusComp() { this.sortMode = new SimpleObjectProperty<>(); - SimpleChangeListener.apply(StoreViewState.get().getActiveCategory(), val -> { + StoreViewState.get().getActiveCategory().subscribe(val -> { sortMode.setValue(val.getSortMode().getValue()); }); sortMode.addListener((observable, oldValue, newValue) -> { @@ -51,21 +51,16 @@ public class StoreEntryListStatusComp extends SimpleComp { private Region createGroupListHeader() { var label = new Label(); - label.textProperty() - .bind(Bindings.createStringBinding( - () -> { - return StoreViewState.get() - .getActiveCategory() - .getValue() - .getRoot() - .equals(StoreViewState.get().getAllConnectionsCategory()) - ? "Connections" - : "Scripts"; - }, - StoreViewState.get().getActiveCategory())); + var name = BindingsHelper.flatMap( + StoreViewState.get().getActiveCategory(), + categoryWrapper -> AppI18n.observable( + categoryWrapper.getRoot().equals(StoreViewState.get().getAllConnectionsCategory()) + ? "connections" + : "scripts")); + label.textProperty().bind(name); label.getStyleClass().add("name"); - var all = BindingsHelper.filteredContentBinding( + var all = ListBindingsHelper.filteredContentBinding( StoreViewState.get().getAllEntries(), storeEntryWrapper -> { var storeRoot = storeEntryWrapper.getCategory().getValue().getRoot(); @@ -76,7 +71,7 @@ public class StoreEntryListStatusComp extends SimpleComp { .equals(storeRoot); }, StoreViewState.get().getActiveCategory()); - var shownList = BindingsHelper.filteredContentBinding( + var shownList = ListBindingsHelper.filteredContentBinding( all, storeEntryWrapper -> { return storeEntryWrapper.shouldShow( @@ -135,7 +130,8 @@ public class StoreEntryListStatusComp extends SimpleComp { } private Region createButtons() { - var menu = new MenuButton(AppI18n.get("addConnections"), new FontIcon("mdi2p-plus-thick")); + var menu = new MenuButton(null, new FontIcon("mdi2p-plus-thick")); + menu.textProperty().bind(AppI18n.observable("addConnections")); menu.setAlignment(Pos.CENTER); menu.setTextAlignment(TextAlignment.CENTER); AppFont.medium(menu); @@ -188,7 +184,7 @@ public class StoreEntryListStatusComp extends SimpleComp { sortMode)); }); alphabetical.accessibleTextKey("sortAlphabetical"); - alphabetical.apply(new FancyTooltipAugment<>("sortAlphabetical")); + alphabetical.apply(new TooltipAugment<>("sortAlphabetical")); return alphabetical; } @@ -227,7 +223,7 @@ public class StoreEntryListStatusComp extends SimpleComp { sortMode)); }); date.accessibleTextKey("sortLastUsed"); - date.apply(new FancyTooltipAugment<>("sortLastUsed")); + date.apply(new TooltipAugment<>("sortLastUsed")); return date; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java index dd5c0ed21..bc7689cd7 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java @@ -21,15 +21,18 @@ public class StoreIntroComp extends SimpleComp { @Override public Region createSimple() { - var title = new Label(AppI18n.get("storeIntroTitle")); + var title = new Label(); + title.textProperty().bind(AppI18n.observable("storeIntroTitle")); title.getStyleClass().add(Styles.TEXT_BOLD); AppFont.setSize(title, 7); - var introDesc = new Label(AppI18n.get("storeIntroDescription")); + var introDesc = new Label(); + introDesc.textProperty().bind(AppI18n.observable("storeIntroDescription")); introDesc.setWrapText(true); introDesc.setMaxWidth(470); - var scanButton = new Button(AppI18n.get("detectConnections"), new FontIcon("mdi2m-magnify")); + var scanButton = new Button(null, new FontIcon("mdi2m-magnify")); + scanButton.textProperty().bind(AppI18n.observable("detectConnections")); scanButton.setOnAction(event -> ScanAlert.showAsync(DataStorage.get().local())); scanButton.setDefaultButton(true); var scanPane = new StackPane(scanButton); @@ -43,12 +46,7 @@ public class StoreIntroComp extends SimpleComp { hbox.setSpacing(35); hbox.setAlignment(Pos.CENTER); - var v = new VBox( - hbox, scanPane - // new Separator(Orientation.HORIZONTAL), - // documentation, - // docLinkPane - ); + var v = new VBox(hbox, scanPane); v.setMinWidth(Region.USE_PREF_SIZE); v.setMaxWidth(Region.USE_PREF_SIZE); v.setMinHeight(Region.USE_PREF_SIZE); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java index e9af0f355..9c3de63d0 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java @@ -39,7 +39,7 @@ public class StoreProviderChoiceComp extends Comp(); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java index 77a81cbfc..44e35a972 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java @@ -42,7 +42,9 @@ public class StoreQuickAccessButtonComp extends Comp> { var graphic = w.getEntry().getProvider().getDisplayIconFileName(w.getEntry().getStore()); if (c.isEmpty()) { - var item = ContextMenuHelper.item(PrettyImageHelper.ofFixedSizeSquare(graphic, 16), w.getName().getValue()); + var item = ContextMenuHelper.item( + PrettyImageHelper.ofFixedSizeSquare(graphic, 16), + w.getName().getValue()); item.setOnAction(event -> { action.accept(w); contextMenu.hide(); @@ -83,7 +85,7 @@ public class StoreQuickAccessButtonComp extends Comp> { } struc.get().setOnAction(event -> { - ContextMenuHelper.toggleShow(cm,struc.get(), Side.RIGHT); + ContextMenuHelper.toggleShow(cm, struc.get(), Side.RIGHT); event.consume(); }); }); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java index 3780cc91c..68d050b44 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java @@ -2,6 +2,7 @@ package io.xpipe.app.comp.store; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; @@ -64,10 +65,10 @@ public class StoreSection { var c = Comparator.comparingInt( value -> value.getWrapper().getEntry().getValidity().isUsable() ? -1 : 1); - var mappedSortMode = BindingsHelper.mappedBinding( + var mappedSortMode = BindingsHelper.flatMap( category, storeCategoryWrapper -> storeCategoryWrapper != null ? storeCategoryWrapper.getSortMode() : null); - return BindingsHelper.orderedContentBinding( + return ListBindingsHelper.orderedContentBinding( list, (o1, o2) -> { var current = mappedSortMode.getValue(); @@ -86,16 +87,18 @@ public class StoreSection { Predicate entryFilter, ObservableStringValue filterString, ObservableValue category) { - var topLevel = BindingsHelper.filteredContentBinding( + var topLevel = ListBindingsHelper.filteredContentBinding( all, section -> { return DataStorage.get().isRootEntry(section.getEntry()); }, category); - var cached = BindingsHelper.cachedMappedContentBinding( - topLevel, storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category)); + var cached = ListBindingsHelper.cachedMappedContentBinding( + topLevel, + topLevel, + storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category)); var ordered = sorted(cached, category); - var shown = BindingsHelper.filteredContentBinding( + var shown = ListBindingsHelper.filteredContentBinding( ordered, section -> { var showFilter = filterString == null || section.shouldShow(filterString.get()); @@ -121,7 +124,7 @@ public class StoreSection { return new StoreSection(e, FXCollections.observableArrayList(), FXCollections.observableArrayList(), depth); } - var allChildren = BindingsHelper.filteredContentBinding(all, other -> { + var allChildren = ListBindingsHelper.filteredContentBinding(all, other -> { // Legacy implementation that does not use children caches. Use for testing // if (true) return DataStorage.get() // .getDisplayParent(other.getEntry()) @@ -131,10 +134,12 @@ public class StoreSection { // This check is fast as the children are cached in the storage return DataStorage.get().getStoreChildren(e.getEntry()).contains(other.getEntry()); }); - var cached = BindingsHelper.cachedMappedContentBinding( - allChildren, entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category)); + var cached = ListBindingsHelper.cachedMappedContentBinding( + allChildren, + allChildren, + entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category)); var ordered = sorted(cached, category); - var filtered = BindingsHelper.filteredContentBinding( + var filtered = ListBindingsHelper.filteredContentBinding( ordered, section -> { var showFilter = filterString == null || section.shouldShow(filterString.get()); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java index 96d111eda..8c6a9b764 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionComp.java @@ -7,8 +7,7 @@ import io.xpipe.app.fxcomps.augment.GrowAugment; import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.VerticalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.util.ThreadHelper; import javafx.beans.binding.Bindings; @@ -40,11 +39,11 @@ public class StoreSectionComp extends Comp> { } private Comp> createQuickAccessButton() { - var quickAccessDisabled = BindingsHelper.persist(Bindings.createBooleanBinding( + var quickAccessDisabled = Bindings.createBooleanBinding( () -> { return section.getShownChildren().isEmpty(); }, - section.getShownChildren())); + section.getShownChildren()); Consumer quickAccessAction = w -> { ThreadHelper.runFailableAsync(() -> { w.executeDefaultAction(); @@ -91,8 +90,7 @@ public class StoreSectionComp extends Comp> { return "Expand " + section.getWrapper().getName().getValue(); }, section.getWrapper().getName())) - .disable(BindingsHelper.persist( - Bindings.size(section.getShownChildren()).isEqualTo(0))) + .disable(Bindings.size(section.getShownChildren()).isEqualTo(0)) .styleClass("expand-button") .maxHeight(100) .vgrow(); @@ -131,7 +129,7 @@ public class StoreSectionComp extends Comp> { // Optimization for large sections. If there are more than 20 children, only add the nodes to the scene if the // section is actually expanded - var listSections = BindingsHelper.filteredContentBinding( + var listSections = ListBindingsHelper.filteredContentBinding( section.getShownChildren(), storeSection -> section.getAllChildren().size() <= 20 || section.getWrapper().getExpanded().get(), @@ -143,26 +141,26 @@ public class StoreSectionComp extends Comp> { .minHeight(0) .hgrow(); - var expanded = BindingsHelper.persist(Bindings.createBooleanBinding( + var expanded = Bindings.createBooleanBinding( () -> { return section.getWrapper().getExpanded().get() && section.getShownChildren().size() > 0; }, section.getWrapper().getExpanded(), - section.getShownChildren())); + section.getShownChildren()); var full = new VerticalComp(List.of( topEntryList, - Comp.separator().hide(BindingsHelper.persist(expanded.not())), + Comp.separator().hide(expanded.not()), new HorizontalComp(List.of(content)) .styleClass("content") .apply(struc -> struc.get().setFillHeight(true)) - .hide(BindingsHelper.persist(Bindings.or( + .hide(Bindings.or( Bindings.not(section.getWrapper().getExpanded()), - Bindings.size(section.getShownChildren()).isEqualTo(0)))))); + Bindings.size(section.getShownChildren()).isEqualTo(0))))); return full.styleClass("store-entry-section-comp") .apply(struc -> { struc.get().setFillWidth(true); - SimpleChangeListener.apply(expanded, val -> { + expanded.subscribe(val -> { struc.get().pseudoClassStateChanged(EXPANDED, val); }); struc.get().pseudoClassStateChanged(EVEN, section.getDepth() % 2 == 0); @@ -170,7 +168,7 @@ public class StoreSectionComp extends Comp> { struc.get().pseudoClassStateChanged(ROOT, topLevel); struc.get().pseudoClassStateChanged(SUB, !topLevel); - SimpleChangeListener.apply(section.getWrapper().getColor(), val -> { + section.getWrapper().getColor().subscribe(val -> { if (!topLevel) { return; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionMiniComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionMiniComp.java index f8f756fae..dc22b86f8 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSectionMiniComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSectionMiniComp.java @@ -8,8 +8,7 @@ import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.VerticalComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.storage.DataStoreColor; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; @@ -101,16 +100,15 @@ public class StoreSectionMiniComp extends Comp> { + section.getWrapper().getName().getValue(); }, section.getWrapper().getName())) - .disable(BindingsHelper.persist( - Bindings.size(section.getAllChildren()).isEqualTo(0))) + .disable(Bindings.size(section.getAllChildren()).isEqualTo(0)) .grow(false, true) .styleClass("expand-button"); - var quickAccessDisabled = BindingsHelper.persist(Bindings.createBooleanBinding( + var quickAccessDisabled = Bindings.createBooleanBinding( () -> { return section.getShownChildren().isEmpty(); }, - section.getShownChildren())); + section.getShownChildren()); Consumer quickAccessAction = w -> { action.accept(w); }; @@ -134,7 +132,7 @@ public class StoreSectionMiniComp extends Comp> { // Optimization for large sections. If there are more than 20 children, only add the nodes to the scene if the // section is actually expanded var listSections = section.getWrapper() != null - ? BindingsHelper.filteredContentBinding( + ? ListBindingsHelper.filteredContentBinding( section.getShownChildren(), storeSection -> section.getAllChildren().size() <= 20 || expanded.get(), expanded, @@ -149,9 +147,9 @@ public class StoreSectionMiniComp extends Comp> { list.add(new HorizontalComp(List.of(content)) .styleClass("content") .apply(struc -> struc.get().setFillHeight(true)) - .hide(BindingsHelper.persist(Bindings.or( + .hide(Bindings.or( Bindings.not(expanded), - Bindings.size(section.getAllChildren()).isEqualTo(0))))); + Bindings.size(section.getAllChildren()).isEqualTo(0)))); var vert = new VerticalComp(list); if (condensedStyle) { @@ -160,7 +158,7 @@ public class StoreSectionMiniComp extends Comp> { return vert.styleClass("store-section-mini-comp") .apply(struc -> { struc.get().setFillWidth(true); - SimpleChangeListener.apply(expanded, val -> { + expanded.subscribe(val -> { struc.get().pseudoClassStateChanged(EXPANDED, val); }); struc.get().pseudoClassStateChanged(EVEN, section.getDepth() % 2 == 0); @@ -171,7 +169,7 @@ public class StoreSectionMiniComp extends Comp> { }) .apply(struc -> { if (section.getWrapper() != null) { - SimpleChangeListener.apply(section.getWrapper().getColor(), val -> { + section.getWrapper().getColor().subscribe(val -> { if (section.getDepth() != 1) { return; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java index 8b6d019b0..84f9816a2 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java @@ -1,7 +1,7 @@ package io.xpipe.app.comp.store; import io.xpipe.app.core.AppCache; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; @@ -270,10 +270,12 @@ public class StoreViewState { return parent; } - return o1.getName().compareToIgnoreCase(o2.getName()); + return o1.nameProperty() + .getValue() + .compareToIgnoreCase(o2.nameProperty().getValue()); } }; - return BindingsHelper.filteredContentBinding( + return ListBindingsHelper.filteredContentBinding( categories, cat -> root == null || cat.getRoot().equals(root)) .sorted(comparator); } diff --git a/app/src/main/java/io/xpipe/app/core/App.java b/app/src/main/java/io/xpipe/app/core/App.java index 99a9e6171..df6873f9c 100644 --- a/app/src/main/java/io/xpipe/app/core/App.java +++ b/app/src/main/java/io/xpipe/app/core/App.java @@ -65,13 +65,13 @@ public class App extends Application { "XPipe %s (%s)", t.getValue(), AppProperties.get().getVersion()); var prefix = AppProperties.get().isStaging() ? "[Public Test Build, Not a proper release] " : ""; var suffix = u.getValue() != null - ? String.format( - " (Update to %s ready)", u.getValue().getVersion()) + ? AppI18n.get("updateReadyTitle", u.getValue().getVersion()) : ""; return prefix + base + suffix; }, u, - t); + t, + AppPrefs.get().language()); var appWindow = AppMainWindow.init(stage); appWindow.getStage().titleProperty().bind(PlatformThread.sync(titleBinding)); diff --git a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java index a1b009b0e..d198685bc 100644 --- a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java +++ b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java @@ -1,11 +1,11 @@ package io.xpipe.app.core; -import io.xpipe.app.exchange.MessageExchangeImpls; import io.xpipe.app.ext.ExtensionException; -import io.xpipe.app.ext.XPipeServiceProviders; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; +import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.util.ModuleHelper; +import io.xpipe.core.util.ModuleLayerLoader; import io.xpipe.core.util.XPipeInstallation; import lombok.Getter; import lombok.Value; @@ -47,10 +47,11 @@ public class AppExtensionManager { } if (load) { - // INSTANCE.addNativeLibrariesToPath(); try { - XPipeServiceProviders.load(INSTANCE.extendedLayer); - MessageExchangeImpls.loadAll(); + ProcessControlProvider.init(INSTANCE.extendedLayer); + ModuleLayerLoader.loadAll(INSTANCE.extendedLayer, t -> { + ErrorEvent.fromThrowable(t).handle(); + }); } catch (Throwable t) { throw new ExtensionException( "Service provider initialization failed. Is the installation data corrupt?", t); diff --git a/app/src/main/java/io/xpipe/app/core/AppGreetings.java b/app/src/main/java/io/xpipe/app/core/AppGreetings.java index 08be1218e..9f2f92486 100644 --- a/app/src/main/java/io/xpipe/app/core/AppGreetings.java +++ b/app/src/main/java/io/xpipe/app/core/AppGreetings.java @@ -3,7 +3,6 @@ package io.xpipe.app.core; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.fxcomps.Comp; -import io.xpipe.app.fxcomps.util.BindingsHelper; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -98,7 +97,7 @@ public class AppGreetings { alert.getButtonTypes().add(buttonType); Button button = (Button) alert.getDialogPane().lookupButton(buttonType); - button.disableProperty().bind(BindingsHelper.persist(accepted.not())); + button.disableProperty().bind(accepted.not()); } alert.getButtonTypes().add(ButtonType.CANCEL); diff --git a/app/src/main/java/io/xpipe/app/core/AppI18n.java b/app/src/main/java/io/xpipe/app/core/AppI18n.java index 327042b30..367dfad13 100644 --- a/app/src/main/java/io/xpipe/app/core/AppI18n.java +++ b/app/src/main/java/io/xpipe/app/core/AppI18n.java @@ -2,7 +2,7 @@ package io.xpipe.app.core; import io.xpipe.app.comp.base.ModalOverlayComp; import io.xpipe.app.ext.PrefsChoiceValue; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; @@ -10,112 +10,57 @@ import io.xpipe.app.prefs.SupportedLocale; import io.xpipe.app.util.OptionsBuilder; import io.xpipe.app.util.Translatable; import io.xpipe.core.util.ModuleHelper; +import io.xpipe.core.util.XPipeInstallation; import javafx.beans.binding.Bindings; -import javafx.beans.binding.StringBinding; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import lombok.SneakyThrows; +import lombok.Value; import org.apache.commons.io.FilenameUtils; import org.ocpsoft.prettytime.PrettyTime; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.time.Duration; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.UnaryOperator; import java.util.regex.Pattern; public class AppI18n { private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\w+?\\$"); - private static final AppI18n INSTANCE = new AppI18n(); - private Map translations; - private Map markdownDocumentations; - private PrettyTime prettyTime; + private static AppI18n INSTANCE; + private final Property currentLanguage = new SimpleObjectProperty<>(); + private LoadedTranslations english; - public static void init() { - var i = INSTANCE; - if (i.translations != null) { - return; - } - - i.load(); - - if (AppPrefs.get() != null) { - AppPrefs.get().language().addListener((c, o, n) -> { - i.clear(); - i.load(); - }); + public static void init() throws Exception { + if (INSTANCE == null) { + INSTANCE = new AppI18n(); } + INSTANCE.load(); } - public static AppI18n getInstance() { + public static AppI18n get() { return INSTANCE; } - public static StringBinding readableInstant(String s, ObservableValue instant) { - return readableInstant(instant, rs -> getValue(getInstance().getLocalised(s), rs)); - } - - public static StringBinding readableInstant(ObservableValue instant, UnaryOperator op) { - return Bindings.createStringBinding( - () -> { - if (instant.getValue() == null) { - return "null"; - } - - return op.apply( - getInstance().prettyTime.format(instant.getValue().minus(Duration.ofSeconds(1)))); - }, - instant); - } - - public static StringBinding readableInstant(ObservableValue instant) { - return Bindings.createStringBinding( - () -> { - if (instant.getValue() == null) { - return "null"; - } - - return getInstance().prettyTime.format(instant.getValue().minus(Duration.ofSeconds(1))); - }, - instant); - } - - public static StringBinding readableDuration(ObservableValue duration) { - return Bindings.createStringBinding( - () -> { - if (duration.getValue() == null) { - return "null"; - } - - return getInstance() - .prettyTime - .formatDuration(getInstance() - .prettyTime - .approximateDuration(Instant.now().plus(duration.getValue()))); - }, - duration); - } - public static ObservableValue observable(String s, Object... vars) { if (s == null) { return null; } var key = INSTANCE.getKey(s); - return Bindings.createStringBinding(() -> { - return get(key, vars); - }); + return Bindings.createStringBinding( + () -> { + return get(key, vars); + }, + INSTANCE.currentLanguage); } public static String get(String s, Object... vars) { @@ -147,7 +92,7 @@ public class AppI18n { || caller.equals(ModuleHelper.class) || caller.equals(ModalOverlayComp.class) || caller.equals(AppI18n.class) - || caller.equals(FancyTooltipAugment.class) + || caller.equals(TooltipAugment.class) || caller.equals(PrefsChoiceValue.class) || caller.equals(Translatable.class) || caller.equals(AppWindowHelper.class) @@ -160,9 +105,28 @@ public class AppI18n { return ""; } - private void clear() { - translations.clear(); - prettyTime = null; + private void load() throws Exception { + if (english == null) { + english = load(Locale.ENGLISH); + Locale.setDefault(Locale.ENGLISH); + } + + if (currentLanguage.getValue() == null) { + if (AppPrefs.get() != null) { + AppPrefs.get().language().subscribe(n -> { + try { + currentLanguage.setValue(n != null ? load(n.getLocale()) : null); + Locale.setDefault(n != null ? n.getLocale() : Locale.ENGLISH); + } catch (Exception e) { + ErrorEvent.fromThrowable(e).handle(); + } + }); + } + } + } + + private LoadedTranslations getLoaded() { + return currentLanguage.getValue() != null ? currentLanguage.getValue() : english; } public String getKey(String s) { @@ -173,142 +137,156 @@ public class AppI18n { return key; } - public boolean containsKey(String s) { - var key = getKey(s); - if (translations == null) { - return false; - } - - return translations.containsKey(key); - } - public String getLocalised(String s, Object... vars) { var key = getKey(s); - if (translations == null) { + if (english == null) { TrackEvent.warn("Translations not initialized for " + key); return s; } - if (!translations.containsKey(key)) { - TrackEvent.warn("Translation key not found for " + key); - return key; + if (currentLanguage.getValue() != null + && currentLanguage.getValue().getTranslations().containsKey(key)) { + var localisedString = currentLanguage.getValue().getTranslations().get(key); + return getValue(localisedString, vars); } - var localisedString = translations.get(key); - return getValue(localisedString, vars); + if (english.getTranslations().containsKey(key)) { + var localisedString = english.getTranslations().get(key); + return getValue(localisedString, vars); + } + + TrackEvent.warn("Translation key not found for " + key); + return key; } - public boolean isLoaded() { - return translations != null; - } - - private boolean matchesLocale(Path f) { - var l = AppPrefs.get() != null - ? AppPrefs.get().language().getValue().getLocale() - : SupportedLocale.ENGLISH.getLocale(); + private boolean matchesLocale(Path f, Locale l) { var name = FilenameUtils.getBaseName(f.getFileName().toString()); var ending = "_" + l.toLanguageTag(); return name.endsWith(ending); } public String getMarkdownDocumentation(String name) { - if (!markdownDocumentations.containsKey(name)) { - TrackEvent.withWarn("Markdown documentation for key " + name + " not found") + if (currentLanguage.getValue() != null + && currentLanguage.getValue().getMarkdownDocumentations().containsKey(name)) { + var localisedString = + currentLanguage.getValue().getMarkdownDocumentations().get(name); + return localisedString; + } + + if (english.getMarkdownDocumentations().containsKey(name)) { + var localisedString = english.getMarkdownDocumentations().get(name); + return localisedString; + } + + TrackEvent.withWarn("Markdown documentation for key " + name + " not found") + .handle(); + return ""; + } + + private Path getModuleLangPath(String module) { + return XPipeInstallation.getLangPath().resolve(module); + } + + private LoadedTranslations load(Locale l) throws Exception { + TrackEvent.info("Loading translations ..."); + + var translations = new HashMap(); + for (var module : AppExtensionManager.getInstance().getContentModules()) { + var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())) + .resolve("strings"); + if (!Files.exists(basePath)) { + continue; + } + + AtomicInteger fileCounter = new AtomicInteger(); + AtomicInteger lineCounter = new AtomicInteger(); + var simpleName = FilenameUtils.getExtension(module.getName()); + String defaultPrefix = simpleName.equals("app") ? "app." : simpleName + "."; + Files.walkFileTree(basePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (!matchesLocale(file, l)) { + return FileVisitResult.CONTINUE; + } + + if (!file.getFileName().toString().endsWith(".properties")) { + return FileVisitResult.CONTINUE; + } + + fileCounter.incrementAndGet(); + try (var in = Files.newInputStream(file)) { + var props = new Properties(); + props.load(new InputStreamReader(in, StandardCharsets.UTF_8)); + props.forEach((key, value) -> { + var hasPrefix = key.toString().contains("."); + var usedPrefix = hasPrefix ? "" : defaultPrefix; + translations.put(usedPrefix + key, value.toString()); + lineCounter.incrementAndGet(); + }); + } catch (IOException ex) { + ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); + } + return FileVisitResult.CONTINUE; + } + }); + + TrackEvent.withDebug("Loading translations for module " + simpleName) + .tag("fileCount", fileCounter.get()) + .tag("lineCount", lineCounter.get()) .handle(); } - return markdownDocumentations.getOrDefault(name, ""); - } - - private void load() { - TrackEvent.info("Loading translations ..."); - - translations = new HashMap<>(); + var markdownDocumentations = new HashMap(); for (var module : AppExtensionManager.getInstance().getContentModules()) { - AppResources.with(module.getName(), "lang", basePath -> { - if (!Files.exists(basePath)) { - return; - } + var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())) + .resolve("texts"); + if (!Files.exists(basePath)) { + continue; + } - AtomicInteger fileCounter = new AtomicInteger(); - AtomicInteger lineCounter = new AtomicInteger(); - var simpleName = FilenameUtils.getExtension(module.getName()); - String defaultPrefix = simpleName.equals("app") ? "app." : simpleName + "."; - Files.walkFileTree(basePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (!matchesLocale(file)) { - return FileVisitResult.CONTINUE; - } - - if (!file.getFileName().toString().endsWith(".properties")) { - return FileVisitResult.CONTINUE; - } - - fileCounter.incrementAndGet(); - try (var in = Files.newInputStream(file)) { - var props = new Properties(); - props.load(in); - props.forEach((key, value) -> { - var hasPrefix = key.toString().contains("."); - var usedPrefix = hasPrefix ? "" : defaultPrefix; - translations.put(usedPrefix + key, value.toString()); - lineCounter.incrementAndGet(); - }); - } catch (IOException ex) { - ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); - } + var moduleName = FilenameUtils.getExtension(module.getName()); + Files.walkFileTree(basePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (!matchesLocale(file, l)) { return FileVisitResult.CONTINUE; } - }); - TrackEvent.withDebug("Loading translations for module " + simpleName) - .tag("fileCount", fileCounter.get()) - .tag("lineCount", lineCounter.get()) - .handle(); + if (!file.getFileName().toString().endsWith(".md")) { + return FileVisitResult.CONTINUE; + } + + var name = file.getFileName() + .toString() + .substring(0, file.getFileName().toString().lastIndexOf("_")); + try (var in = Files.newInputStream(file)) { + var usedPrefix = moduleName + ":"; + markdownDocumentations.put( + usedPrefix + name, new String(in.readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException ex) { + ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); + } + return FileVisitResult.CONTINUE; + } }); } - markdownDocumentations = new HashMap<>(); - for (var module : AppExtensionManager.getInstance().getContentModules()) { - AppResources.with(module.getName(), "lang", basePath -> { - if (!Files.exists(basePath)) { - return; - } - - var moduleName = FilenameUtils.getExtension(module.getName()); - Files.walkFileTree(basePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (!matchesLocale(file)) { - return FileVisitResult.CONTINUE; - } - - if (!file.getFileName().toString().endsWith(".md")) { - return FileVisitResult.CONTINUE; - } - - var name = file.getFileName() - .toString() - .substring(0, file.getFileName().toString().lastIndexOf("_")); - try (var in = Files.newInputStream(file)) { - var usedPrefix = moduleName + ":"; - markdownDocumentations.put( - usedPrefix + name, new String(in.readAllBytes(), StandardCharsets.UTF_8)); - } catch (IOException ex) { - ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); - } - return FileVisitResult.CONTINUE; - } - }); - }); - } - - this.prettyTime = new PrettyTime( + var prettyTime = new PrettyTime( AppPrefs.get() != null ? AppPrefs.get().language().getValue().getLocale() - : SupportedLocale.ENGLISH.getLocale()); + : SupportedLocale.getEnglish().getLocale()); + + return new LoadedTranslations(l, translations, markdownDocumentations, prettyTime); + } + + @Value + static class LoadedTranslations { + + Locale locale; + Map translations; + Map markdownDocumentations; + PrettyTime prettyTime; } @SuppressWarnings("removal") diff --git a/app/src/main/java/io/xpipe/app/core/AppImages.java b/app/src/main/java/io/xpipe/app/core/AppImages.java index 07fcdc688..7a4dc4c6d 100644 --- a/app/src/main/java/io/xpipe/app/core/AppImages.java +++ b/app/src/main/java/io/xpipe/app/core/AppImages.java @@ -30,11 +30,11 @@ public class AppImages { TrackEvent.info("Loading images ..."); for (var module : AppExtensionManager.getInstance().getContentModules()) { - loadDirectory(module.getName(), "img"); + loadDirectory(module.getName(), "img", true, true); } } - public static void loadDirectory(String module, String dir) { + public static void loadDirectory(String module, String dir, boolean loadImages, boolean loadSvgs) { AppResources.with(module, dir, basePath -> { if (!Files.exists(basePath)) { return; @@ -48,10 +48,10 @@ public class AppImages { var relativeFileName = FilenameUtils.separatorsToUnix( basePath.relativize(file).toString()); try { - if (FilenameUtils.getExtension(file.toString()).equals("svg")) { + if (FilenameUtils.getExtension(file.toString()).equals("svg") && loadSvgs) { var s = Files.readString(file); svgImages.put(defaultPrefix + relativeFileName, s); - } else { + } else if (loadImages) { images.put(defaultPrefix + relativeFileName, loadImage(file)); } } catch (IOException ex) { diff --git a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java index 8860ef334..ccfad3989 100644 --- a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java +++ b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java @@ -1,11 +1,9 @@ package io.xpipe.app.core; -import io.xpipe.app.browser.BrowserComp; -import io.xpipe.app.browser.BrowserModel; -import io.xpipe.app.comp.DeveloperTabComp; +import io.xpipe.app.browser.session.BrowserSessionComp; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.store.StoreLayoutComp; import io.xpipe.app.fxcomps.Comp; -import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefsComp; import io.xpipe.app.util.LicenseProvider; import javafx.beans.property.Property; @@ -30,13 +28,11 @@ public class AppLayoutModel { private final List entries; private final Property selected; - private final ObservableValue selectedWrapper; public AppLayoutModel(SavedState savedState) { this.savedState = savedState; this.entries = createEntryList(); this.selected = new SimpleObjectProperty<>(entries.get(1)); - this.selectedWrapper = PlatformThread.sync(selected); } public static AppLayoutModel get() { @@ -53,14 +49,10 @@ public class AppLayoutModel { INSTANCE = null; } - public Property getSelectedInternal() { + public Property getSelected() { return selected; } - public ObservableValue getSelected() { - return selectedWrapper; - } - public void selectBrowser() { selected.setValue(entries.getFirst()); } @@ -79,21 +71,16 @@ public class AppLayoutModel { private List createEntryList() { var l = new ArrayList<>(List.of( - new Entry(AppI18n.observable("browser"), "mdi2f-file-cabinet", new BrowserComp(BrowserModel.DEFAULT)), + new Entry( + AppI18n.observable("browser"), + "mdi2f-file-cabinet", + new BrowserSessionComp(BrowserSessionModel.DEFAULT)), new Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()), - new Entry(AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new AppPrefsComp()))); - // new SideMenuBarComp.Entry(AppI18n.observable("help"), "mdi2b-book-open-variant", new - // StorageLayoutComp()), - // new SideMenuBarComp.Entry(AppI18n.observable("account"), "mdi2a-account", new StorageLayoutComp()) - if (AppProperties.get().isDeveloperMode() && !AppProperties.get().isImage()) { - l.add(new Entry(AppI18n.observable("developer"), "mdi2b-book-open-variant", new DeveloperTabComp())); - } - - l.add(new Entry( - AppI18n.observable("explorePlans"), - "mdi2p-professional-hexagon", - LicenseProvider.get().overviewPage())); - + new Entry(AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new AppPrefsComp()), + new Entry( + AppI18n.observable("explorePlans"), + "mdi2p-professional-hexagon", + LicenseProvider.get().overviewPage()))); return l; } diff --git a/app/src/main/java/io/xpipe/app/core/AppProperties.java b/app/src/main/java/io/xpipe/app/core/AppProperties.java index 24254c84c..2efcc1f64 100644 --- a/app/src/main/java/io/xpipe/app/core/AppProperties.java +++ b/app/src/main/java/io/xpipe/app/core/AppProperties.java @@ -29,6 +29,7 @@ public class AppProperties { UUID buildUuid; String sentryUrl; String arch; + List languages; @Getter boolean image; @@ -53,6 +54,7 @@ public class AppProperties { .orElse(UUID.randomUUID()); sentryUrl = System.getProperty("io.xpipe.app.sentryUrl"); arch = System.getProperty("io.xpipe.app.arch"); + languages = Arrays.asList(System.getProperty("io.xpipe.app.languages").split(";")); staging = XPipeInstallation.isStaging(); useVirtualThreads = Optional.ofNullable(System.getProperty("io.xpipe.app.useVirtualThreads")) .map(Boolean::parseBoolean) diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index ff8625600..0f1d5f1db 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -3,25 +3,24 @@ package io.xpipe.app.core; import atlantafx.base.theme.*; import io.xpipe.app.ext.PrefsChoiceValue; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.process.OsType; -import javafx.animation.Interpolator; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; +import javafx.animation.*; import javafx.application.Application; import javafx.application.ColorScheme; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; import javafx.css.PseudoClass; +import javafx.event.EventHandler; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.Pane; +import javafx.stage.Stage; import javafx.stage.Window; +import javafx.stage.WindowEvent; import javafx.util.Duration; import lombok.AllArgsConstructor; import lombok.Getter; @@ -39,26 +38,75 @@ public class AppTheme { private static final PseudoClass PERFORMANCE = PseudoClass.getPseudoClass("performance"); private static boolean init; - public static void initThemeHandlers(Window stage) { + public static void initThemeHandlers(Stage stage) { if (AppPrefs.get() == null) { return; } - SimpleChangeListener.apply(AppPrefs.get().theme, t -> { - Theme.ALL.forEach( - theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); - if (t == null) { - return; + initWindowsThemeHandler(stage); + + Runnable r = () -> { + AppPrefs.get().theme.subscribe(t -> { + Theme.ALL.forEach( + theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); + if (t == null) { + return; + } + + stage.getScene().getRoot().getStyleClass().add(t.getCssId()); + stage.getScene().getRoot().pseudoClassStateChanged(LIGHT, !t.isDark()); + stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark()); + }); + + AppPrefs.get().performanceMode().subscribe(val -> { + stage.getScene().getRoot().pseudoClassStateChanged(PRETTY, !val); + stage.getScene().getRoot().pseudoClassStateChanged(PERFORMANCE, val); + }); + }; + if (stage.getOwner() != null) { + // If we set the theme pseudo classes earlier when the window is not shown + // they do not apply. Is this a bug in JavaFX? + Platform.runLater(r); + } else { + r.run(); + } + } + + private static void initWindowsThemeHandler(Window stage) { + if (OsType.getLocal() != OsType.WINDOWS) { + return; + } + + EventHandler windowTheme = new EventHandler<>() { + @Override + public void handle(WindowEvent event) { + if (!stage.isShowing()) { + return; + } + + try { +// var c = new WindowControl(stage); +// c.setWindowAttribute(20, AppPrefs.get().theme.getValue().isDark()); + } catch (Throwable e) { + ErrorEvent.fromThrowable(e).handle(); + } + stage.removeEventFilter(WindowEvent.WINDOW_SHOWN, this); } + }; + if (stage.isShowing()) { + windowTheme.handle(null); + } else { + stage.addEventFilter(WindowEvent.WINDOW_SHOWN, windowTheme); + } - stage.getScene().getRoot().getStyleClass().add(t.getCssId()); - stage.getScene().getRoot().pseudoClassStateChanged(LIGHT, !t.isDark()); - stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark()); - }); - - SimpleChangeListener.apply(AppPrefs.get().performanceMode(), val -> { - stage.getScene().getRoot().pseudoClassStateChanged(PRETTY, !val); - stage.getScene().getRoot().pseudoClassStateChanged(PERFORMANCE, val); + AppPrefs.get().theme.addListener((observable, oldValue, newValue) -> { + Platform.runLater(() -> { + var transition = new PauseTransition(Duration.millis(300)); + transition.setOnFinished(e -> { + windowTheme.handle(null); + }); + transition.play(); + }); }); } diff --git a/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java b/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java index 1cfc5f0c5..d2f1895ac 100644 --- a/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java +++ b/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java @@ -53,11 +53,12 @@ public class AppWindowHelper { // This allows for assigning logos even if AppImages has not been initialized yet var dir = OsType.getLocal() == OsType.MACOS ? "img/logo/padded" : "img/logo/full"; AppResources.with(AppResources.XPIPE_MODULE, dir, path -> { - var size = switch (OsType.getLocal()) { - case OsType.Linux linux -> 128; - case OsType.MacOs macOs -> 128; - case OsType.Windows windows -> 32; - }; + var size = + switch (OsType.getLocal()) { + case OsType.Linux linux -> 128; + case OsType.MacOs macOs -> 128; + case OsType.Windows windows -> 32; + }; stage.getIcons().add(AppImages.loadImage(path.resolve("logo_" + size + "x" + size + ".png"))); }); } @@ -82,12 +83,7 @@ public class AppWindowHelper { } stage.setOnShown(e -> { - // If we set the theme pseudo classes earlier when the window is not shown - // they do not apply. Is this a bug in JavaFX? - Platform.runLater(() -> { - AppTheme.initThemeHandlers(stage); - }); - + AppTheme.initThemeHandlers(stage); centerToMainWindow(stage); clampWindow(stage).ifPresent(rectangle2D -> { stage.setX(rectangle2D.getMinX()); diff --git a/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java index 5ed0fc06f..d3812b757 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java @@ -13,7 +13,8 @@ public class AppFontLoadingCheck { // This can fail if the found system fonts can somehow not be loaded Font.getDefault(); } catch (Throwable e) { - var event = ErrorEvent.fromThrowable("Unable to load fonts", e).build(); + var event = ErrorEvent.fromThrowable("Unable to load fonts. Do you have valid font packages installed?", e) + .build(); // We can't use the normal error handling facility // as the platform reports as working but opening windows still does not work new LogErrorHandler().handle(event); diff --git a/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java index 0dc00b6c7..458fd1505 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java @@ -18,7 +18,7 @@ public class AppPtbCheck { .setContent(AppWindowHelper.alertContentText("You are running a PTB build of XPipe." + " This version is unstable and might contain bugs." + " You should not use it as a daily driver." - + " It will also not receive regular updates." + + " It will also not receive regular updates after its testing period." + " You will have to install and launch the normal XPipe release for that.")); }); } diff --git a/app/src/main/java/io/xpipe/app/core/check/AppShellCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppShellCheck.java index fde248476..086203c6d 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppShellCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppShellCheck.java @@ -55,6 +55,7 @@ public class AppShellCheck { - On Windows, an AntiVirus program might block required programs and commands - The system shell is restricted or blocked - Some elementary command-line tools are not available or not working correctly + - Your PATH environment variable is corrupt / incomplete %s """ diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index 450af36e5..397219c0d 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -1,6 +1,6 @@ package io.xpipe.app.core.mode; -import io.xpipe.app.browser.BrowserModel; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.*; import io.xpipe.app.core.check.AppAvCheck; @@ -47,6 +47,7 @@ public class BaseMode extends OperationMode { AppI18n.init(); LicenseProvider.get().init(); AppPrefs.initLocal(); + AppI18n.init(); AppCertutilCheck.check(); AppAvCheck.check(); AppSid.init(); @@ -74,7 +75,7 @@ public class BaseMode extends OperationMode { @Override public void finalTeardown() { TrackEvent.info("Background mode shutdown started"); - BrowserModel.DEFAULT.reset(); + BrowserSessionModel.DEFAULT.reset(); StoreViewState.reset(); DataStorage.reset(); AppPrefs.reset(); diff --git a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java index a61c3311c..a7dfb5a7c 100644 --- a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java @@ -2,7 +2,6 @@ package io.xpipe.app.exchange; import io.xpipe.beacon.BeaconHandler; import io.xpipe.beacon.exchange.LaunchExchange; -import io.xpipe.core.process.TerminalInitScriptConfig; import io.xpipe.core.store.LaunchableStore; import java.util.Arrays; @@ -16,9 +15,9 @@ public class LaunchExchangeImpl extends LaunchExchange public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { var store = getStoreEntryById(msg.getId(), false); if (store.getStore() instanceof LaunchableStore s) { - var command = s.prepareLaunchCommand() - .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null); - return Response.builder().command(split(command)).build(); + // var command = s.prepareLaunchCommand() + // .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null); + // return Response.builder().command(split(command)).build(); } throw new IllegalArgumentException(store.getName() + " is not launchable"); diff --git a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java index b318e8069..94a18b15b 100644 --- a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java +++ b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java @@ -3,6 +3,7 @@ package io.xpipe.app.exchange; import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.exchange.MessageExchanges; +import io.xpipe.core.util.ModuleLayerLoader; import java.util.List; import java.util.Optional; @@ -13,27 +14,6 @@ public class MessageExchangeImpls { private static List> ALL; - public static void loadAll() { - ALL = ServiceLoader.load(MessageExchangeImpl.class).stream() - .map(s -> { - // TrackEvent.trace("init", "Loaded exchange implementation " + ex.getId()); - return (MessageExchangeImpl) s.get(); - }) - .collect(Collectors.toList()); - - ALL.forEach(messageExchange -> { - if (MessageExchanges.byId(messageExchange.getId()).isEmpty()) { - throw new AssertionError("Missing base exchange: " + messageExchange.getId()); - } - }); - - MessageExchanges.getAll().forEach(messageExchange -> { - if (MessageExchangeImpls.byId(messageExchange.getId()).isEmpty()) { - throw new AssertionError("Missing exchange implementation: " + messageExchange.getId()); - } - }); - } - @SuppressWarnings("unchecked") public static Optional> byId( String name) { @@ -53,4 +33,29 @@ public class MessageExchangeImpls { public static List> getAll() { return ALL; } + + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { + ALL = ServiceLoader.load(layer, MessageExchangeImpl.class).stream() + .map(s -> { + // TrackEvent.trace("init", "Loaded exchange implementation " + ex.getId()); + return (MessageExchangeImpl) s.get(); + }) + .collect(Collectors.toList()); + + ALL.forEach(messageExchange -> { + if (MessageExchanges.byId(messageExchange.getId()).isEmpty()) { + throw new AssertionError("Missing base exchange: " + messageExchange.getId()); + } + }); + + MessageExchanges.getAll().forEach(messageExchange -> { + if (MessageExchangeImpls.byId(messageExchange.getId()).isEmpty()) { + throw new AssertionError("Missing exchange implementation: " + messageExchange.getId()); + } + }); + } + } } diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java deleted file mode 100644 index 972559515..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/InstanceExchangeImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.update.XPipeInstanceHelper; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.InstanceExchange; -import io.xpipe.core.store.LocalStore; - -public class InstanceExchangeImpl extends InstanceExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - return Response.builder() - .instance(XPipeInstanceHelper.getInstance(new LocalStore()).orElseThrow()) - .build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java index 50833abee..b89861049 100644 --- a/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java @@ -22,7 +22,7 @@ public class StoreProviderListExchangeImpl extends StoreProviderListExchange .filter(dataStoreProvider -> category.equals(dataStoreProvider.getCreationCategory())) .map(p -> ProviderEntry.builder() .id(p.getId()) - .description(p.getDisplayDescription()) + .description(p.displayDescription().getValue()) .hidden(p.getCreationCategory() == null) .build()) .toList())); diff --git a/app/src/main/java/io/xpipe/app/ext/ActionProvider.java b/app/src/main/java/io/xpipe/app/ext/ActionProvider.java index 208b637e9..e08ccf72f 100644 --- a/app/src/main/java/io/xpipe/app/ext/ActionProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ActionProvider.java @@ -143,15 +143,5 @@ public interface ActionProvider { }) .toList()); } - - @Override - public boolean requiresFullDaemon() { - return true; - } - - @Override - public boolean prioritizeLoading() { - return false; - } } } diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java index 23d94a170..42ef90e01 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProvider.java @@ -1,5 +1,6 @@ package io.xpipe.app.ext; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.store.StoreEntryComp; import io.xpipe.app.comp.store.StoreEntryWrapper; @@ -15,6 +16,7 @@ import io.xpipe.core.dialog.Dialog; import io.xpipe.core.store.DataStore; import io.xpipe.core.util.JacksonizedValue; import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -44,6 +46,14 @@ public interface DataStoreProvider { } } + default ActionProvider.Action launchAction(DataStoreEntry store) { + return null; + } + + default ActionProvider.Action browserAction(BrowserSessionModel sessionModel, DataStoreEntry store, BooleanProperty busy) { + return null; + } + default String browserDisplayName(DataStore store) { var e = DataStorage.get().getStoreDisplayName(store); return e.orElse("?"); @@ -147,19 +157,15 @@ public interface DataStoreProvider { return new SimpleStringProperty(null); } - default String i18n(String key) { - return AppI18n.get(getId() + "." + key); + default ObservableValue i18n(String key) { + return AppI18n.observable(getId() + "." + key); } - default String i18nKey(String key) { - return getId() + "." + key; - } - - default String getDisplayName() { + default ObservableValue displayName() { return i18n("displayName"); } - default String getDisplayDescription() { + default ObservableValue displayDescription() { return i18n("displayDescription"); } @@ -201,6 +207,7 @@ public interface DataStoreProvider { COMMAND, TUNNEL, SCRIPT, - CLUSTER + CLUSTER, + VISUAL; } } diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java index 7931ae3ef..7b62155f1 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java @@ -1,7 +1,11 @@ package io.xpipe.app.ext; +import com.fasterxml.jackson.databind.jsontype.NamedType; import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.app.issue.TrackEvent; import io.xpipe.core.store.DataStore; +import io.xpipe.core.util.JacksonMapper; +import io.xpipe.core.util.ModuleLayerLoader; import java.util.List; import java.util.Optional; @@ -12,27 +16,6 @@ public class DataStoreProviders { private static List ALL; - public static void init(ModuleLayer layer) { - if (ALL == null) { - ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream() - .map(ServiceLoader.Provider::get) - .collect(Collectors.toList()); - ALL.removeIf(p -> { - try { - if (!p.init()) { - return true; - } - - p.validate(); - return false; - } catch (Throwable e) { - ErrorEvent.fromThrowable(e).handle(); - return true; - } - }); - } - } - public static void postInit(ModuleLayer layer) { ALL.forEach(p -> { try { @@ -86,4 +69,37 @@ public class DataStoreProviders { public static List getAll() { return ALL; } + + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { + TrackEvent.info("Loading extension providers ..."); + ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream() + .map(ServiceLoader.Provider::get) + .collect(Collectors.toList()); + ALL.removeIf(p -> { + try { + if (!p.init()) { + return true; + } + + p.validate(); + return false; + } catch (Throwable e) { + ErrorEvent.fromThrowable(e).handle(); + return true; + } + }); + + for (DataStoreProvider p : getAll()) { + TrackEvent.trace("Loaded data store provider " + p.getId()); + JacksonMapper.configure(objectMapper -> { + for (Class storeClass : p.getStoreClasses()) { + objectMapper.registerSubtypes(new NamedType(storeClass)); + } + }); + } + } + } } diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java b/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java index 8e3f87436..e42f70bd2 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java @@ -30,20 +30,13 @@ public interface PrefsChoiceValue extends Translatable { } } - @SuppressWarnings("unchecked") static List getSupported(Class type) { - try { - return (List) type.getDeclaredField("SUPPORTED").get(null); - } catch (IllegalAccessException | NoSuchFieldException e) { - var all = getAll(type); - if (all == null) { - throw new AssertionError(); - } - - return all.stream() - .filter(t -> ((PrefsChoiceValue) t).isSelectable()) - .toList(); + var all = getAll(type); + if (all == null) { + throw new AssertionError(); } + + return all.stream().filter(t -> ((PrefsChoiceValue) t).isSelectable()).toList(); } default boolean isAvailable() { diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java index 14039c655..d1b8433f1 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java @@ -34,15 +34,5 @@ public abstract class PrefsProvider { .map(ServiceLoader.Provider::get) .collect(Collectors.toList()); } - - @Override - public boolean requiresFullDaemon() { - return true; - } - - @Override - public boolean prioritizeLoading() { - return false; - } } } diff --git a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java index 3da157de0..671b8cc8c 100644 --- a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java @@ -62,15 +62,5 @@ public abstract class ScanProvider { scanProvider -> scanProvider.getClass().getName())) .collect(Collectors.toList()); } - - @Override - public boolean requiresFullDaemon() { - return true; - } - - @Override - public boolean prioritizeLoading() { - return false; - } } } diff --git a/app/src/main/java/io/xpipe/app/ext/XPipeServiceProviders.java b/app/src/main/java/io/xpipe/app/ext/XPipeServiceProviders.java deleted file mode 100644 index 298b7e11e..000000000 --- a/app/src/main/java/io/xpipe/app/ext/XPipeServiceProviders.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.xpipe.app.ext; - -import com.fasterxml.jackson.databind.jsontype.NamedType; -import io.xpipe.app.issue.ErrorEvent; -import io.xpipe.app.issue.TrackEvent; -import io.xpipe.core.process.ProcessControlProvider; -import io.xpipe.core.util.JacksonMapper; -import io.xpipe.core.util.ModuleLayerLoader; - -public class XPipeServiceProviders { - - public static void load(ModuleLayer layer) { - var hasDaemon = true; - ModuleLayerLoader.loadAll(layer, hasDaemon, true, t -> { - ErrorEvent.fromThrowable(t).handle(); - }); - ProcessControlProvider.init(layer); - - TrackEvent.info("Loading extension providers ..."); - DataStoreProviders.init(layer); - for (DataStoreProvider p : DataStoreProviders.getAll()) { - TrackEvent.trace("Loaded data store provider " + p.getId()); - JacksonMapper.configure(objectMapper -> { - for (Class storeClass : p.getStoreClasses()) { - objectMapper.registerSubtypes(new NamedType(storeClass)); - } - }); - } - - ModuleLayerLoader.loadAll(layer, hasDaemon, false, t -> { - ErrorEvent.fromThrowable(t).handle(); - }); - - TrackEvent.info("Finished loading extension providers"); - } -} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/Comp.java b/app/src/main/java/io/xpipe/app/fxcomps/Comp.java index 1b8d6483c..dce02a41a 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/Comp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/Comp.java @@ -4,9 +4,9 @@ import atlantafx.base.controls.Spacer; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.augment.Augment; import io.xpipe.app.fxcomps.augment.GrowAugment; -import io.xpipe.app.fxcomps.impl.FancyTooltipAugment; +import io.xpipe.app.fxcomps.impl.TooltipAugment; +import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.Shortcuts; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.application.Platform; import javafx.beans.value.ObservableValue; import javafx.geometry.Insets; @@ -144,7 +144,8 @@ public abstract class Comp> { public Comp hide(ObservableValue o) { return apply(struc -> { var region = struc.get(); - SimpleChangeListener.apply(o, n -> { + BindingsHelper.preserve(region, o); + o.subscribe(n -> { if (!n) { region.setVisible(true); region.setManaged(true); @@ -189,11 +190,11 @@ public abstract class Comp> { } public Comp tooltip(ObservableValue text) { - return apply(new FancyTooltipAugment<>(text)); + return apply(new TooltipAugment<>(text)); } public Comp tooltipKey(String key) { - return apply(new FancyTooltipAugment<>(key)); + return apply(new TooltipAugment<>(key)); } public Region createRegion() { @@ -202,6 +203,8 @@ public abstract class Comp> { public S createStructure() { S struc = createBase(); + // Make comp last at least as long as region + BindingsHelper.preserve(struc.get(), this); if (augments != null) { for (var a : augments) { a.augment(struc); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java index 8198cd69a..66993e53f 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java @@ -18,7 +18,10 @@ public class ContextMenuAugment> implements Augment keyEventCheck; private final Supplier contextMenu; - public ContextMenuAugment(Predicate mouseEventCheck, Predicate keyEventCheck, Supplier contextMenu) { + public ContextMenuAugment( + Predicate mouseEventCheck, + Predicate keyEventCheck, + Supplier contextMenu) { this.mouseEventCheck = mouseEventCheck; this.keyEventCheck = keyEventCheck; this.contextMenu = contextMenu; diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoiceComp.java index 779c5732f..2a56182ce 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoiceComp.java @@ -4,9 +4,8 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.util.Translatable; import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; @@ -72,19 +71,19 @@ public class ChoiceComp extends Comp>> { throw new UnsupportedOperationException(); } }); - SimpleChangeListener.apply(range, c -> { + range.subscribe(c -> { var list = FXCollections.observableArrayList(c.keySet()); if (!list.contains(null) && includeNone) { list.add(null); } - BindingsHelper.setContent(cb.getItems(), list); + ListBindingsHelper.setContent(cb.getItems(), list); }); cb.valueProperty().addListener((observable, oldValue, newValue) -> { value.setValue(newValue); }); - SimpleChangeListener.apply(value, val -> { + value.subscribe(val -> { PlatformThread.runLaterIfNeeded(() -> cb.valueProperty().set(val)); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoicePaneComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoicePaneComp.java index 2bc5f1d51..48ad40924 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoicePaneComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ChoicePaneComp.java @@ -4,7 +4,6 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; @@ -58,7 +57,7 @@ public class ChoicePaneComp extends Comp> { var vbox = new VBox(transformer.apply(cb)); vbox.setFillWidth(true); cb.prefWidthProperty().bind(vbox.widthProperty()); - SimpleChangeListener.apply(cb.valueProperty(), n -> { + cb.valueProperty().subscribe(n -> { if (n == null) { if (vbox.getChildren().size() > 1) { vbox.getChildren().remove(1); @@ -82,7 +81,7 @@ public class ChoicePaneComp extends Comp> { cb.valueProperty().addListener((observable, oldValue, newValue) -> { selected.setValue(newValue); }); - SimpleChangeListener.apply(selected, val -> { + selected.subscribe(val -> { PlatformThread.runLaterIfNeeded(() -> cb.valueProperty().set(val)); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java index 8652a6660..1921ea75b 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java @@ -1,13 +1,14 @@ package io.xpipe.app.fxcomps.impl; import atlantafx.base.theme.Styles; -import io.xpipe.app.browser.StandaloneFileBrowser; +import io.xpipe.app.browser.session.BrowserChooserComp; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.AppWindowHelper; -import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.CompStructure; +import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.ContextualFileReference; @@ -23,7 +24,6 @@ import javafx.beans.value.ObservableValue; import javafx.scene.control.Alert; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; import org.kordamp.ikonli.javafx.FontIcon; import java.nio.file.Files; @@ -31,7 +31,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.List; -public class ContextualFileReferenceChoiceComp extends SimpleComp { +public class ContextualFileReferenceChoiceComp extends Comp> { private final Property> fileSystem; private final Property filePath; @@ -39,34 +39,37 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { public ContextualFileReferenceChoiceComp( ObservableValue> fileSystem, Property filePath) { this.fileSystem = new SimpleObjectProperty<>(); - SimpleChangeListener.apply(fileSystem, val -> { + fileSystem.subscribe(val -> { this.fileSystem.setValue(val); }); this.filePath = filePath; } @Override - protected Region createSimple() { + public CompStructure createBase() { var fileNameComp = new TextFieldComp(filePath) .apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS)) .styleClass(Styles.LEFT_PILL) .grow(false, true); var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> { - StandaloneFileBrowser.openSingleFile(() -> fileSystem.getValue(), fileStore -> { - if (fileStore == null) { - filePath.setValue(null); - fileSystem.setValue(null); - } else { - filePath.setValue(fileStore.getPath()); - fileSystem.setValue(fileStore.getFileSystem()); - } - }); + BrowserChooserComp.openSingleFile( + () -> fileSystem.getValue(), + fileStore -> { + if (fileStore == null) { + filePath.setValue(null); + fileSystem.setValue(null); + } else { + filePath.setValue(fileStore.getPath()); + fileSystem.setValue(fileStore.getFileSystem()); + } + }, + false); }) .styleClass(Styles.CENTER_PILL) .grow(false, true); - var canGitShare = BindingsHelper.persist(Bindings.createBooleanBinding( + var canGitShare = Bindings.createBooleanBinding( () -> { if (!AppPrefs.get().enableGitStorage().get() || filePath.getValue() == null @@ -77,8 +80,19 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { return true; }, filePath, - AppPrefs.get().enableGitStorage())); + AppPrefs.get().enableGitStorage()); var gitShareButton = new ButtonComp(null, new FontIcon("mdi2g-git"), () -> { + if (!AppPrefs.get().enableGitStorage().get()) { + AppLayoutModel.get().selectSettings(); + AppPrefs.get().selectCategory(3); + return; + } + + if (filePath.getValue() == null + || ContextualFileReference.of(filePath.getValue()).isInDataDirectory()) { + return; + } + if (filePath.getValue() == null || filePath.getValue().isBlank() || !canGitShare.get()) { return; } @@ -108,7 +122,7 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { ErrorEvent.fromThrowable(e).handle(); } }); - gitShareButton.apply(new FancyTooltipAugment<>("gitShareFileTooltip")); + gitShareButton.apply(new TooltipAugment<>("gitShareFileTooltip")); gitShareButton.styleClass(Styles.RIGHT_PILL).grow(false, true); var layout = new HorizontalComp(List.of(fileNameComp, fileBrowseButton, gitShareButton)) @@ -120,6 +134,6 @@ public class ContextualFileReferenceChoiceComp extends SimpleComp { }); }); - return layout.createRegion(); + return new SimpleCompStructure<>(layout.createStructure().get()); } } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreFlowChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreFlowChoiceComp.java index 6568a563c..8f98b608d 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreFlowChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreFlowChoiceComp.java @@ -27,11 +27,11 @@ public class DataStoreFlowChoiceComp extends SimpleComp { map.put(DataFlow.INPUT_OUTPUT, AppI18n.observable("app.inout")); return new ToggleGroupComp<>(selected, new SimpleObjectProperty<>(map)) .apply(struc -> { - new FancyTooltipAugment<>("app.inputDescription") + new TooltipAugment<>("app.inputDescription") .augment(struc.get().getChildren().get(0)); - new FancyTooltipAugment<>("app.outputDescription") + new TooltipAugment<>("app.outputDescription") .augment(struc.get().getChildren().get(1)); - new FancyTooltipAugment<>("app.inoutDescription") + new TooltipAugment<>("app.inoutDescription") .augment(struc.get().getChildren().get(2)); }) .createRegion(); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/FancyTooltipAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/FancyTooltipAugment.java deleted file mode 100644 index 7af8b6d0d..000000000 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/FancyTooltipAugment.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.xpipe.app.fxcomps.impl; - -import io.xpipe.app.core.AppI18n; -import io.xpipe.app.fxcomps.CompStructure; -import io.xpipe.app.fxcomps.augment.Augment; -import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.Shortcuts; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.Tooltip; - -public class FancyTooltipAugment> implements Augment { - - private final ObservableValue text; - - public FancyTooltipAugment(ObservableValue text) { - this.text = PlatformThread.sync(text); - } - - public FancyTooltipAugment(String key) { - this.text = AppI18n.observable(key); - } - - @Override - public void augment(S struc) { - var region = struc.get(); - var tt = new Tooltip(); - var toDisplay = text.getValue(); - if (Shortcuts.getDisplayShortcut(region) != null) { - toDisplay = toDisplay + "\n\nShortcut: " + Shortcuts.getDisplayShortcut(region).getDisplayText(); - } - tt.textProperty().setValue(toDisplay); - tt.setStyle("-fx-font-size: 11pt;"); - tt.setWrapText(true); - tt.setMaxWidth(400); - tt.getStyleClass().add("fancy-tooltip"); - - Tooltip.install(struc.get(), tt); - } -} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/FilterComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/FilterComp.java index 205708977..f148fc6b9 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/FilterComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/FilterComp.java @@ -1,10 +1,10 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.core.AppActionLinkDetector; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; import javafx.scene.Node; @@ -28,12 +28,13 @@ public class FilterComp extends Comp { @Override public Structure createBase() { var fi = new FontIcon("mdi2m-magnify"); - var bgLabel = new Label("Search", fi); + var bgLabel = new Label(null, fi); + bgLabel.textProperty().bind(AppI18n.observable("searchFilter")); bgLabel.getStyleClass().add("filter-background"); var filter = new TextField(); filter.setAccessibleText("Filter"); - SimpleChangeListener.apply(filterText, val -> { + filterText.subscribe(val -> { PlatformThread.runLaterIfNeeded(() -> { if (!Objects.equals(filter.getText(), val)) { filter.setText(val); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettyImageComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettyImageComp.java index 83433c5f2..cb4794b69 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettyImageComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettyImageComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.core.AppImages; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.store.FileNames; @@ -106,7 +105,7 @@ public class PrettyImageComp extends SimpleComp { } }; - SimpleChangeListener.apply(PlatformThread.sync(value), val -> update.accept(val)); + PlatformThread.sync(value).subscribe(val -> update.accept(val)); AppPrefs.get().theme.addListener((observable, oldValue, newValue) -> { update.accept(value.getValue()); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettySvgComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettySvgComp.java index 2519304c8..461baa10d 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettySvgComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/PrettySvgComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.core.AppImages; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.store.FileNames; import javafx.beans.binding.Bindings; @@ -92,7 +91,7 @@ public class PrettySvgComp extends SimpleComp { image.set(fixed); }; - SimpleChangeListener.apply(syncValue, val -> update.accept(val)); + syncValue.subscribe(val -> update.accept(val)); AppPrefs.get().theme.addListener((observable, oldValue, newValue) -> { update.accept(syncValue.getValue()); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java index c4eaf095a..41c777c71 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java @@ -11,8 +11,7 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; -import io.xpipe.app.fxcomps.util.BindingsHelper; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.util.ContextMenuHelper; @@ -72,12 +71,13 @@ public class StoreCategoryComp extends SimpleComp { var showing = new SimpleBooleanProperty(); var settings = new IconButtonComp("mdomz-settings") .styleClass("settings") - .apply(new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> { - var cm = createContextMenu(name); - showing.bind(cm.showingProperty()); - return cm; - })); - var shownList = BindingsHelper.filteredContentBinding( + .apply(new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> { + var cm = createContextMenu(name); + showing.bind(cm.showingProperty()); + return cm; + })); + var shownList = ListBindingsHelper.filteredContentBinding( category.getContainedEntries(), storeEntryWrapper -> { return storeEntryWrapper.shouldShow( @@ -92,9 +92,8 @@ public class StoreCategoryComp extends SimpleComp { Comp.hspacer(4), Comp.of(() -> name), Comp.hspacer(), - count.hide(BindingsHelper.persist(hover.or(showing).or(focus))), - settings.hide( - BindingsHelper.persist(hover.not().and(showing.not()).and(focus.not()))))); + count.hide(hover.or(showing).or(focus)), + settings.hide(hover.not().and(showing.not()).and(focus.not())))); h.padding(new Insets(0, 10, 0, (category.getDepth() * 10))); var categoryButton = new ButtonComp(null, h.createRegion(), category::select) @@ -104,18 +103,20 @@ public class StoreCategoryComp extends SimpleComp { .accessibleText(category.nameProperty()) .grow(true, false); categoryButton.apply(new ContextMenuAugment<>( - mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, keyEvent -> keyEvent.getCode() == KeyCode.SPACE, () -> createContextMenu(name))); + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + keyEvent -> keyEvent.getCode() == KeyCode.SPACE, + () -> createContextMenu(name))); var l = category.getChildren() - .sorted(Comparator.comparing( - storeCategoryWrapper -> storeCategoryWrapper.getName().toLowerCase(Locale.ROOT))); + .sorted(Comparator.comparing(storeCategoryWrapper -> + storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT))); var children = new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper)); var emptyBinding = Bindings.isEmpty(category.getChildren()); var v = new VerticalComp(List.of(categoryButton, children.hide(emptyBinding))); v.styleClass("category"); v.apply(struc -> { - SimpleChangeListener.apply(StoreViewState.get().getActiveCategory(), val -> { + StoreViewState.get().getActiveCategory().subscribe(val -> { struc.get().pseudoClassStateChanged(SELECTED, val.equals(category)); }); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java new file mode 100644 index 000000000..166d47090 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java @@ -0,0 +1,62 @@ +package io.xpipe.app.fxcomps.impl; + +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.StringSource; +import io.xpipe.core.store.ShellStore; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; + +public class StringSourceComp extends SimpleComp { + + private final Property> fileSystem; + private final Property stringSource; + + public StringSourceComp( + ObservableValue> fileSystem, Property stringSource) { + this.stringSource = stringSource; + this.fileSystem = new SimpleObjectProperty<>(); + fileSystem.subscribe(val -> { + this.fileSystem.setValue(val.get().ref()); + }); + } + + @Override + protected Region createSimple() { + var inPlace = + new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null); + var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null; + var file = new SimpleObjectProperty<>( + stringSource.getValue() instanceof StringSource.File f + ? f.getFile().serialize() + : null); + var showText = new SimpleBooleanProperty(inPlace.get() != null); + + var stringField = new TextAreaComp(inPlace); + stringField.hide(showText.not()); + var fileComp = new ContextualFileReferenceChoiceComp(fileSystem, file); + fileComp.hide(showText); + + var tr = stringField.createRegion(); + var button = new IconButtonComp("mdi2c-checkbox-marked-outline", () -> { + showText.set(!showText.getValue()); + }) + .createRegion(); + AnchorPane.setBottomAnchor(button, 10.0); + AnchorPane.setRightAnchor(button, 10.0); + var anchorPane = new AnchorPane(tr, button); + AnchorPane.setBottomAnchor(tr, 0.0); + AnchorPane.setTopAnchor(tr, 0.0); + AnchorPane.setLeftAnchor(tr, 0.0); + AnchorPane.setRightAnchor(tr, 0.0); + + var fr = fileComp.createRegion(); + + return new StackPane(tr, fr); + } +} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java index f5960527d..10847b188 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java @@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.core.AppProperties; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.value.ObservableValue; @@ -37,7 +36,7 @@ public class SvgView { public static SvgView create(ObservableValue content) { var widthProperty = new SimpleIntegerProperty(); var heightProperty = new SimpleIntegerProperty(); - SimpleChangeListener.apply(content, val -> { + content.subscribe(val -> { if (val == null || val.isBlank()) { return; } @@ -69,7 +68,7 @@ public class SvgView { wv.setDisable(true); wv.getEngine().loadContent(svgContent.getValue() != null ? getHtml(svgContent.getValue()) : null); - SimpleChangeListener.apply(svgContent, n -> { + svgContent.subscribe(n -> { if (n == null) { wv.setOpacity(0.0); return; diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/TextAreaComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/TextAreaComp.java index 9f0ffe0c1..f31825dae 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/TextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/TextAreaComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; @@ -28,7 +27,7 @@ public class TextAreaComp extends Comp { this.lastAppliedValue = value; this.currentValue = new SimpleStringProperty(value.getValue()); this.lazy = lazy; - SimpleChangeListener.apply(value, val -> { + value.subscribe(val -> { this.currentValue.setValue(val); }); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/TextFieldComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/TextFieldComp.java index 4ce92c33c..eea8bf4ca 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/TextFieldComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/TextFieldComp.java @@ -4,7 +4,6 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; import javafx.scene.control.TextField; @@ -27,10 +26,13 @@ public class TextFieldComp extends Comp> { this.currentValue = new SimpleStringProperty(value.getValue()); this.lazy = lazy; if (!lazy) { - SimpleChangeListener.apply(currentValue, val -> { + currentValue.subscribe(val -> { value.setValue(val); }); } + lastAppliedValue.addListener((c, o, n) -> { + currentValue.setValue(n); + }); } @Override @@ -40,7 +42,6 @@ public class TextFieldComp extends Comp> { currentValue.setValue(n != null && n.length() > 0 ? n : null); }); lastAppliedValue.addListener((c, o, n) -> { - currentValue.setValue(n); PlatformThread.runLaterIfNeeded(() -> { // Check if control value is the same. Then don't set it as that might cause bugs if (Objects.equals(text.getText(), n) diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java index 55cd6f56f..9f590e33c 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java @@ -5,7 +5,6 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; import javafx.scene.control.ToggleButton; @@ -29,7 +28,7 @@ public class ToggleGroupComp extends Comp> { var box = new HBox(); box.getStyleClass().add("toggle-group-comp"); ToggleGroup group = new ToggleGroup(); - SimpleChangeListener.apply(PlatformThread.sync(range), val -> { + PlatformThread.sync(range).subscribe(val -> { if (!val.containsKey(value.getValue())) { this.value.setValue(null); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java new file mode 100644 index 000000000..2c681be7f --- /dev/null +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java @@ -0,0 +1,62 @@ +package io.xpipe.app.fxcomps.impl; + +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.fxcomps.CompStructure; +import io.xpipe.app.fxcomps.augment.Augment; +import io.xpipe.app.fxcomps.util.PlatformThread; +import io.xpipe.app.fxcomps.util.Shortcuts; +import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableValue; +import javafx.scene.control.Tooltip; +import javafx.stage.Window; + +public class TooltipAugment> implements Augment { + + private final ObservableValue text; + + public TooltipAugment(ObservableValue text) { + this.text = PlatformThread.sync(text); + } + + public TooltipAugment(String key) { + this.text = AppI18n.observable(key); + } + + @Override + public void augment(S struc) { + var region = struc.get(); + var tt = new FixedTooltip(); + if (Shortcuts.getDisplayShortcut(region) != null) { + var s = AppI18n.observable("shortcut"); + var binding = Bindings.createStringBinding( + () -> { + return text.getValue() + "\n\n" + s.getValue() + ": " + + Shortcuts.getDisplayShortcut(region).getDisplayText(); + }, + text, + s); + tt.textProperty().bind(binding); + } else { + tt.textProperty().bind(text); + } + tt.setStyle("-fx-font-size: 11pt;"); + tt.setWrapText(true); + tt.setMaxWidth(400); + tt.getStyleClass().add("fancy-tooltip"); + + Tooltip.install(struc.get(), tt); + } + + private static class FixedTooltip extends Tooltip { + + public FixedTooltip() { + super(); + } + + @Override + protected void show() { + Window owner = getOwnerWindow(); + if (owner.isFocused()) super.show(); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java b/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java index b557a61d4..169f4ee65 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/BindingsHelper.java @@ -1,98 +1,50 @@ package io.xpipe.app.fxcomps.util; import io.xpipe.app.util.ThreadHelper; -import javafx.beans.Observable; -import javafx.beans.binding.Binding; import javafx.beans.binding.Bindings; -import javafx.beans.binding.ListBinding; -import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; import lombok.Value; import java.lang.ref.WeakReference; -import java.util.*; +import java.util.Collections; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.function.Predicate; @SuppressWarnings("InfiniteLoopStatement") public class BindingsHelper { private static final Set REFERENCES = Collections.newSetFromMap(new ConcurrentHashMap<>()); - /* - TODO: Proper cleanup. Maybe with a separate thread? - */ - private static final Map, Set> BINDINGS = new ConcurrentHashMap<>(); static { ThreadHelper.createPlatformThread("referenceGC", true, () -> { while (true) { for (ReferenceEntry reference : REFERENCES) { if (reference.canGc()) { - /* - TODO: Figure out why some bindings are garbage collected, even if they shouldn't - */ - // REFERENCES.remove(reference); + REFERENCES.remove(reference); } } ThreadHelper.sleep(1000); + + // Use for testing + // System.gc(); } }) .start(); } - public static void bindExclusive( - Property selected, Map> map, Property toBind) { - selected.addListener((c, o, n) -> { - toBind.unbind(); - toBind.bind(map.get(n)); - }); - - toBind.bind(map.get(selected.getValue())); - } - - public static void linkPersistently(Object source, Object target) { + public static void preserve(Object source, Object target) { REFERENCES.add(new ReferenceEntry(new WeakReference<>(source), target)); } - public static > T persist(T binding) { - var dependencies = new HashSet(); - while (dependencies.addAll(binding.getDependencies().stream() - .map(o -> (javafx.beans.Observable) o) - .toList())) {} - dependencies.add(binding); - BINDINGS.put(new WeakReference<>(binding), dependencies); - return binding; - } - - public static > T persist(T binding) { - var dependencies = new HashSet(); - while (dependencies.addAll(binding.getDependencies().stream() - .map(o -> (javafx.beans.Observable) o) - .toList())) {} - dependencies.add(binding); - BINDINGS.put(new WeakReference<>(binding), dependencies); - return binding; - } - - public static void bindContent(ObservableList l1, ObservableList l2) { - setContent(l1, l2); - l2.addListener((ListChangeListener) c -> { - setContent(l1, l2); - }); - } - public static ObservableValue map( ObservableValue observableValue, Function mapper) { - return persist(Bindings.createObjectBinding( + return Bindings.createObjectBinding( () -> { return mapper.apply(observableValue.getValue()); }, - observableValue)); + observableValue); } public static ObservableValue flatMap( @@ -105,229 +57,10 @@ public class BindingsHelper { observableValue.addListener((observable, oldValue, newValue) -> { runnable.run(); }); - linkPersistently(observableValue, prop); + preserve(prop, observableValue); return prop; } - public static ObservableValue anyMatch(List> l) { - return BindingsHelper.persist(Bindings.createBooleanBinding( - () -> { - return l.stream().anyMatch(booleanObservableValue -> booleanObservableValue.getValue()); - }, - l.toArray(ObservableValue[]::new))); - } - - public static void bindMappedContent(ObservableList l1, ObservableList l2, Function map) { - Runnable runnable = () -> { - setContent(l1, l2.stream().map(map).toList()); - }; - runnable.run(); - l2.addListener((ListChangeListener) c -> { - runnable.run(); - }); - } - - public static ObservableList mappedContentBinding(ObservableList l2, Function map) { - ObservableList l1 = FXCollections.observableList(new ArrayList<>()); - Runnable runnable = () -> { - setContent(l1, l2.stream().map(map).toList()); - }; - runnable.run(); - l2.addListener((ListChangeListener) c -> { - runnable.run(); - }); - linkPersistently(l2, l1); - return l1; - } - - public static ObservableList cachedMappedContentBinding(ObservableList l2, Function map) { - var cache = new HashMap(); - - ObservableList l1 = FXCollections.observableList(new ArrayList<>()); - Runnable runnable = () -> { - cache.keySet().removeIf(t -> !l2.contains(t)); - setContent( - l1, - l2.stream() - .map(v -> { - if (!cache.containsKey(v)) { - cache.put(v, map.apply(v)); - } - - return cache.get(v); - }) - .toList()); - }; - runnable.run(); - l2.addListener((ListChangeListener) c -> { - runnable.run(); - }); - linkPersistently(l2, l1); - return l1; - } - - public static ObservableList cachedMappedContentBinding( - ObservableList all, ObservableList shown, Function map) { - var cache = new HashMap(); - - ObservableList l1 = FXCollections.observableList(new ArrayList<>()); - Runnable runnable = () -> { - cache.keySet().removeIf(t -> !all.contains(t)); - setContent( - l1, - shown.stream() - .map(v -> { - if (!cache.containsKey(v)) { - cache.put(v, map.apply(v)); - } - - return cache.get(v); - }) - .toList()); - }; - runnable.run(); - shown.addListener((ListChangeListener) c -> { - runnable.run(); - }); - linkPersistently(all, l1); - linkPersistently(shown, l1); - return l1; - } - - public static ObservableValue mappedBinding( - ObservableValue observableValue, Function> mapper) { - var binding = (Binding) observableValue.flatMap(mapper); - return persist(binding); - } - - public static ObservableList orderedContentBinding( - ObservableList l2, Comparator comp, Observable... observables) { - return orderedContentBinding( - l2, - Bindings.createObjectBinding( - () -> { - return new Comparator<>() { - @Override - public int compare(V o1, V o2) { - return comp.compare(o1, o2); - } - }; - }, - observables)); - } - - // public static ObservableValue mappedBinding(ObservableValue observableValue, Function> mapper) { - // var v = new SimpleObjectProperty(); - // SimpleChangeListener.apply(observableValue, val -> { - // v.unbind(); - // v.bind(mapper.apply(val)); - // }); - // return v; - // } - - public static ObservableList orderedContentBinding( - ObservableList l2, ObservableValue> comp) { - ObservableList l1 = FXCollections.observableList(new ArrayList<>()); - Runnable runnable = () -> { - setContent(l1, l2.stream().sorted(comp.getValue()).toList()); - }; - runnable.run(); - l2.addListener((ListChangeListener) c -> { - runnable.run(); - }); - comp.addListener((observable, oldValue, newValue) -> { - runnable.run(); - }); - linkPersistently(l2, l1); - return l1; - } - - public static ObservableList filteredContentBinding(ObservableList l2, Predicate predicate) { - return filteredContentBinding(l2, new SimpleObjectProperty<>(predicate)); - } - - public static ObservableList filteredContentBinding( - ObservableList l2, Predicate predicate, Observable... observables) { - return filteredContentBinding( - l2, - Bindings.createObjectBinding( - () -> { - return new Predicate<>() { - @Override - public boolean test(V v) { - return predicate.test(v); - } - }; - }, - Arrays.stream(observables).filter(Objects::nonNull).toArray(Observable[]::new))); - } - - public static ObservableList filteredContentBinding( - ObservableList l2, ObservableValue> predicate) { - ObservableList l1 = FXCollections.observableList(new ArrayList<>()); - Runnable runnable = () -> { - setContent( - l1, - predicate.getValue() != null - ? l2.stream().filter(predicate.getValue()).toList() - : l2); - }; - runnable.run(); - l2.addListener((ListChangeListener) c -> { - runnable.run(); - }); - predicate.addListener((c, o, n) -> { - runnable.run(); - }); - linkPersistently(l2, l1); - return l1; - } - - public static void setContent(ObservableList target, List newList) { - if (target.equals(newList)) { - return; - } - - if (target.size() == 0) { - target.setAll(newList); - return; - } - - if (newList.size() == 0) { - target.clear(); - return; - } - - var targetSet = new HashSet<>(target); - var newSet = new HashSet<>(newList); - - // Only add missing element - if (target.size() + 1 == newList.size() && newSet.containsAll(targetSet)) { - var l = new HashSet<>(newSet); - l.removeAll(targetSet); - if (l.size() > 0) { - var found = l.iterator().next(); - var index = newList.indexOf(found); - target.add(index, found); - return; - } - } - - // Only remove not needed element - if (target.size() - 1 == newList.size() && targetSet.containsAll(newSet)) { - var l = new HashSet<>(targetSet); - l.removeAll(newSet); - if (l.size() > 0) { - target.remove(l.iterator().next()); - return; - } - } - - // Other cases are more difficult - target.setAll(newList); - } - @Value private static class ReferenceEntry { diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/ListBindingsHelper.java b/app/src/main/java/io/xpipe/app/fxcomps/util/ListBindingsHelper.java new file mode 100644 index 000000000..9d0e95d94 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/ListBindingsHelper.java @@ -0,0 +1,190 @@ +package io.xpipe.app.fxcomps.util; + +import javafx.beans.Observable; +import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; + +public class ListBindingsHelper { + + public static void bindContent(ObservableList l1, ObservableList l2) { + setContent(l1, l2); + l2.addListener((ListChangeListener) c -> { + setContent(l1, l2); + }); + } + + public static ObservableValue anyMatch(List> l) { + return Bindings.createBooleanBinding( + () -> { + return l.stream().anyMatch(booleanObservableValue -> booleanObservableValue.getValue()); + }, + l.toArray(ObservableValue[]::new)); + } + + public static ObservableList mappedContentBinding(ObservableList l2, Function map) { + ObservableList l1 = FXCollections.observableList(new ArrayList<>()); + Runnable runnable = () -> { + setContent(l1, l2.stream().map(map).toList()); + }; + runnable.run(); + l2.addListener((ListChangeListener) c -> { + runnable.run(); + }); + BindingsHelper.preserve(l1, l2); + return l1; + } + + public static ObservableList cachedMappedContentBinding( + ObservableList all, ObservableList shown, Function map) { + var cache = new HashMap(); + + ObservableList l1 = FXCollections.observableList(new ArrayList<>()); + Runnable runnable = () -> { + cache.keySet().removeIf(t -> !all.contains(t)); + setContent( + l1, + shown.stream() + .map(v -> { + if (!cache.containsKey(v)) { + cache.put(v, map.apply(v)); + } + + return cache.get(v); + }) + .toList()); + }; + runnable.run(); + shown.addListener((ListChangeListener) c -> { + runnable.run(); + }); + BindingsHelper.preserve(l1, all); + BindingsHelper.preserve(l1, shown); + return l1; + } + + public static ObservableList orderedContentBinding( + ObservableList l2, Comparator comp, Observable... observables) { + return orderedContentBinding( + l2, + Bindings.createObjectBinding( + () -> { + return new Comparator<>() { + @Override + public int compare(V o1, V o2) { + return comp.compare(o1, o2); + } + }; + }, + observables)); + } + + public static ObservableList orderedContentBinding( + ObservableList l2, ObservableValue> comp) { + ObservableList l1 = FXCollections.observableList(new ArrayList<>()); + Runnable runnable = () -> { + setContent(l1, l2.stream().sorted(comp.getValue()).toList()); + }; + runnable.run(); + l2.addListener((ListChangeListener) c -> { + runnable.run(); + }); + comp.addListener((observable, oldValue, newValue) -> { + runnable.run(); + }); + BindingsHelper.preserve(l1, l2); + return l1; + } + + public static ObservableList filteredContentBinding(ObservableList l2, Predicate predicate) { + return filteredContentBinding(l2, new SimpleObjectProperty<>(predicate)); + } + + public static ObservableList filteredContentBinding( + ObservableList l2, Predicate predicate, Observable... observables) { + return filteredContentBinding( + l2, + Bindings.createObjectBinding( + () -> { + return new Predicate<>() { + @Override + public boolean test(V v) { + return predicate.test(v); + } + }; + }, + Arrays.stream(observables).filter(Objects::nonNull).toArray(Observable[]::new))); + } + + public static ObservableList filteredContentBinding( + ObservableList l2, ObservableValue> predicate) { + ObservableList l1 = FXCollections.observableList(new ArrayList<>()); + Runnable runnable = () -> { + setContent( + l1, + predicate.getValue() != null + ? l2.stream().filter(predicate.getValue()).toList() + : l2); + }; + runnable.run(); + l2.addListener((ListChangeListener) c -> { + runnable.run(); + }); + predicate.addListener((c, o, n) -> { + runnable.run(); + }); + BindingsHelper.preserve(l1, l2); + return l1; + } + + public static void setContent(ObservableList target, List newList) { + if (target.equals(newList)) { + return; + } + + if (target.size() == 0) { + target.setAll(newList); + return; + } + + if (newList.size() == 0) { + target.clear(); + return; + } + + var targetSet = new HashSet<>(target); + var newSet = new HashSet<>(newList); + + // Only add missing element + if (target.size() + 1 == newList.size() && newSet.containsAll(targetSet)) { + var l = new HashSet<>(newSet); + l.removeAll(targetSet); + if (l.size() > 0) { + var found = l.iterator().next(); + var index = newList.indexOf(found); + target.add(index, found); + return; + } + } + + // Only remove not needed element + if (target.size() - 1 == newList.size() && targetSet.containsAll(newSet)) { + var l = new HashSet<>(targetSet); + l.removeAll(newSet); + if (l.size() > 0) { + target.remove(l.iterator().next()); + return; + } + } + + // Other cases are more difficult + target.setAll(newList); + } +} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/PlatformThread.java b/app/src/main/java/io/xpipe/app/fxcomps/util/PlatformThread.java index 09c560f2a..43513134e 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/PlatformThread.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/PlatformThread.java @@ -85,7 +85,6 @@ public class PlatformThread { ov.removeListener(invListenerMap.getOrDefault(listener, listener)); } }; - BindingsHelper.linkPersistently(obs, ov); return obs; } @@ -272,7 +271,6 @@ public class PlatformThread { ol.removeListener(invListenerMap.getOrDefault(listener, listener)); } }; - BindingsHelper.linkPersistently(obs, ol); return obs; } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/Shortcuts.java b/app/src/main/java/io/xpipe/app/fxcomps/util/Shortcuts.java index 08a17de86..0863bafe8 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/Shortcuts.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/Shortcuts.java @@ -41,7 +41,7 @@ public class Shortcuts { DISPLAY_SHORTCUTS.put(region, comb); AtomicReference scene = new AtomicReference<>(); - SimpleChangeListener.apply(region.sceneProperty(), s -> { + region.sceneProperty().subscribe(s -> { if (Objects.equals(s, scene.get())) { return; } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/SimpleChangeListener.java b/app/src/main/java/io/xpipe/app/fxcomps/util/SimpleChangeListener.java deleted file mode 100644 index 48720c16a..000000000 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/SimpleChangeListener.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.xpipe.app.fxcomps.util; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; - -@FunctionalInterface -public interface SimpleChangeListener { - - static void apply(ObservableValue obs, SimpleChangeListener cl) { - obs.addListener(cl.wrapped()); - cl.onChange(obs.getValue()); - } - - void onChange(T val); - - default ChangeListener wrapped() { - return (observable, oldValue, newValue) -> this.onChange(newValue); - } -} diff --git a/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java b/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java index 7f0c8cd57..214abf3a0 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java @@ -109,7 +109,7 @@ public class LauncherCommand implements Callable { // starting up or listening on another port if (!AppDataLock.lock()) { throw new IOException( - "Data directory " + AppProperties.get().getDataDir().toString() + " is already locked"); + "Data directory " + AppProperties.get().getDataDir().toString() + " is already locked. Is another instance running?"); } } catch (Exception ex) { var cli = XPipeInstallation.getLocalDefaultCliExecutable(); diff --git a/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java b/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java index 7ac8f0bba..87adc1579 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java @@ -1,6 +1,6 @@ package io.xpipe.app.launcher; -import io.xpipe.app.browser.BrowserModel; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.ext.ActionProvider; @@ -119,7 +119,8 @@ public abstract class LauncherInput { var dir = Files.isDirectory(file) ? file : file.getParent(); AppLayoutModel.get().selectBrowser(); - BrowserModel.DEFAULT.openFileSystemAsync(DataStorage.get().local().ref(), model -> dir.toString(), null); + BrowserSessionModel.DEFAULT.openFileSystemAsync( + DataStorage.get().local().ref(), model -> dir.toString(), null); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java b/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java index 4110c58ef..d4addda96 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java @@ -11,6 +11,7 @@ import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.JfxHelper; import io.xpipe.app.util.OptionsBuilder; +import javafx.beans.property.SimpleStringProperty; import javafx.geometry.Insets; import javafx.scene.control.ScrollPane; import javafx.scene.layout.Region; @@ -101,9 +102,9 @@ public class AboutCategory extends AppPrefsCategory { private Comp createProperties() { var title = Comp.of(() -> { return JfxHelper.createNamedEntry( - AppI18n.get("xPipeClient"), - "Version " + AppProperties.get().getVersion() + " (" - + AppProperties.get().getArch() + ")", + AppI18n.observable("xPipeClient"), + new SimpleStringProperty("Version " + AppProperties.get().getVersion() + " (" + + AppProperties.get().getArch() + ")"), "logo.png"); }) .styleClass(Styles.TEXT_BOLD); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index b16362539..0dedd5a3f 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -49,11 +49,13 @@ public class AppPrefs { map(new SimpleBooleanProperty(true), "saveWindowLocation", Boolean.class); final ObjectProperty terminalType = map(new SimpleObjectProperty<>(), "terminalType", ExternalTerminalType.class); + final ObjectProperty rdpClientType = + map(new SimpleObjectProperty<>(), "rdpClientType", ExternalRdpClientType.class); final DoubleProperty windowOpacity = map(new SimpleDoubleProperty(1.0), "windowOpacity", Double.class); + final StringProperty customRdpClientCommand = + map(new SimpleStringProperty(null), "customRdpClientCommand", String.class); final StringProperty customTerminalCommand = - map(new SimpleStringProperty(""), "customTerminalCommand", String.class); - final BooleanProperty preferTerminalTabs = - map(new SimpleBooleanProperty(true), "preferTerminalTabs", Boolean.class); + map(new SimpleStringProperty(null), "customTerminalCommand", String.class); final BooleanProperty clearTerminalOnInit = map(new SimpleBooleanProperty(true), "clearTerminalOnInit", Boolean.class); public final BooleanProperty disableCertutilUse = @@ -104,8 +106,8 @@ public class AppPrefs { map(new SimpleBooleanProperty(false), "developerDisableGuiRestrictions", Boolean.class); private final ObservableBooleanValue developerDisableGuiRestrictionsEffective = bindDeveloperTrue(developerDisableGuiRestrictions); - private final ObjectProperty language = - map(new SimpleObjectProperty<>(SupportedLocale.ENGLISH), "language", SupportedLocale.class); + final ObjectProperty language = + map(new SimpleObjectProperty<>(SupportedLocale.getEnglish()), "language", SupportedLocale.class); @Getter private final Property lockPassword = new SimpleObjectProperty<>(); @@ -139,8 +141,10 @@ public class AppPrefs { new AppearanceCategory(), new TerminalCategory(), new EditorCategory(), + new RdpCategory(), new SyncCategory(), new VaultCategory(), + new SshCategory(), new LocalShellCategory(), new SecurityCategory(), new PasswordManagerCategory(), @@ -357,10 +361,18 @@ public class AppPrefs { return terminalType; } + public ObservableValue rdpClientType() { + return rdpClientType; + } + public ObservableValue customTerminalCommand() { return customTerminalCommand; } + public ObservableValue customRdpClientCommand() { + return customRdpClientCommand; + } + public ObservableValue storageDirectory() { return storageDirectory; } @@ -411,7 +423,12 @@ public class AppPrefs { if (externalEditor.get() == null) { ExternalEditorType.detectDefault(); } + terminalType.set(ExternalTerminalType.determineDefault(terminalType.get())); + + if (rdpClientType.get() == null) { + rdpClientType.setValue(ExternalRdpClientType.determineDefault()); + } } public Comp getCustomComp(String id) { diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java index 38caefcd3..f5cbc92cc 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.prefs; import io.xpipe.app.core.AppFont; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.ScrollPane; @@ -28,7 +27,7 @@ public class AppPrefsComp extends SimpleComp { .createRegion(); })); var pfxSp = new ScrollPane(); - SimpleChangeListener.apply(AppPrefs.get().getSelectedCategory(), val -> { + AppPrefs.get().getSelectedCategory().subscribe(val -> { PlatformThread.runLaterIfNeeded(() -> { pfxSp.setContent(map.get(val)); }); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java index 43de8d9aa..f8b0ad50e 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java @@ -6,7 +6,6 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.css.PseudoClass; import javafx.geometry.Pos; import javafx.scene.control.Button; @@ -27,7 +26,7 @@ public class AppPrefsSidebarComp extends SimpleComp { .apply(struc -> { struc.get().setTextAlignment(TextAlignment.LEFT); struc.get().setAlignment(Pos.CENTER_LEFT); - SimpleChangeListener.apply(AppPrefs.get().getSelectedCategory(), val -> { + AppPrefs.get().getSelectedCategory().subscribe(val -> { struc.get().pseudoClassStateChanged(SELECTED, appPrefsCategory.equals(val)); }); }) @@ -36,13 +35,15 @@ public class AppPrefsSidebarComp extends SimpleComp { .toList(); var vbox = new VerticalComp(buttons).styleClass("sidebar"); vbox.apply(struc -> { - SimpleChangeListener.apply(PlatformThread.sync(AppPrefs.get().getSelectedCategory()), val -> { - var index = val != null ? AppPrefs.get().getCategories().indexOf(val) : 0; - if (index >= struc.get().getChildren().size()) { - return; - } + AppPrefs.get().getSelectedCategory().subscribe(val -> { + PlatformThread.runLaterIfNeeded(() -> { + var index = val != null ? AppPrefs.get().getCategories().indexOf(val) : 0; + if (index >= struc.get().getChildren().size()) { + return; + } - ((Button) struc.get().getChildren().get(index)).fire(); + ((Button) struc.get().getChildren().get(index)).fire(); + }); }); }); return vbox.createRegion(); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java index 75d7fb000..09eb5645d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java @@ -2,12 +2,20 @@ package io.xpipe.app.prefs; import atlantafx.base.controls.ProgressSliderSkin; import atlantafx.base.theme.Styles; +import io.xpipe.app.comp.base.ButtonComp; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppTheme; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.ChoiceComp; +import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.IntFieldComp; +import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.OptionsBuilder; +import javafx.geometry.Pos; import javafx.scene.control.Slider; +import org.kordamp.ikonli.javafx.FontIcon; + +import java.util.List; public class AppearanceCategory extends AppPrefsCategory { @@ -22,6 +30,8 @@ public class AppearanceCategory extends AppPrefsCategory { return new OptionsBuilder() .addTitle("uiOptions") .sub(new OptionsBuilder() + .nameAndDescription("language") + .addComp(languageChoice(), prefs.language) .nameAndDescription("theme") .addComp( ChoiceComp.ofTranslatable(prefs.theme, AppTheme.Theme.ALL, false) @@ -59,4 +69,16 @@ public class AppearanceCategory extends AppPrefsCategory { .addToggle(prefs.enforceWindowModality)) .buildComp(); } + + private Comp languageChoice() { + var prefs = AppPrefs.get(); + var c = ChoiceComp.ofTranslatable(prefs.language, SupportedLocale.ALL, false); + var visit = new ButtonComp(AppI18n.observable("translate"), new FontIcon("mdi2w-web"), () -> { + Hyperlinks.open(Hyperlinks.TRANSLATE); + }); + return new HorizontalComp(List.of(c, visit)).apply(struc -> { + struc.get().setAlignment(Pos.CENTER_LEFT); + struc.get().setSpacing(10); + }); + } } diff --git a/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java b/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java index 645cc1073..ae8d78a40 100644 --- a/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java +++ b/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java @@ -46,6 +46,7 @@ public class CloseBehaviourAlert { rb.setSelected(true); } vb.getChildren().add(rb); + vb.setMinHeight(150); } alert.getDialogPane().setContent(vb); }) diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java index a0a8f7b55..6c1827b83 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java @@ -106,8 +106,8 @@ public interface ExternalEditorType extends PrefsChoiceValue { var format = customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE"; - ExternalApplicationHelper.startAsync( - CommandBuilder.of().add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString()))); + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString()))); } @Override @@ -199,11 +199,10 @@ public interface ExternalEditorType extends PrefsChoiceValue { throw new IOException("Application " + applicationName + ".app not found"); } - ExternalApplicationHelper.startAsync( - CommandBuilder.of() - .add("open", "-a") - .addFile(execFile.orElseThrow().toString()) - .addFile(file.toString())); + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add("open", "-a") + .addFile(execFile.orElseThrow().toString()) + .addFile(file.toString())); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java new file mode 100644 index 000000000..6969fe99d --- /dev/null +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java @@ -0,0 +1,169 @@ +package io.xpipe.app.prefs; + +import io.xpipe.app.ext.PrefsChoiceValue; +import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.app.util.*; +import io.xpipe.core.process.CommandBuilder; +import io.xpipe.core.process.OsType; +import lombok.Value; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Supplier; + +public interface ExternalRdpClientType extends PrefsChoiceValue { + + ExternalRdpClientType MSTSC = new PathCheckType("app.mstsc", "mstsc.exe", true) { + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + var adaptedRdpConfig = getAdaptedConfig(configuration); + var file = writeConfig(adaptedRdpConfig); + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of().add(executable).addFile(file.toString())); + } + + private RdpConfig getAdaptedConfig(LaunchConfiguration configuration) throws Exception { + var input = configuration.getConfig(); + if (input.get("password 51").isPresent()) { + return input; + } + + var address = input.get("full address") + .map(typedValue -> typedValue.getValue()) + .orElse("?"); + var pass = SecretManager.retrieve( + configuration.getPassword(), "Password for " + address, configuration.getStoreId(), 0); + if (pass == null) { + return input; + } + + var adapted = input.overlay(Map.of( + "password 51", + new RdpConfig.TypedValue("b", encrypt(pass.getSecretValue())), + "prompt for credentials", + new RdpConfig.TypedValue("i", "0"))); + return adapted; + } + + private String encrypt(String password) throws Exception { + var ps = LocalShell.getLocalPowershell(); + var cmd = ps.command( + "(\"" + password + "\" | ConvertTo-SecureString -AsPlainText -Force) | ConvertFrom-SecureString;"); + cmd.setSensitive(); + return cmd.readStdoutOrThrow(); + } + }; + ExternalRdpClientType REMMINA = new PathCheckType("app.remmina", "remmina", true) { + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + var file = writeConfig(configuration.getConfig()); + LocalShell.getShell() + .executeSimpleCommand( + CommandBuilder.of().add(executable).add("-c").addFile(file.toString())); + } + }; + ExternalRdpClientType MICROSOFT_REMOTE_DESKTOP_MACOS_APP = + new MacOsType("app.microsoftRemoteDesktopApp", "Microsoft Remote Desktop.app") { + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + var file = writeConfig(configuration.getConfig()); + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .add("open", "-a") + .addQuoted("Microsoft Remote Desktop.app") + .addFile(file.toString())); + } + }; + ExternalRdpClientType CUSTOM = new CustomType(); + List WINDOWS_CLIENTS = List.of(MSTSC); + List LINUX_CLIENTS = List.of(REMMINA); + List MACOS_CLIENTS = List.of(MICROSOFT_REMOTE_DESKTOP_MACOS_APP); + @SuppressWarnings("TrivialFunctionalExpressionUsage") + List ALL = ((Supplier>) () -> { + var all = new ArrayList(); + if (OsType.getLocal().equals(OsType.WINDOWS)) { + all.addAll(WINDOWS_CLIENTS); + } + if (OsType.getLocal().equals(OsType.LINUX)) { + all.addAll(LINUX_CLIENTS); + } + if (OsType.getLocal().equals(OsType.MACOS)) { + all.addAll(MACOS_CLIENTS); + } + all.add(CUSTOM); + return all; + }) + .get(); + + static ExternalRdpClientType determineDefault() { + return ALL.stream() + .filter(t -> !t.equals(CUSTOM)) + .filter(t -> t.isAvailable()) + .findFirst() + .orElse(null); + } + + void launch(LaunchConfiguration configuration) throws Exception; + + default Path writeConfig(RdpConfig input) throws Exception { + var file = + LocalShell.getShell().getSystemTemporaryDirectory().join("exec-" + ScriptHelper.getScriptId() + ".rdp"); + var string = input.toString(); + Files.writeString(file.toLocalPath(), string); + return file.toLocalPath(); + } + + @Value + class LaunchConfiguration { + String title; + RdpConfig config; + UUID storeId; + SecretRetrievalStrategy password; + } + + abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType { + + public PathCheckType(String id, String executable, boolean explicityAsync) { + super(id, executable, explicityAsync); + } + } + + abstract class MacOsType extends ExternalApplicationType.MacApplication implements ExternalRdpClientType { + + public MacOsType(String id, String applicationName) { + super(id, applicationName); + } + } + + class CustomType extends ExternalApplicationType implements ExternalRdpClientType { + + public CustomType() { + super("app.custom"); + } + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + var customCommand = AppPrefs.get().customRdpClientCommand().getValue(); + if (customCommand == null || customCommand.isBlank()) { + throw ErrorEvent.expected(new IllegalStateException("No custom RDP command specified")); + } + + var format = + customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE"; + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add(ExternalApplicationHelper.replaceFileArgument( + format, + "FILE", + writeConfig(configuration.getConfig()).toString()))); + } + + @Override + public boolean isAvailable() { + return true; + } + } +} diff --git a/app/src/main/java/io/xpipe/app/prefs/LocalShellCategory.java b/app/src/main/java/io/xpipe/app/prefs/LocalShellCategory.java index b51696f61..04186e08a 100644 --- a/app/src/main/java/io/xpipe/app/prefs/LocalShellCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/LocalShellCategory.java @@ -2,8 +2,6 @@ package io.xpipe.app.prefs; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.util.OptionsBuilder; -import io.xpipe.core.process.OsType; -import javafx.beans.property.SimpleBooleanProperty; public class LocalShellCategory extends AppPrefsCategory { @@ -18,9 +16,6 @@ public class LocalShellCategory extends AppPrefsCategory { return new OptionsBuilder() .addTitle("localShell") .sub(new OptionsBuilder() - .nameAndDescription("useBundledTools") - .addToggle(prefs.useBundledTools) - .hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS))) .nameAndDescription("useLocalFallbackShell") .addToggle(prefs.useLocalFallbackShell)) .buildComp(); diff --git a/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java b/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java new file mode 100644 index 000000000..8c3a97483 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java @@ -0,0 +1,31 @@ +package io.xpipe.app.prefs; + +import io.xpipe.app.ext.PrefsChoiceValue; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.fxcomps.impl.ChoiceComp; +import io.xpipe.app.fxcomps.impl.TextFieldComp; +import io.xpipe.app.util.OptionsBuilder; + +public class RdpCategory extends AppPrefsCategory { + + @Override + protected String getId() { + return "rdp"; + } + + @Override + protected Comp create() { + var prefs = AppPrefs.get(); + return new OptionsBuilder() + .addTitle("rdpConfiguration") + .sub(new OptionsBuilder() + .nameAndDescription("rdpClient") + .addComp(ChoiceComp.ofTranslatable( + prefs.rdpClientType, PrefsChoiceValue.getSupported(ExternalRdpClientType.class), false)) + .nameAndDescription("customRdpClientCommand") + .addComp(new TextFieldComp(prefs.customRdpClientCommand, true) + .apply(struc -> struc.get().setPromptText("myrdpclient -c $FILE")) + .hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClientType.CUSTOM)))) + .buildComp(); + } +} diff --git a/app/src/main/java/io/xpipe/app/prefs/SshCategory.java b/app/src/main/java/io/xpipe/app/prefs/SshCategory.java new file mode 100644 index 000000000..cb8750cad --- /dev/null +++ b/app/src/main/java/io/xpipe/app/prefs/SshCategory.java @@ -0,0 +1,28 @@ +package io.xpipe.app.prefs; + +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.util.OptionsBuilder; +import io.xpipe.core.process.OsType; +import javafx.beans.property.SimpleBooleanProperty; + +public class SshCategory extends AppPrefsCategory { + + @Override + protected String getId() { + return "ssh"; + } + + @Override + protected Comp create() { + var prefs = AppPrefs.get(); + return new OptionsBuilder() + .addTitle("sshConfiguration") + .sub(new OptionsBuilder() + .nameAndDescription("useBundledTools") + .addToggle(prefs.useBundledTools) + .hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS))) + .addComp(prefs.getCustomComp("x11WslInstance")) + .hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS)))) + .buildComp(); + } +} diff --git a/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java b/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java index a3a3cde31..5ead1d653 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java +++ b/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java @@ -1,25 +1,39 @@ package io.xpipe.app.prefs; +import io.xpipe.app.core.AppProperties; import io.xpipe.app.ext.PrefsChoiceValue; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.List; import java.util.Locale; @AllArgsConstructor @Getter -public enum SupportedLocale implements PrefsChoiceValue { - ENGLISH(Locale.ENGLISH, "english"); - // GERMAN(Locale.GERMAN, "german"); +public class SupportedLocale implements PrefsChoiceValue { + public static List ALL = AppProperties.get().getLanguages().stream() + .map(s -> { + var split = s.split("-"); + var loc = split.length == 2 ? Locale.of(split[0], split[1]) : Locale.of(s); + return new SupportedLocale(loc, s); + }) + .toList(); private final Locale locale; private final String id; + public static SupportedLocale getEnglish() { + return ALL.stream() + .filter(supportedLocale -> supportedLocale.getId().equals("en")) + .findFirst() + .orElseThrow(); + } + @Override public ObservableValue toTranslatedString() { - return new SimpleStringProperty(locale.getDisplayName()); + return new SimpleStringProperty(locale.getDisplayName(locale)); } @Override diff --git a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java index af2dbde99..5bfe1ec99 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -8,7 +8,6 @@ import io.xpipe.app.fxcomps.impl.ChoiceComp; import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.TextFieldComp; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.terminal.ExternalTerminalType; import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.OptionsBuilder; @@ -31,57 +30,6 @@ public class TerminalCategory extends AppPrefsCategory { return "terminal"; } - private Comp terminalChoice() { - var prefs = AppPrefs.get(); - var c = ChoiceComp.ofTranslatable( - prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false); - c.apply(struc -> { - struc.get().setCellFactory(param -> { - return new ListCell<>() { - @Override - protected void updateItem(ExternalTerminalType item, boolean empty) { - super.updateItem(item, empty); - if (empty) { - return; - } - - setText(item.toTranslatedString().getValue()); - if (item != ExternalTerminalType.CUSTOM) { - var graphic = new FontIcon(item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check"); - graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE); - setGraphic(graphic); - } else { - setGraphic(new FontIcon("mdi2m-minus-circle")); - } - } - }; - }); - }); - - var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> { - var t = prefs.terminalType().getValue(); - if (t == null || t.getWebsite() == null) { - return; - } - - Hyperlinks.open(t.getWebsite()); - }); - var visitVisible = BindingsHelper.persist(Bindings.createBooleanBinding(() -> { - var t = prefs.terminalType().getValue(); - if (t == null || t.getWebsite() == null) { - return false; - } - - return true; - }, prefs.terminalType())); - visit.visible(visitVisible); - - return new HorizontalComp(List.of(c, visit)).apply(struc -> { - struc.get().setAlignment(Pos.CENTER_LEFT); - struc.get().setSpacing(10); - }); - } - @Override protected Comp create() { var prefs = AppPrefs.get(); @@ -108,22 +56,6 @@ public class TerminalCategory extends AppPrefsCategory { .apply(struc -> struc.get().setPromptText("myterminal -e $CMD")) .hide(prefs.terminalType.isNotEqualTo(ExternalTerminalType.CUSTOM))) .addComp(terminalTest) - .name("preferTerminalTabs") - .description(Bindings.createStringBinding( - () -> { - var disabled = prefs.terminalType().getValue() != null - && !prefs.terminalType.get().supportsTabs(); - return !disabled - ? AppI18n.get("preferTerminalTabs") - : AppI18n.get( - "preferTerminalTabsDisabled", - prefs.terminalType() - .getValue() - .toTranslatedString() - .getValue()); - }, - prefs.terminalType())) - .addToggle(prefs.preferTerminalTabs) .disable(Bindings.createBooleanBinding( () -> { return prefs.terminalType().getValue() != null @@ -134,4 +66,58 @@ public class TerminalCategory extends AppPrefsCategory { .addToggle(prefs.clearTerminalOnInit)) .buildComp(); } + + private Comp terminalChoice() { + var prefs = AppPrefs.get(); + var c = ChoiceComp.ofTranslatable( + prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false); + c.apply(struc -> { + struc.get().setCellFactory(param -> { + return new ListCell<>() { + @Override + protected void updateItem(ExternalTerminalType item, boolean empty) { + super.updateItem(item, empty); + if (empty) { + return; + } + + setText(item.toTranslatedString().getValue()); + if (item != ExternalTerminalType.CUSTOM) { + var graphic = new FontIcon( + item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check"); + graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE); + setGraphic(graphic); + } else { + setGraphic(new FontIcon("mdi2m-minus-circle")); + } + } + }; + }); + }); + + var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> { + var t = prefs.terminalType().getValue(); + if (t == null || t.getWebsite() == null) { + return; + } + + Hyperlinks.open(t.getWebsite()); + }); + var visitVisible = Bindings.createBooleanBinding( + () -> { + var t = prefs.terminalType().getValue(); + if (t == null || t.getWebsite() == null) { + return false; + } + + return true; + }, + prefs.terminalType()); + visit.visible(visitVisible); + + return new HorizontalComp(List.of(c, visit)).apply(struc -> { + struc.get().setAlignment(Pos.CENTER_LEFT); + struc.get().setSpacing(10); + }); + } } diff --git a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java index 867c26be6..c8f35968f 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java @@ -45,7 +45,8 @@ public class TroubleshootCategory extends AppPrefsCategory { XPipeInstallation.getCurrentInstallationBasePath() .toString(), XPipeInstallation.getDaemonDebugScriptPath(OsType.getLocal())); - TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect().runScriptCommand(sc, script)); + TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect() + .runScriptCommand(sc, script)); }); e.consume(); }) diff --git a/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java b/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java index 5d6241b20..339a77839 100644 --- a/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java @@ -27,7 +27,7 @@ public class UpdateCheckComp extends SimpleComp { XPipeDistributionType.get().getUpdateHandler().getPreparedUpdate())); } - private void restart() { + private void performUpdateAndRestart() { XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(); UpdateAvailableAlert.showIfNeeded(); } @@ -82,7 +82,7 @@ public class UpdateCheckComp extends SimpleComp { return new TileButtonComp(name, description, graphic, actionEvent -> { actionEvent.consume(); if (updateReady.getValue()) { - restart(); + performUpdateAndRestart(); return; } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index e709f08d6..eb32ae21a 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -111,7 +111,7 @@ public class DataStoreEntry extends StorageElement { this.categoryUuid = categoryUuid; this.store = store; this.storeNode = null; - this.validity = Validity.COMPLETE; + this.validity = Validity.INCOMPLETE; this.configuration = Configuration.defaultConfiguration(); this.expanded = false; this.color = null; diff --git a/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java index a80feebc6..4a3f70993 100644 --- a/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java @@ -5,6 +5,30 @@ import io.xpipe.core.process.CommandBuilder; public interface AlacrittyTerminalType extends ExternalTerminalType { + ExternalTerminalType ALACRITTY_WINDOWS = new Windows(); + ExternalTerminalType ALACRITTY_LINUX = new Linux(); + ExternalTerminalType ALACRITTY_MAC_OS = new MacOs(); + + @Override + default boolean supportsTabs() { + return false; + } + + @Override + default String getWebsite() { + return "https://github.com/alacritty/alacritty"; + } + + @Override + default boolean isRecommended() { + return false; + } + + @Override + default boolean supportsColoredTitle() { + return false; + } + static class Windows extends SimplePathType implements AlacrittyTerminalType { public Windows() { @@ -15,11 +39,11 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { protected CommandBuilder toCommand(LaunchConfiguration configuration) { var b = CommandBuilder.of(); -// if (configuration.getColor() != null) { -// b.add("-o") -// .addQuoted("colors.primary.background='%s'" -// .formatted(configuration.getColor().toHexString())); -// } + // if (configuration.getColor() != null) { + // b.add("-o") + // .addQuoted("colors.primary.background='%s'" + // .formatted(configuration.getColor().toHexString())); + // } // Alacritty is bugged and will not accept arguments with spaces even if they are correctly passed/escaped // So this will not work when the script file has spaces @@ -28,7 +52,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { .add("-e") .add(configuration.getDialectLaunchCommand()); } - } static class Linux extends SimplePathType implements AlacrittyTerminalType { @@ -45,31 +68,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { .add("-e") .addFile(configuration.getScriptFile()); } - - } - - ExternalTerminalType ALACRITTY_WINDOWS = new Windows(); - ExternalTerminalType ALACRITTY_LINUX = new Linux(); - ExternalTerminalType ALACRITTY_MAC_OS = new MacOs(); - - @Override - default String getWebsite() { - return "https://github.com/alacritty/alacritty"; - } - - @Override - default boolean isRecommended() { - return false; - } - - @Override - default boolean supportsTabs() { - return false; - } - - @Override - default boolean supportsColoredTitle() { - return false; } class MacOs extends MacOsType implements AlacrittyTerminalType { diff --git a/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java index 2209e4258..170e443f0 100644 --- a/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java @@ -39,7 +39,8 @@ public class CustomTerminalType extends ExternalApplicationType implements Exter var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD"; try (var pc = LocalShell.getShell()) { - var toExecute = ExternalApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile().toString()); + var toExecute = ExternalApplicationHelper.replaceFileArgument( + format, "CMD", configuration.getScriptFile().toString()); // We can't be sure whether the command is blocking or not, so always make it not blocking if (pc.getOsType().equals(OsType.WINDOWS)) { toExecute = "start \"" + configuration.getCleanTitle() + "\" " + toExecute; diff --git a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java index 02cd76c00..6af87c6fe 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -3,7 +3,8 @@ package io.xpipe.app.terminal; import io.xpipe.app.ext.PrefsChoiceValue; import io.xpipe.app.prefs.ExternalApplicationType; import io.xpipe.app.storage.DataStoreColor; -import io.xpipe.app.util.*; +import io.xpipe.app.util.CommandSupport; +import io.xpipe.app.util.LocalShell; import io.xpipe.core.process.*; import io.xpipe.core.store.FilePath; import lombok.Getter; @@ -13,7 +14,10 @@ import lombok.With; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Comparator; +import java.util.List; import java.util.function.Supplier; public interface ExternalTerminalType extends PrefsChoiceValue { @@ -21,12 +25,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType CMD = new SimplePathType("app.cmd", "cmd.exe", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -48,12 +52,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType POWERSHELL = new SimplePathType("app.powershell", "powershell", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -88,12 +92,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType PWSH = new SimplePathType("app.pwsh", "pwsh", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -118,8 +122,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType GNOME_TERMINAL = new PathCheckType("app.gnomeTerminal", "gnome-terminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -128,8 +132,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -152,12 +156,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType KONSOLE = new SimplePathType("app.konsole", "konsole", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return true; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return true; } @@ -176,18 +180,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType XFCE = new SimplePathType("app.xfce", "xfce4-terminal", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -202,18 +205,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType ELEMENTARY = new SimplePathType("app.elementaryTerminal", "io.elementary.terminal", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -224,19 +226,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -250,18 +251,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TERMINATOR = new SimplePathType("app.terminator", "terminator", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -277,18 +277,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TERMINOLOGY = new SimplePathType("app.terminology", "terminology", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -304,19 +303,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType COOL_RETRO_TERM = new SimplePathType("app.coolRetroTerm", "cool-retro-term", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -330,18 +328,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType GUAKE = new SimplePathType("app.guake", "guake", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -357,18 +354,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TILDA = new SimplePathType("app.tilda", "tilda", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -379,19 +375,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType XTERM = new SimplePathType("app.xterm", "xterm", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -405,19 +400,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType DEEPIN_TERMINAL = new SimplePathType("app.deepinTerminal", "deepin-terminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -427,8 +421,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType Q_TERMINAL = new SimplePathType("app.qTerminal", "qterminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -436,10 +430,9 @@ public interface ExternalTerminalType extends PrefsChoiceValue { return false; } - @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -449,8 +442,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType MACOS_TERMINAL = new MacOsType("app.macosTerminal", "Terminal") { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -459,8 +452,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -480,7 +473,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType ITERM2 = new MacOsType("app.iterm2", "iTerm") { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } @@ -490,7 +483,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -519,7 +512,11 @@ public interface ExternalTerminalType extends PrefsChoiceValue { create window with default profile command "%s" end tell """, - a, a, a, a, configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) + a, + a, + a, + a, + configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) .execute(); } } @@ -527,7 +524,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType WARP = new MacOsType("app.warp", "Warp") { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } @@ -537,7 +534,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -582,8 +579,14 @@ public interface ExternalTerminalType extends PrefsChoiceValue { XTERM, DEEPIN_TERMINAL, Q_TERMINAL); - List MACOS_TERMINALS = - List.of(ITERM2, TabbyTerminalType.TABBY_MAC_OS, AlacrittyTerminalType.ALACRITTY_MAC_OS, KittyTerminalType.KITTY_MACOS, WARP, WezTerminalType.WEZTERM_MAC_OS, MACOS_TERMINAL); + List MACOS_TERMINALS = List.of( + ITERM2, + TabbyTerminalType.TABBY_MAC_OS, + AlacrittyTerminalType.ALACRITTY_MAC_OS, + KittyTerminalType.KITTY_MACOS, + WARP, + WezTerminalType.WEZTERM_MAC_OS, + MACOS_TERMINAL); @SuppressWarnings("TrivialFunctionalExpressionUsage") List ALL = ((Supplier>) () -> { @@ -714,5 +717,4 @@ public interface ExternalTerminalType extends PrefsChoiceValue { protected abstract CommandBuilder toCommand(LaunchConfiguration configuration) throws Exception; } - } diff --git a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java index 08c7d073c..a38d8fce6 100644 --- a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java @@ -11,14 +11,61 @@ import io.xpipe.core.util.XPipeInstallation; public interface KittyTerminalType extends ExternalTerminalType { - @Override - default boolean supportsColoredTitle() { - return true; + public static final ExternalTerminalType KITTY_LINUX = new Linux(); + public static final ExternalTerminalType KITTY_MACOS = new MacOs(); + + private static FilePath getSocket() throws Exception { + try (var sc = LocalShell.getShell().start()) { + var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null); + sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString())); + return temp.join("xpipe_kitty"); + } } - @Override - default boolean isRecommended() { - return true; + private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite) + throws Exception { + try (var sc = LocalShell.getShell().start()) { + var payload = JsonNodeFactory.instance.objectNode(); + var args = configuration.getDialectLaunchCommand().buildBaseParts(sc); + var argsArray = payload.putArray("args"); + args.forEach(argsArray::add); + payload.put("tab_title", configuration.getColoredTitle()); + payload.put("type", "tab"); + payload.put("logo_alpha", 0.01); + payload.put( + "logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString()); + + var json = JsonNodeFactory.instance.objectNode(); + json.put("cmd", "launch"); + json.set("payload", payload); + json.putArray("version").add(0).add(14).add(2); + var jsonString = json.toString(); + var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; + + sc.executeSimpleCommand(CommandBuilder.of() + .add("echo", "-en", echoString, "|") + .add(socketWrite) + .addFile(getSocket())); + } + } + + private static void closeInitial(CommandBuilder socketWrite) throws Exception { + try (var sc = LocalShell.getShell().start()) { + var payload = JsonNodeFactory.instance.objectNode(); + payload.put("match", "not recent:0"); + + var json = JsonNodeFactory.instance.objectNode(); + json.put("cmd", "close-tab"); + json.set("payload", payload); + json.putArray("version").add(0).add(14).add(2); + var jsonString = json.toString(); + var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; + + sc.executeSimpleCommand(CommandBuilder.of() + .add("echo", "-en", echoString, "|") + .add(socketWrite) + .addFile(getSocket())); + } } @Override @@ -31,55 +78,14 @@ public interface KittyTerminalType extends ExternalTerminalType { return "https://github.com/kovidgoyal/kitty"; } - - public static final ExternalTerminalType KITTY_LINUX = new Linux(); - - public static final ExternalTerminalType KITTY_MACOS = new MacOs(); - - private static FilePath getSocket() throws Exception { - try (var sc = LocalShell.getShell().start()) { - var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null); - sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString())); - return temp.join("xpipe_kitty"); - } + @Override + default boolean isRecommended() { + return true; } - private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite) throws Exception { - try (var sc = LocalShell.getShell().start()) { - var payload = JsonNodeFactory.instance.objectNode(); - var args = configuration.getDialectLaunchCommand().buildBaseParts(sc); - var argsArray = payload.putArray("args"); - args.forEach(argsArray::add); - payload.put("tab_title",configuration.getColoredTitle()); - payload.put("type", "tab"); - payload.put("logo_alpha", 0.01); - payload.put("logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString()); - - var json = JsonNodeFactory.instance.objectNode(); - json.put("cmd", "launch"); - json.set("payload", payload); - json.putArray("version").add(0).add(14).add(2); - var jsonString = json.toString(); - var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; - - sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket())); - } - } - - private static void closeInitial( CommandBuilder socketWrite) throws Exception { - try (var sc = LocalShell.getShell().start()) { - var payload = JsonNodeFactory.instance.objectNode(); - payload.put("match", "not recent:0"); - - var json = JsonNodeFactory.instance.objectNode(); - json.put("cmd", "close-tab"); - json.set("payload", payload); - json.putArray("version").add(0).add(14).add(2); - var jsonString = json.toString(); - var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; - - sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket())); - } + @Override + default boolean supportsColoredTitle() { + return true; } class Linux implements KittyTerminalType { @@ -107,11 +113,19 @@ public interface KittyTerminalType extends ExternalTerminalType { private boolean prepare() throws Exception { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { - if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) { + if (sc.executeSimpleBooleanCommand( + "test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } - sc.executeSimpleCommand(CommandBuilder.of().add("kitty").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket(), "--detach")); + sc.executeSimpleCommand(CommandBuilder.of() + .add("kitty") + .add( + "-o", + "allow_remote_control=socket-only", + "--listen-on", + "unix:" + getSocket(), + "--detach")); ThreadHelper.sleep(1500); return true; } @@ -120,7 +134,9 @@ public interface KittyTerminalType extends ExternalTerminalType { class MacOs extends MacOsType implements KittyTerminalType { - public MacOs() {super("app.kitty", "kitty");} + public MacOs() { + super("app.kitty", "kitty"); + } @Override public void launch(LaunchConfiguration configuration) throws Exception { @@ -139,11 +155,14 @@ public interface KittyTerminalType extends ExternalTerminalType { private boolean prepare() throws Exception { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { - if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) { + if (sc.executeSimpleBooleanCommand( + "test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } - sc.executeSimpleCommand(CommandBuilder.of().add("open", "-a", "kitty.app", "--args").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket())); + sc.executeSimpleCommand(CommandBuilder.of() + .add("open", "-a", "kitty.app", "--args") + .add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket())); ThreadHelper.sleep(1000); return true; } diff --git a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java index 0ee04a312..cffade904 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java @@ -10,52 +10,14 @@ import java.util.Optional; public interface TabbyTerminalType extends ExternalTerminalType { - static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType { - - public Windows() { - super("app.tabby", "Tabby.exe"); - } - - - @Override - protected void execute(Path file, LaunchConfiguration configuration) throws Exception { - // Tabby has a very weird handling of output, even detaching with start does not prevent it from printing - if (configuration.getScriptDialect().equals(ShellDialects.CMD)) { - // It also freezes with any other input than .bat files, why? - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of() - .addFile(file.toString()) - .add("run") - .addFile(configuration.getScriptFile()) - .discardOutput()); - } - - // This is probably not going to work as it does not launch a bat file - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of() - .addFile(file.toString()) - .add("run") - .add(configuration.getDialectLaunchCommand()) - .discardOutput()); - } - - @Override - protected Optional determineInstallation() { - var perUser = WindowsRegistry.readString(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", - "InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of); - if (perUser.isPresent()) { - return perUser; - } - - var systemWide = WindowsRegistry.readString(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", - "InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of); - return systemWide; - } - - } - ExternalTerminalType TABBY_WINDOWS = new Windows(); - ExternalTerminalType TABBY_MAC_OS = new MacOs(); + @Override + default boolean supportsTabs() { + return true; + } + @Override default String getWebsite() { return "https://tabby.sh"; @@ -67,13 +29,58 @@ public interface TabbyTerminalType extends ExternalTerminalType { } @Override - default boolean supportsTabs() { + default boolean supportsColoredTitle() { return true; } - @Override - default boolean supportsColoredTitle() { - return true; + static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType { + + public Windows() { + super("app.tabby", "Tabby.exe"); + } + + @Override + protected void execute(Path file, LaunchConfiguration configuration) throws Exception { + // Tabby has a very weird handling of output, even detaching with start does not prevent it from printing + if (configuration.getScriptDialect().equals(ShellDialects.CMD)) { + // It also freezes with any other input than .bat files, why? + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("run") + .addFile(configuration.getScriptFile()) + .discardOutput()); + } + + // This is probably not going to work as it does not launch a bat file + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("run") + .add(configuration.getDialectLaunchCommand()) + .discardOutput()); + } + + @Override + protected Optional determineInstallation() { + var perUser = WindowsRegistry.readString( + WindowsRegistry.HKEY_CURRENT_USER, + "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", + "InstallLocation") + .map(p -> p + "\\Tabby.exe") + .map(Path::of); + if (perUser.isPresent()) { + return perUser; + } + + var systemWide = WindowsRegistry.readString( + WindowsRegistry.HKEY_LOCAL_MACHINE, + "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", + "InstallLocation") + .map(p -> p + "\\Tabby.exe") + .map(Path::of); + return systemWide; + } } class MacOs extends MacOsType implements TabbyTerminalType { diff --git a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java index bbf5451d6..60698c581 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java @@ -10,47 +10,15 @@ import java.util.Optional; public interface WezTerminalType extends ExternalTerminalType { - static class Windows extends WindowsType implements WezTerminalType { - - public Windows() { - super("app.wezterm", "wezterm-gui"); - } - - @Override - protected void execute(Path file, LaunchConfiguration configuration) throws Exception { - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().addFile(file.toString()).add("start").add(configuration.getDialectLaunchCommand())); - } - - @Override - protected Optional determineInstallation() { - Optional launcherDir; - launcherDir = WindowsRegistry.readString( - WindowsRegistry.HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1", - "InstallLocation") - .map(p -> p + "\\wezterm-gui.exe"); - return launcherDir.map(Path::of); - } - - } - - static class Linux extends SimplePathType implements WezTerminalType { - - public Linux() { - super("app.wezterm", "wezterm-gui", true); - } - - @Override - protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of().add("start").addFile(configuration.getScriptFile()); - } - - } - ExternalTerminalType WEZTERM_WINDOWS = new Windows(); ExternalTerminalType WEZTERM_LINUX = new Linux(); ExternalTerminalType WEZTERM_MAC_OS = new MacOs(); + @Override + default boolean supportsTabs() { + return false; + } + @Override default String getWebsite() { return "https://wezfurlong.org/wezterm/index.html"; @@ -61,16 +29,50 @@ public interface WezTerminalType extends ExternalTerminalType { return false; } - @Override - default boolean supportsTabs() { - return false; - } - @Override default boolean supportsColoredTitle() { return true; } + static class Windows extends WindowsType implements WezTerminalType { + + public Windows() { + super("app.wezterm", "wezterm-gui"); + } + + @Override + protected void execute(Path file, LaunchConfiguration configuration) throws Exception { + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("start") + .add(configuration.getDialectLaunchCommand())); + } + + @Override + protected Optional determineInstallation() { + Optional launcherDir; + launcherDir = WindowsRegistry.readString( + WindowsRegistry.HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1", + "InstallLocation") + .map(p -> p + "\\wezterm-gui.exe"); + return launcherDir.map(Path::of); + } + } + + static class Linux extends SimplePathType implements WezTerminalType { + + public Linux() { + super("app.wezterm", "wezterm-gui", true); + } + + @Override + protected CommandBuilder toCommand(LaunchConfiguration configuration) { + return CommandBuilder.of().add("start").addFile(configuration.getScriptFile()); + } + } + class MacOs extends MacOsType implements WezTerminalType { public MacOs() { diff --git a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java index a5ab1fc39..605151719 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java @@ -10,23 +10,7 @@ import java.nio.file.Path; public interface WindowsTerminalType extends ExternalTerminalType { - @Override - default boolean isRecommended() { - return true; - } - - @Override - default boolean supportsTabs() { - return true; - } - - @Override - default boolean supportsColoredTitle() { - return false; - } - public static final ExternalTerminalType WINDOWS_TERMINAL = new Standard(); - public static final ExternalTerminalType WINDOWS_TERMINAL_PREVIEW = new Preview(); private static CommandBuilder toCommand(ExternalTerminalType.LaunchConfiguration configuration) throws Exception { @@ -48,9 +32,26 @@ public interface WindowsTerminalType extends ExternalTerminalType { return cmd.add("--title").addQuoted(fixedName).add(toExec); } + @Override + default boolean supportsTabs() { + return true; + } + + @Override + default boolean isRecommended() { + return true; + } + + @Override + default boolean supportsColoredTitle() { + return false; + } + class Standard extends SimplePathType implements WindowsTerminalType { - public Standard() {super("app.windowsTerminal", "wt.exe", false);} + public Standard() { + super("app.windowsTerminal", "wt.exe", false); + } @Override public String getWebsite() { diff --git a/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java index dcc83c3e6..a2fb3f221 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java @@ -18,6 +18,12 @@ public class UpdateAvailableAlert { return; } + // Check whether we still have the latest version prepared + uh.refreshUpdateCheckSilent(); + if (uh.getPreparedUpdate().getValue() == null) { + return; + } + var u = uh.getPreparedUpdate().getValue(); var update = AppWindowHelper.showBlockingAlert(alert -> { alert.setTitle(AppI18n.get("updateReadyAlertTitle")); diff --git a/app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java b/app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java deleted file mode 100644 index 0c42c420b..000000000 --- a/app/src/main/java/io/xpipe/app/update/XPipeInstanceHelper.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.xpipe.app.update; - -import io.xpipe.app.core.AppProperties; -import io.xpipe.app.issue.ErrorEvent; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.beacon.XPipeInstance; -import io.xpipe.core.store.ShellStore; - -import java.io.IOException; -import java.nio.file.Files; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - -public class XPipeInstanceHelper { - - public static UUID getInstanceId() { - var file = AppProperties.get().getDataDir().resolve("instance"); - if (!Files.exists(file)) { - var id = UUID.randomUUID(); - try { - Files.writeString(file, id.toString()); - } catch (IOException e) { - ErrorEvent.fromThrowable(e).handle(); - } - return id; - } - - try { - return UUID.fromString(Files.readString(file)); - } catch (Exception e) { - ErrorEvent.fromThrowable(e).handle(); - return UUID.randomUUID(); - } - } - - public static boolean isSupported(ShellStore host) { - try (var pc = host.control().start(); - var cmd = pc.command("xpipe")) { - cmd.discardOrThrow(); - return true; - } catch (Exception e) { - return false; - } - } - - public static Optional getInstance(ShellStore store) { - if (!isSupported(store)) { - return Optional.empty(); - } - - // try (BeaconClient beaconClient = ProcessBeaconClient.create(store)) { - // beaconClient.sendRequest(InstanceExchange.Request.builder().build()); - // InstanceExchange.Response response = beaconClient.receiveResponse(); - // return Optional.of(response.getInstance()); - // } catch (Exception e) { - // return Optional.empty(); - // } - return Optional.empty(); - } - - public static XPipeInstance refresh() { - Map> map = DataStorage.get().getStoreEntries().stream() - .filter(entry -> entry.getStore() instanceof ShellStore) - .collect(Collectors.toMap( - entry -> entry.getStore().asNeeded(), - entry -> getInstance(entry.getStore().asNeeded()))); - var adjacent = map.entrySet().stream() - .filter(shellStoreOptionalEntry -> - shellStoreOptionalEntry.getValue().isPresent()) - .collect(Collectors.toMap( - entry -> entry.getKey(), entry -> entry.getValue().get())); - var reachable = adjacent.values().stream() - .map(XPipeInstance::getReachable) - .flatMap(Collection::stream) - .toList(); - - var id = getInstanceId(); - var name = "test"; - return new XPipeInstance(id, name, adjacent, reachable); - } -} diff --git a/app/src/main/java/io/xpipe/app/util/DataStoreCategoryChoiceComp.java b/app/src/main/java/io/xpipe/app/util/DataStoreCategoryChoiceComp.java index f274250d7..65410fa29 100644 --- a/app/src/main/java/io/xpipe/app/util/DataStoreCategoryChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/util/DataStoreCategoryChoiceComp.java @@ -4,7 +4,6 @@ import io.xpipe.app.comp.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.property.Property; import javafx.geometry.Insets; import javafx.scene.control.ComboBox; @@ -28,7 +27,7 @@ public class DataStoreCategoryChoiceComp extends SimpleComp { @Override protected Region createSimple() { - SimpleChangeListener.apply(external, newValue -> { + external.subscribe(newValue -> { if (newValue == null) { value.setValue(root); } else if (root == null) { diff --git a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java index 592271f83..99c67b8cc 100644 --- a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java +++ b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java @@ -68,7 +68,9 @@ public class DesktopShortcuts { .createTextFileWriteCommand(pc, "APPL????", base + "/Contents/PkgInfo") .execute(); pc.getShellDialect() - .createTextFileWriteCommand(pc, """ + .createTextFileWriteCommand( + pc, + """ @@ -77,7 +79,8 @@ public class DesktopShortcuts { icon.icns - """, base + "/Contents/Info.plist") + """, + base + "/Contents/Info.plist") .execute(); pc.executeSimpleCommand("cp \"" + icon + "\" \"" + base + "/Contents/Resources/icon.icns\""); } diff --git a/app/src/main/java/io/xpipe/app/util/HostHelper.java b/app/src/main/java/io/xpipe/app/util/HostHelper.java index f15d4cfcc..c73857f68 100644 --- a/app/src/main/java/io/xpipe/app/util/HostHelper.java +++ b/app/src/main/java/io/xpipe/app/util/HostHelper.java @@ -1,9 +1,17 @@ package io.xpipe.app.util; +import java.io.IOException; +import java.net.ServerSocket; import java.util.Locale; public class HostHelper { + public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException { + try (ServerSocket socket = new ServerSocket(0)) { + return socket.getLocalPort(); + } + } + public static boolean isLocalHost(String host) { if (host.equals("127.0.0.1")) { return true; diff --git a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java index 37b66fcb1..cc9f384d1 100644 --- a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java +++ b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java @@ -9,6 +9,7 @@ public class Hyperlinks { public static final String PRIVACY = "https://docs.xpipe.io/privacy-policy"; public static final String EULA = "https://docs.xpipe.io/end-user-license-agreement"; public static final String SECURITY = "https://docs.xpipe.io/security"; + public static final String TRANSLATE = "https://github.com/xpipe-io/xpipe/lang"; public static final String DISCORD = "https://discord.gg/8y89vS8cRb"; public static final String SLACK = "https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg"; diff --git a/app/src/main/java/io/xpipe/app/util/InputHelper.java b/app/src/main/java/io/xpipe/app/util/InputHelper.java index 73459c621..31c8a239c 100644 --- a/app/src/main/java/io/xpipe/app/util/InputHelper.java +++ b/app/src/main/java/io/xpipe/app/util/InputHelper.java @@ -38,9 +38,21 @@ public class InputHelper { } public static void onNavigationInput(EventTarget target, Consumer r) { - target.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + target.addEventFilter(KeyEvent.KEY_PRESSED, event -> { var c = event.getCode(); - var list = List.of(KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN, KeyCode.SPACE, KeyCode.ENTER, KeyCode.SHIFT, KeyCode.TAB, KeyCode.NUMPAD2, KeyCode.NUMPAD4, KeyCode.NUMPAD6, KeyCode.NUMPAD8); + var list = List.of( + KeyCode.LEFT, + KeyCode.RIGHT, + KeyCode.UP, + KeyCode.DOWN, + KeyCode.SPACE, + KeyCode.ENTER, + KeyCode.SHIFT, + KeyCode.TAB, + KeyCode.NUMPAD2, + KeyCode.NUMPAD4, + KeyCode.NUMPAD6, + KeyCode.NUMPAD8); r.accept(list.stream().anyMatch(keyCode -> keyCode == c)); }); target.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { diff --git a/app/src/main/java/io/xpipe/app/util/JfxHelper.java b/app/src/main/java/io/xpipe/app/util/JfxHelper.java index b704bf8c4..64512f105 100644 --- a/app/src/main/java/io/xpipe/app/util/JfxHelper.java +++ b/app/src/main/java/io/xpipe/app/util/JfxHelper.java @@ -3,6 +3,7 @@ package io.xpipe.app.util; import atlantafx.base.controls.Spacer; import io.xpipe.app.core.AppFont; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; +import javafx.beans.value.ObservableValue; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.HBox; @@ -11,10 +12,12 @@ import javafx.scene.layout.VBox; public class JfxHelper { - public static Region createNamedEntry(String nameString, String descString, String image) { - var header = new Label(nameString); + public static Region createNamedEntry(ObservableValue nameString, ObservableValue descString, String image) { + var header = new Label(); + header.textProperty().bind(nameString); AppFont.header(header); - var desc = new Label(descString); + var desc = new Label(); + desc.textProperty().bind(descString); AppFont.small(desc); var text = new VBox(header, new Spacer(), desc); text.setAlignment(Pos.CENTER_LEFT); diff --git a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java index e979a1f1e..c0e28b8ad 100644 --- a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java +++ b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java @@ -2,7 +2,6 @@ package io.xpipe.app.util; import io.xpipe.app.ext.ExtensionException; import io.xpipe.app.fxcomps.Comp; -import io.xpipe.core.process.ShellControl; import io.xpipe.core.util.ModuleLayerLoader; import javafx.beans.value.ObservableValue; @@ -22,7 +21,7 @@ public abstract class LicenseProvider { public abstract LicensedFeature getFeature(String id); - public abstract void handleShellControl(ShellControl sc); + public abstract void checkShellControl(String s); public abstract void showLicenseAlert(LicenseRequiredException ex); @@ -41,15 +40,5 @@ public abstract class LicenseProvider { .findFirst() .orElseThrow(() -> ExtensionException.corrupt("Missing license provider")); } - - @Override - public boolean requiresFullDaemon() { - return true; - } - - @Override - public boolean prioritizeLoading() { - return true; - } } } diff --git a/app/src/main/java/io/xpipe/app/util/LicenseRequiredException.java b/app/src/main/java/io/xpipe/app/util/LicenseRequiredException.java index 8eb2eda02..e3ac65449 100644 --- a/app/src/main/java/io/xpipe/app/util/LicenseRequiredException.java +++ b/app/src/main/java/io/xpipe/app/util/LicenseRequiredException.java @@ -1,20 +1,20 @@ package io.xpipe.app.util; +import io.xpipe.app.core.AppI18n; import lombok.Getter; +@Getter public class LicenseRequiredException extends RuntimeException { - @Getter private final LicensedFeature feature; public LicenseRequiredException(LicensedFeature feature) { - super(feature.getDisplayName() + (feature.isPlural() ? " are" : " is") - + " only supported with a professional license"); + super(feature.getDisplayName() + " " + (feature.isPlural() ? AppI18n.get("areOnlySupported") : AppI18n.get("isOnlySupported"))); this.feature = feature; } public LicenseRequiredException(String featureName, boolean plural, LicensedFeature feature) { - super(featureName + (plural ? " are" : " is") + " only supported with a professional license"); + super(featureName + " " + (plural ? AppI18n.get("areOnlySupported") : AppI18n.get("isOnlySupported"))); this.feature = feature; } } diff --git a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java index 0b7f50c0a..0c713373c 100644 --- a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java +++ b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java @@ -297,7 +297,7 @@ public class OptionsBuilder { public OptionsBuilder longDescription(String descriptionKey) { finishCurrent(); - longDescription = AppI18n.getInstance().getMarkdownDocumentation(descriptionKey); + longDescription = AppI18n.get().getMarkdownDocumentation(descriptionKey); return this; } diff --git a/app/src/main/java/io/xpipe/app/util/PlatformState.java b/app/src/main/java/io/xpipe/app/util/PlatformState.java index 4632cdba3..7c0bf40c3 100644 --- a/app/src/main/java/io/xpipe/app/util/PlatformState.java +++ b/app/src/main/java/io/xpipe/app/util/PlatformState.java @@ -1,17 +1,14 @@ package io.xpipe.app.util; import io.xpipe.app.core.check.AppSystemFontCheck; -import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.process.OsType; import javafx.application.Platform; -import javafx.scene.input.Clipboard; import lombok.Getter; import lombok.Setter; import java.awt.*; -import java.awt.datatransfer.StringSelection; import java.util.Optional; import java.util.concurrent.CountDownLatch; @@ -28,15 +25,16 @@ public enum PlatformState { private static Exception lastError; public static void teardown() { - PlatformThread.runLaterIfNeededBlocking(() -> { - try { - // Fix to preserve clipboard contents after shutdown - var string = Clipboard.getSystemClipboard().getString(); - var s = new StringSelection(string); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s); - } catch (IllegalStateException ignored) { - } - }); + // This is bad and can get sometimes stuck + // PlatformThread.runLaterIfNeededBlocking(() -> { + // try { + // // Fix to preserve clipboard contents after shutdown + // var string = Clipboard.getSystemClipboard().getString(); + // var s = new StringSelection(string); + // Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s); + // } catch (IllegalStateException ignored) { + // } + // }); Platform.exit(); setCurrent(PlatformState.EXITED); diff --git a/app/src/main/java/io/xpipe/app/util/RdpConfig.java b/app/src/main/java/io/xpipe/app/util/RdpConfig.java new file mode 100644 index 000000000..e89b68ce5 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/RdpConfig.java @@ -0,0 +1,66 @@ +package io.xpipe.app.util; + +import lombok.Value; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Value +public class RdpConfig { + + Map content; + + public static RdpConfig parseFile(String file) throws IOException { + var content = Files.readString(Path.of(file)); + return parseContent(content); + } + + public static RdpConfig parseContent(String content) { + var map = new LinkedHashMap(); + content.lines().forEach(s -> { + var split = s.split(":"); + if (split.length < 2) { + return; + } + + if (split.length == 2) { + map.put(split[0].trim(), new RdpConfig.TypedValue("s", split[1].trim())); + } + + if (split.length == 3) { + map.put(split[0].trim(), new RdpConfig.TypedValue(split[1].trim(), split[2].trim())); + } + }); + return new RdpConfig(map); + } + + public RdpConfig overlay(Map override) { + var newMap = new LinkedHashMap<>(content); + newMap.putAll(override); + return new RdpConfig(newMap); + } + + public String toString() { + return content.entrySet().stream() + .map(e -> { + return e.getKey() + ":" + e.getValue().getType() + ":" + + e.getValue().getValue(); + }) + .collect(Collectors.joining("\n")); + } + + public Optional get(String key) { + return Optional.ofNullable(content.get(key)); + } + + @Value + public static class TypedValue { + String type; + String value; + } +} diff --git a/app/src/main/java/io/xpipe/app/util/ScanAlert.java b/app/src/main/java/io/xpipe/app/util/ScanAlert.java index d6804e8d1..4f4e53cd0 100644 --- a/app/src/main/java/io/xpipe/app/util/ScanAlert.java +++ b/app/src/main/java/io/xpipe/app/util/ScanAlert.java @@ -7,7 +7,6 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ScanProvider; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; @@ -168,7 +167,7 @@ public class ScanAlert { }) .padding(new Insets(20)); - SimpleChangeListener.apply(entry, newValue -> { + entry.subscribe(newValue -> { selected.clear(); stackPane.getChildren().clear(); diff --git a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java index 4318f18bb..6bc9ae938 100644 --- a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java @@ -3,7 +3,6 @@ package io.xpipe.app.util; import io.xpipe.app.issue.TrackEvent; import io.xpipe.core.process.*; import io.xpipe.core.store.FilePath; -import io.xpipe.core.util.FailableFunction; import io.xpipe.core.util.SecretValue; import lombok.SneakyThrows; @@ -30,7 +29,7 @@ public class ScriptHelper { public static FilePath constructTerminalInitFile( ShellDialect t, ShellControl processControl, - FailableFunction workingDirectory, + WorkingDirectoryFunction workingDirectory, List init, String toExecuteInShell, TerminalInitScriptConfig config) @@ -59,10 +58,10 @@ public class ScriptHelper { content += nl + t.changeTitleCommand(config.getDisplayName()) + nl; } - if (workingDirectory != null) { + if (workingDirectory != null && workingDirectory.isSpecified()) { var wd = workingDirectory.apply(processControl); if (wd != null) { - content += t.getCdCommand(wd) + nl; + content += t.getCdCommand(wd.toString()) + nl; } } @@ -104,7 +103,8 @@ public class ScriptHelper { } @SneakyThrows - public static FilePath createExecScript(ShellDialect type, ShellControl processControl, FilePath file, String content) { + public static FilePath createExecScript( + ShellDialect type, ShellControl processControl, FilePath file, String content) { content = type.prepareScriptContent(content); TrackEvent.withTrace("Writing exec script") diff --git a/app/src/main/java/io/xpipe/app/util/ShellTemp.java b/app/src/main/java/io/xpipe/app/util/ShellTemp.java index 7be0c9bc8..eeacef7b9 100644 --- a/app/src/main/java/io/xpipe/app/util/ShellTemp.java +++ b/app/src/main/java/io/xpipe/app/util/ShellTemp.java @@ -59,7 +59,8 @@ public class ShellTemp { var d = proc.getShellDialect(); var systemTemp = proc.getSystemTemporaryDirectory(); - if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() || !checkDirectoryPermissions(proc, systemTemp.toString())) { + if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() + || !checkDirectoryPermissions(proc, systemTemp.toString())) { throw ErrorEvent.expected(new IOException("No permissions to access %s".formatted(systemTemp))); } @@ -87,7 +88,7 @@ public class ShellTemp { var base = proc.getSystemTemporaryDirectory(); var arr = Stream.concat(Stream.of(base.toString()), Arrays.stream(sub)).toArray(String[]::new); var dir = FileNames.join(arr); - + // We assume that this directory does not exist yet and therefore don't perform any checks proc.getShellDialect().prepareUserTempDirectory(proc, dir).execute(); diff --git a/app/src/main/java/io/xpipe/app/util/StringSource.java b/app/src/main/java/io/xpipe/app/util/StringSource.java new file mode 100644 index 000000000..6be190226 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/StringSource.java @@ -0,0 +1,50 @@ +package io.xpipe.app.util; + +import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.app.storage.ContextualFileReference; +import io.xpipe.core.store.ShellStore; +import lombok.EqualsAndHashCode; +import lombok.Value; + +public abstract class StringSource { + + public abstract String get() throws Exception; + + @Value + @EqualsAndHashCode(callSuper = true) + public static class InPlace extends StringSource { + + String value; + + @Override + public String get() { + return value; + } + } + + @Value + @EqualsAndHashCode(callSuper = true) + public static class File extends StringSource { + + ShellStore host; + ContextualFileReference file; + + @Override + public String get() throws Exception { + if (host == null || file == null) { + return ""; + } + + try (var sc = host.control().start()) { + var path = file.toAbsoluteFilePath(sc); + if (!sc.getShellDialect().createFileExistsCommand(sc, path).executeAndCheck()) { + throw ErrorEvent.expected(new IllegalArgumentException("File " + path + " does not exist")); + } + + var abs = file.toAbsoluteFilePath(sc); + var content = sc.getShellDialect().getFileReadCommand(sc, abs).readStdoutOrThrow(); + return content; + } + } + } +} diff --git a/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java b/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java index 4ee4a3209..e63da7ecb 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java @@ -6,10 +6,7 @@ import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.terminal.ExternalTerminalType; -import io.xpipe.core.process.ProcessControl; -import io.xpipe.core.process.ProcessControlProvider; -import io.xpipe.core.process.ShellControl; -import io.xpipe.core.process.TerminalInitScriptConfig; +import io.xpipe.core.process.*; import io.xpipe.core.util.FailableFunction; import java.io.IOException; @@ -18,14 +15,23 @@ import java.util.UUID; public class TerminalLauncher { - public static void openDirect(String title, FailableFunction command) throws Exception { + public static void openDirect(String title, FailableFunction command) + throws Exception { try (var sc = LocalShell.getShell().start()) { var type = AppPrefs.get().terminalType().getValue(); if (type == null) { throw ErrorEvent.expected(new IllegalStateException(AppI18n.get("noTerminalSet"))); } - var script = ScriptHelper.constructTerminalInitFile(sc.getShellDialect(), sc, ignored -> null, List.of(), - command.apply(sc), new TerminalInitScriptConfig(title, type.shouldClear() && AppPrefs.get().clearTerminalOnInit().get())); + var script = ScriptHelper.constructTerminalInitFile( + sc.getShellDialect(), + sc, + WorkingDirectoryFunction.none(), + List.of(), + command.apply(sc), + new TerminalInitScriptConfig( + title, + type.shouldClear() + && AppPrefs.get().clearTerminalOnInit().get())); var config = new ExternalTerminalType.LaunchConfiguration(null, title, title, script, sc.getShellDialect()); type.launch(config); } diff --git a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java index fa88d9ac2..73e4fbb6a 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java @@ -5,7 +5,8 @@ import io.xpipe.beacon.ServerException; import io.xpipe.core.process.ProcessControl; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.TerminalInitScriptConfig; -import io.xpipe.core.util.FailableFunction; +import io.xpipe.core.process.WorkingDirectoryFunction; +import io.xpipe.core.store.FilePath; import lombok.Setter; import lombok.Value; import lombok.experimental.NonFinal; @@ -22,16 +23,26 @@ public class TerminalLauncherManager { private static void prepare( ProcessControl processControl, TerminalInitScriptConfig config, String directory, Entry entry) { - FailableFunction workingDirectory = sc -> { - if (directory == null) { - return null; + var workingDirectory = new WorkingDirectoryFunction() { + + @Override + public boolean isFixed() { + return true; } - if (!sc.getShellDialect().directoryExists(sc, directory).executeAndCheck()) { - return null; + @Override + public boolean isSpecified() { + return directory != null; } - return directory; + @Override + public FilePath apply(ShellControl shellControl) throws Exception { + if (directory == null) { + return null; + } + + return new FilePath(directory); + } }; try { diff --git a/app/src/main/java/io/xpipe/app/util/WindowControl.java b/app/src/main/java/io/xpipe/app/util/WindowControl.java new file mode 100644 index 000000000..867b241bc --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/WindowControl.java @@ -0,0 +1,55 @@ +package io.xpipe.app.util; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.PointerType; +import com.sun.jna.platform.win32.User32; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinNT; +import javafx.stage.Window; +import lombok.Getter; + +import java.lang.reflect.Method; + +@Getter +public class WindowControl { + + private final WinDef.HWND windowHandle; + + public WindowControl(Window stage) throws Exception { + Method tkStageGetter = stage.getClass().getSuperclass().getDeclaredMethod("getPeer"); + tkStageGetter.setAccessible(true); + Object tkStage = tkStageGetter.invoke(stage); + Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow"); + getPlatformWindow.setAccessible(true); + Object platformWindow = getPlatformWindow.invoke(tkStage); + Method getNativeHandle = platformWindow.getClass().getMethod("getNativeHandle"); + getNativeHandle.setAccessible(true); + Object nativeHandle = getNativeHandle.invoke(platformWindow); + var hwnd = new WinDef.HWND(new Pointer((long) nativeHandle)); + this.windowHandle = hwnd; + } + + public WindowControl(WinDef.HWND windowHandle) { + this.windowHandle = windowHandle; + } + + public void move(int x, int y, int w, int h) { + User32.INSTANCE.SetWindowPos(windowHandle, new WinDef.HWND(), x, y, w, h, 0); + } + + public void setWindowAttribute(int attribute, boolean attributeValue) { + DwmSupport.INSTANCE.DwmSetWindowAttribute( + windowHandle, attribute, new WinDef.BOOLByReference(new WinDef.BOOL(attributeValue)), WinDef.BOOL.SIZE); + User32.INSTANCE.UpdateWindow(windowHandle); + } + + public interface DwmSupport extends Library { + + DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class); + + WinNT.HRESULT DwmSetWindowAttribute( + WinDef.HWND hwnd, int dwAttribute, PointerType pvAttribute, int cbAttribute); + } +} diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 4bad25c43..4320a8533 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -3,10 +3,7 @@ import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.core.AppLogs; import io.xpipe.app.exchange.*; import io.xpipe.app.exchange.cli.*; -import io.xpipe.app.ext.ActionProvider; -import io.xpipe.app.ext.DataStoreProvider; -import io.xpipe.app.ext.PrefsProvider; -import io.xpipe.app.ext.ScanProvider; +import io.xpipe.app.ext.*; import io.xpipe.app.issue.EventHandler; import io.xpipe.app.issue.EventHandlerImpl; import io.xpipe.app.storage.DataStateProviderImpl; @@ -42,6 +39,9 @@ open module io.xpipe.app { exports io.xpipe.app.browser.icon; exports io.xpipe.app.core.check; exports io.xpipe.app.terminal; + exports io.xpipe.app.browser.session; + exports io.xpipe.app.browser.fs; + exports io.xpipe.app.browser.file; requires com.sun.jna; requires com.sun.jna.platform; @@ -77,6 +77,7 @@ open module io.xpipe.app { requires jdk.management; requires jdk.management.agent; requires net.steppschuh.markdowngenerator; + requires com.shinyhut.vernacular; // Required by extensions requires java.security.jgss; @@ -116,6 +117,8 @@ open module io.xpipe.app { provides Module with StorageJacksonModule; provides ModuleLayerLoader with + MessageExchangeImpls.Loader, + DataStoreProviders.Loader, ActionProvider.Loader, PrefsProvider.Loader, BrowserAction.Loader, @@ -150,6 +153,5 @@ open module io.xpipe.app { TerminalWaitExchangeImpl, TerminalLaunchExchangeImpl, QueryStoreExchangeImpl, - InstanceExchangeImpl, VersionExchangeImpl; } diff --git a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties b/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties deleted file mode 100644 index 47e2669e5..000000000 --- a/app/src/main/resources/io/xpipe/app/resources/lang/translations_en.properties +++ /dev/null @@ -1,392 +0,0 @@ -# Interface -addCollection=Add collection -newCollection=New collection -delete=Delete -rename=Rename -properties=Properties -usedDate=Used $DATE$ -cols=$COLS$ columns -rowsCols=$ROWS$ rows / $COLS$ columns -lines=$LINES$ lines -objects=$OBJECTS$ objects -bytes=$BYTES$ bytes -entries=$ENTRIES$ entries -unknownLength=Unknown length -temporaryCollection=Temporary -entrySettings=Settings -pipe=Pipe -openDir=Open Directory -failedToLoad=Failed to Load -stores=Stores -# Dialogs -confirmCollectionDeletionTitle=Confirm collection deletion -confirmCollectionDeletionHeader=Do you really want to delete the collection $NAME$? -confirmCollectionDeletionContent=This will delete all ($COUNT$) contained data sources as well. -retrieveDataSource=Retrieve Data Source -# Tooltips -addCollectionFolder=Create new collection folder -collectionOptions=Collection options -addStreamDataSource=Add stream data source -addDatabaseDataSource=Add database data source -displayList=Display as list -displayTiles=Display as tiles -sortLastUsed=Sort by last used date -sortAlphabetical=Sort alphabetical by name -temporaryCollectionNote=All data sources inside the temporary collection are only stored while until the next system restart. -storeForLaterUse=Store for later use -localFile=Local File -network=Network -recentFiles=Recent files -newDataSource=New data source -newDataStore=New data store -selectInput=Select Input -configure=Configure -retrieve=Retrieve -internet=Internet -table=Table -update=Update -selectStreamStore=Select Stream Store -openStreamStoreWizard=Open Stream Store Wizard -updateDataSource=Update Data Source -structure=Structure -text=Text -raw=Raw -collection=Collection -anyFile=Any file -anyStream=Any Stream Type -noMatchingStoreFound=No suitable saved store was found -addStore=Add Store -anyStreamDescription=Or choose specific type -restart=Restart XPipe -restartDescription=A restart can often be a quick fix -reportIssue=Report Issue -reportIssueDescription=Open the integrated issue reporter -usefulActions=Useful actions -stored=Saved -troubleshootingOptions=Troubleshooting tools -troubleshoot=Troubleshoot -remote=Remote File -addShellStore=Add Shell ... -addShellTitle=Add Shell Connection -savedConnections=Saved Connections -save=Save -clean=Clean -refresh=Refresh -moveTo=Move to ... -addDatabase=Database ... -browseInternalStorage=Browse internal storage -addTunnel=Tunnel ... -addScript=Script ... -addHost=Remote Host ... -addShell=Shell Environment ... -addCommand=Custom Command ... -addAutomatically=Search Automatically ... -addOther=Add Other ... -addStreamTitle=Add Stream Store -addConnection=Add Connection -skip=Skip -addConnections=New -selectType=Select Type -selectTypeDescription=Select connection type -selectDatabaseType=Database Type -selectDatabaseTypeDescription=Select Type of the Database -selectShellType=Shell Type -selectShellTypeDescription=Select the Type of the Shell Connection -selectStreamType=Stream Type -selectStreamTypeDescription=Select type of the stream -name=Name -storeIntroTitle=Connection Hub -storeIntroDescription=Here you can manage all your local and remote shell connections in one place. To start off, you can quickly detect available connections automatically and choose which ones to add. -detectConnections=Search for connections -configuration=Configuration -dragAndDropFilesHere=Or just drag and drop a file here -confirmDsCreationAbortTitle=Confirm abort -confirmDsCreationAbortHeader=Do you want to abort the data source creation? -confirmDsCreationAbortContent=Any data source creation progress will be lost. -confirmInvalidStoreTitle=Failed connection -confirmInvalidStoreHeader=Do you want to skip connection validation? -confirmInvalidStoreContent=You can add this connection even if it could not be validated and fix the connection problems later on. -charset=Charset -newLine=Newline -crlf=CRLF (Windows) -lf=LF (Linux) -none=None -expand=Expand -accessSubConnections=Access sub connections -common=Common -key=Key -color=Color -roadmap=Roadmap and feature requests -alwaysConfirmElevation=Always confirm elevation -alwaysConfirmElevationDescription=Controls how to handle cases when elevated access is required to run a command on a system, e.g. with sudo.\n\nBy default, any sudo credentials are cached during a session and automatically provided when needed. If this option is enabled, it will ask you to confirm the elevation access every time. -allow=Allow -ask=Ask -deny=Deny -elevationRequestTitle=Elevation request -elevationRequestHeader=A command on $SYSTEM$ requires elevation. Do you want to allow this? -elevationRequestDescription=Continuing from here XPipe will try to elevate commands when needed. Aborting will cancel the operation. -share=Add to git repository -unshare=Remove from git repository -remove=Remove -newCategory=New subcategory -passwordManager=Password manager -prompt=Prompt -customCommand=Custom command -other=Other -setLock=Set lock -selectConnection=Select connection -changeLock=Change passphrase -test=Test -lockCreationAlertTitle=Set passphrase -lockCreationAlertHeader=Set your new master passphrase -finish=Finish -error=An error occurred -downloadStageDescription=Downloads files to your local machine, so you can drag and drop them into your native desktop environment. -ok=Ok -search=Search -newFile=New file -newDirectory=New directory -passphrase=Passphrase -repeatPassphrase=Repeat passphrase -password=Password -unlockAlertTitle=Unlock workspace -unlockAlertHeader=Enter your vault passphrase to continue -enterLockPassword=Enter lock password -repeatPassword=Repeat password -askpassAlertTitle=Askpass -nullPointer=Null Pointer -unsupportedOperation=Unsupported operation: $MSG$ -fileConflictAlertTitle=Resolve conflict -fileConflictAlertHeader=A conflict was encountered. How would you like to proceed? -fileConflictAlertContent=The file $FILE$ does already exist on the target system. -fileConflictAlertContentMultiple=The file $FILE$ already exists. There might be more conflicts that you can automatically resolve by choosing an option that applies to all. -moveAlertTitle=Confirm move -moveAlertHeader=Do you want to move the ($COUNT$) selected elements into $TARGET$? -deleteAlertTitle=Confirm deletion -deleteAlertHeader=Do you want to delete the ($COUNT$) selected elements? -selectedElements=Selected elements: -mustNotBeEmpty=$VALUE$ must not be empty -valueMustNotBeEmpty=Value must not be empty -transferDescription=Drop files to transfer -dragFiles=Drag files within browser -dragLocalFiles=Drag local files from here -null=$VALUE$ must be not null -roots=Roots -terminator=Terminator -kitty=Kitty -terminology=Terminology -coolRetroTerm=Cool Retro Term -guake=Guake -alacritty=Alacritty -tilda=Tilda -xterm=XTerm -deepinTerminal=Deepin Terminal -qTerminal=QTerminal -recent=Recent -hostFeatureUnsupported=$FEATURE$ is not installed on the host -missingStore=$NAME$ does not exist -connectionName=Connection name -connectionNameDescription=Give this connection a custom name -openFileTitle=Open file -unknown=Unknown -scanAlertTitle=Add connections -scanAlertChoiceHeader=Target -scanAlertChoiceHeaderDescription=Choose where to search for connections. This will look for all available connections first. -scanAlertHeader=Connection types -scanAlertHeaderDescription=Select types of connections you want to automatically add for the system. -namedHostFeatureUnsupported=$HOST$ does not support this feature -namedHostNotActive=$HOST$ is not active -noInformationAvailable=No information available -localMachine=Local Machine -input=Input -output=Output -inout=Transformation -inputDescription=This store only produces input for data sources to read -outputDescription=This store only accepts output from data sources to write -inoutDescription=This store uses both input and output to essentially create a data transformation -replace=Replace -append=Append -prepend=Prepend -replaceDescription=Replaces all content -appendDescription=Appends the new content to the existing content -prependDescription=Prepends the new content to the existing content -yes=Yes -no=No -connectorInstallationTitle=XPipe Connector -connectorInstallationHeader=Would you like to install the XPipe connector on that host? -connectorInstallationContent=Some operations require the XPipe connector to be installed on the host. Note that this operation may take some time. -errorOccured=An error occured -terminalErrorOccured=A terminal error occured -errorTypeOccured=An exception of type $TYPE$ was thrown -permissionsAlertTitle=Permissions required -permissionsAlertHeader=Additional permissions are required to perform this operation. -permissionsAlertContent=Please follow the pop-up to give XPipe the required permissions in the settings menu. -errorDetails=Show details -target=Target -data=Data -more=More -pipeDataSource=Pipe Data Source -updateReadyAlertTitle=Update Ready -updateReadyAlertHeader=An update to version $VERSION$ is ready to be installed -updateReadyAlertContent=This will install the new version and restart XPipe once the installation finished. -errorNoDetail=No error details are available -updateAvailableTitle=Update Available -updateAvailableHeader=An XPipe update to version $VERSION$ is available to install -updateAvailableContent=Even though XPipe could not be started, you can attempt to install the update to potentially fix the issue. -clipboardActionDetectedTitle=Clipboard Action detected -clipboardActionDetectedHeader=Do you want to import your clipboard content? -clipboardActionDetectedContent=XPipe detected content in your clipboard that can be opened. Do you want to open it now? -install=Install ... -ignore=Ignore -possibleActions=Possible actions -reportError=Report error -reportOnGithub=Report on GitHub -reportOnGithubDescription=Open a new issue in the GitHub repository -reportErrorDescription=Send an error report with optional user feedback and diagnostics info -ignoreError=Ignore error -ignoreErrorDescription=Ignore this error and continue like nothing happened -provideEmail=How to contact you (optional, only if you want to get notified about fixes) -additionalErrorInfo=Provide additional information (optional) -additionalErrorAttachments=Select attachments (optional) -dataHandlingPolicies=Privacy policy -sendReport=Send report -errorHandler=Error handler -events=Events -method=Method -validate=Validate -confirmTableMappingTitle=Confirm Table Mapping -confirmTableMapping=Please confirm the automatically determined table mapping: -changeTableMapping=In case you are not satisfied with this mapping, take a look at how to customize data flows: -discarded=Discarded -stackTrace=Stack trace -previousStep=< Previous -nextStep=Next > -finishStep=Finish -machine=Machine -noMatchingSourceFound=No matching source found -addSource=Add Source -edit=Edit -addStream=Add File -pipeStream=Pipe File -pipeDatabase=Pipe Database -transfer=Transfer -browseInternal=Browse Internal -checkOutUpdate=Check out update -# Tray -open=Open -quit=Quit -# DS preview -normal=Normal -normalDescription=The data source contents are queried from the original source each time it is accessed. -cached=Cache -cachedDescription=The data source contents are cached, i.e. stored temporarily such that the original data source does not have to accessed every time. The caching state can be refreshed at any time. -managed=Manage copy -editDataSource=Edit Data Source -managedDescription=The data source contents are copied to an internally managed file, i.e. the original data source is never accessed again after creation. -storageType=Access mode: -setupGuide=Guide -recentlyUsed=Recently used -programmingLanguages=Programming languages -applications=Applications -addMore=Add more -vscode=Visual Studio Code -vscodium=VSCodium -vscodeInsiders=Visual Studio Code Insiders -kate=Kate -gedit=GEdit -gnomeTextEditor=Gnome Text Editor -leafpad=Leafpad -mousepad=Mousepad -pluma=Pluma -noTerminalSet=No terminal application has been set automatically. You can do so manually in the settings menu. -textEdit=Text Edit -sublime=Sublime Text -newTable=new_table -editRaw=Edit Raw -file=File -# Sidebar -overview=Sources -connections=Connections -settings=Settings -explorePlans=License -help=Help -account=Account -about=About -developer=Developer -# Comps -browseFileTitle=Browse file -browse=Browse -browser=Browser -selectFileFromComputer=Select a file from this computer -# About -links=Useful links -website=Website -documentation=Documentation -discord=Discord -discordDescription=Join the Discord server -security=Security -securityPolicy=Security information -securityPolicyDescription=Read the detailed security policy -privacy=Privacy Policy -privacyDescription=Read the privacy policy for the XPipe application -slack=Slack -slackDescription=Join the Slack workspace -support=Support -github=GitHub -githubDescription=Check out the GitHub repository -openSourceNotices=Open Source Notices -xPipeClient=XPipe Desktop -checkForUpdates=Check for updates -checkForUpdatesDescription=Download an update if there is one -lastChecked=Last checked -version=Version -build=Build -runtimeVersion=Runtime version -virtualMachine=Virtual machine -updateReady=Install update -updateReadyPortable=Check out update -updateReadyDescription=An update was downloaded and is ready to be installed -updateReadyDescriptionPortable=An update is available to download -updateRestart=Restart to update -never=Never -updateAvailableTooltip=Update available -visitGithubRepository=Visit GitHub repository -updateAvailable=Update available: $VERSION$ -downloadUpdate=Download update -legalAccept=I accept the End User License Agreement -confirm=Confirm -print=Print -whatsNew=What's new in version $VERSION$ ($DATE$) -antivirusNoticeTitle=A note on Antivirus programs -malwarebytesNoticeTitle=A note on Malwarebytes -updateChangelogAlertTitle=Changelog -greetingsAlertTitle=Welcome to XPipe -gotIt=Got It -eula=End User License Agreement -news=News -introduction=Introduction -privacyPolicy=Privacy Policy -agree=Agree -disagree=Disagree -directories=Directories -logFile=Log File -logFiles=Log Files -logFilesAttachment=Log Files -issueReporter=Issue Reporter -openCurrentLogFile=Log files -openCurrentLogFileDescription=Open the log file of the current session -openLogsDirectory=Open logs directory -installationFiles=Installation Files -openInstallationDirectory=Installation files -openInstallationDirectoryDescription=Open XPipe installation directory -launchDebugMode=Debug mode -launchDebugModeDescription=Restart XPipe in debug mode -extensionInstallTitle=Download -extensionInstallDescription=This action requires additional third party libraries that are not distributed by XPipe. You can automatically install them here. The components are then downloaded from the vendor website: -extensionInstallLicenseNote=By performing the download and automatic installation you agree to the terms of the third party licenses: -license=License -installRequired=Installation Required -restore=Restore -restoreAllSessions=Restore all sessions - - diff --git a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css index bec47fc7d..c521ef04c 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css @@ -1,6 +1,6 @@ .bookmark-list > .categories { - -fx-padding: 0.7em 1em 0.7em 1em; + -fx-padding: 1em; -fx-background-color: -color-bg-subtle; -fx-border-color: -color-border-default; -fx-border-width: 0 0 1 0; diff --git a/app/src/main/resources/io/xpipe/app/resources/style/browser.css b/app/src/main/resources/io/xpipe/app/resources/style/browser.css index 0285991f0..97300ce42 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/browser.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/browser.css @@ -1,3 +1,12 @@ +.browser .visual-display { + -fx-border-color: -color-border-default; + -fx-border-width: 2 1 1 1; +} + +.browser .visual-display:focused { + -fx-border-color: -color-accent-emphasis; +} + .download-background { -fx-border-color: -color-border-default; -fx-border-width: 1px 0 0 0; diff --git a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css index 796d4b334..a40eb5d41 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css @@ -43,11 +43,6 @@ -fx-background-color: linear-gradient(from 100% 0% to 0% 100%, rgb(12, 11, 11) 40%, rgb(32, 32, 40) 50%, rgb(35, 29, 29) 100%); } -.store-header-bar .menu-button:hover, .root:key-navigation .store-header-bar .menu-button:focused { - -fx-background-color: -color-bg-default; - -fx-border-color: -color-fg-default; -} - .store-header-bar .menu-button > * { -fx-text-fill: -color-bg-default; } @@ -61,15 +56,20 @@ -fx-border-width: 4; } -.store-header-bar .menu-button:hover > *, .root:key-navigation .store-header-bar .menu-button:focused > * { +.root .store-header-bar .menu-button:hover, .root:key-navigation .store-header-bar .menu-button:focused { + -fx-background-color: -color-bg-default; + -fx-border-color: -color-fg-default; +} + +.root .store-header-bar .menu-button:hover > *, .root:key-navigation .store-header-bar .menu-button:focused > * { -fx-text-fill: -color-fg-default; } -.store-header-bar .menu-button:hover > * > .ikonli-font-icon, .root:key-navigation .store-header-bar .menu-button:focused > * > .ikonli-font-icon { +.root .store-header-bar .menu-button:hover > * > .ikonli-font-icon, .root:key-navigation .store-header-bar .menu-button:focused > * > .ikonli-font-icon { -fx-icon-color: -color-fg-default; } -.store-header-bar .menu-button:hover .arrow, .root:key-navigation .store-header-bar .menu-button:focused .arrow { +.root .store-header-bar .menu-button:hover .arrow, .root:key-navigation .store-header-bar .menu-button:focused .arrow { -fx-border-color: -color-fg-default; -fx-border-width: 4; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/style.css b/app/src/main/resources/io/xpipe/app/resources/style/style.css index 9961de269..c170ce6a9 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/style.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/style.css @@ -2,19 +2,11 @@ -fx-background-color: transparent; } -.root:pretty:dark.background { - -fx-background-color: linear-gradient(from 100% 0% to 0% 100%, derive(-color-bg-default, 5%) 40%, derive(-color-bg-default, 2%) 50%, derive(-color-bg-default, 5%) 100%); -} - -.root:performance:dark.background { +.root:dark.background { -fx-background-color: derive(-color-bg-default, 5%); } -.root:pretty:light.background { - -fx-background-color: linear-gradient(from 100% 0% to 0% 100%, derive(-color-bg-default, -9%) 40%, derive(-color-bg-default, 1%) 50%, derive(-color-bg-default, -9%) 100%); -} - -.root:performance:light.background { +.root:light.background { -fx-background-color: derive(-color-bg-default, -9%); } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java index bcef6b4a1..724f92bf6 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java @@ -11,10 +11,8 @@ import com.fasterxml.jackson.databind.node.TextNode; import io.xpipe.beacon.exchange.MessageExchanges; import io.xpipe.beacon.exchange.data.ClientErrorMessage; import io.xpipe.beacon.exchange.data.ServerErrorMessage; -import io.xpipe.core.store.ShellStore; import io.xpipe.core.util.Deobfuscator; import io.xpipe.core.util.JacksonMapper; -import io.xpipe.core.util.ProxyManagerProvider; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -62,51 +60,6 @@ public class BeaconClient implements AutoCloseable { return client; } - public static BeaconClient connectProxy(ShellStore proxy) throws Exception { - var control = proxy.control().start(); - if (!ProxyManagerProvider.get().setup(control)) { - throw new IOException("XPipe connector required to perform operation"); - } - var command = control.command("xpipe beacon --raw").start(); - command.discardErr(); - return new BeaconClient(command, command.getStdout(), command.getStdin()) { - - // { - // new Thread(() -> { - // while (true) { - // if (!control.isRunning()) { - // close(); - // } - // } - // }) - // } - - @Override - public void close() throws ConnectorException { - try { - getRawInputStream().readAllBytes(); - } catch (IOException ex) { - throw new ConnectorException(ex); - } - - super.close(); - } - - @Override - public T receiveResponse() - throws ConnectorException, ClientException, ServerException { - try { - sendEOF(); - getRawOutputStream().close(); - } catch (IOException ex) { - throw new ConnectorException(ex); - } - - return super.receiveResponse(); - } - }; - } - public static Optional tryEstablishConnection(ClientInformation information) { try { return Optional.of(establishConnection(information)); diff --git a/beacon/src/main/java/io/xpipe/beacon/XPipeInstance.java b/beacon/src/main/java/io/xpipe/beacon/XPipeInstance.java deleted file mode 100644 index 272086c04..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/XPipeInstance.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.xpipe.beacon; - -import io.xpipe.core.store.ShellStore; -import lombok.Value; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -@Value -public class XPipeInstance { - - UUID uuid; - String name; - Map adjacent; - List reachable; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/InstanceExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/InstanceExchange.java deleted file mode 100644 index 9f080bb88..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/InstanceExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.XPipeInstance; -import io.xpipe.beacon.exchange.MessageExchange; -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class InstanceExchange implements MessageExchange { - - @Override - public String getId() { - return "instance"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - XPipeInstance instance; - } -} diff --git a/beacon/src/main/java/module-info.java b/beacon/src/main/java/module-info.java index 53b0602d1..56dc388d9 100644 --- a/beacon/src/main/java/module-info.java +++ b/beacon/src/main/java/module-info.java @@ -27,7 +27,6 @@ open module io.xpipe.beacon { SinkExchange, DrainExchange, LaunchExchange, - InstanceExchange, EditStoreExchange, StoreProviderListExchange, ModeExchange, diff --git a/build.gradle b/build.gradle index 277f6755f..d324c44d5 100644 --- a/build.gradle +++ b/build.gradle @@ -77,14 +77,20 @@ project.ext { javafxVersion = '22' platformName = getPlatformName() artifactChecksums = new HashMap() + languages = ["en", "nl", "es", "fr", "de", "it", "pt", "ru", "ja", "zh", "tr"] jvmRunArgs = [ "--add-opens", "java.base/java.lang=io.xpipe.app", "--add-opens", "java.base/java.lang=io.xpipe.core", "--add-opens", "java.desktop/java.awt=io.xpipe.app", "--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=io.xpipe.app", "--add-opens", "java.base/java.nio.file=io.xpipe.app", + "--add-exports", "javafx.graphics/com.sun.javafx.tk=io.xpipe.app", + "--add-opens", "javafx.graphics/com.sun.glass.ui=io.xpipe.app", + "--add-opens", "javafx.graphics/javafx.stage=io.xpipe.app", + "--add-opens", "javafx.graphics/com.sun.javafx.tk.quantum=io.xpipe.app", "-Xmx8g", "-Dio.xpipe.app.arch=$rootProject.arch", + "-Dio.xpipe.app.languages=${String.join(";", languages)}", "-Dfile.encoding=UTF-8", // Disable this for now as it requires Windows 10+ // '-XX:+UseZGC', @@ -104,6 +110,7 @@ project.ext { if (signingPassword == null) { signingPassword = '' } + deeplApiKey = findProperty('DEEPL_API_KEY') } if (org.gradle.internal.os.OperatingSystem.current() == org.gradle.internal.os.OperatingSystem.LINUX) { diff --git a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java index 4e4f859bf..85c5211f9 100644 --- a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java +++ b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java @@ -147,6 +147,18 @@ public class CommandBuilder { return this; } + public CommandBuilder addAll(List s) { + for (String s1 : s) { + elements.add(new Fixed(s1)); + } + return this; + } + + public CommandBuilder addAll(FailableFunction, Exception> f) { + elements.add(sc -> String.join(" ", f.apply(sc))); + return this; + } + public CommandBuilder prepend(String... s) { elements.addAll(0, Arrays.stream(s).map(s2 -> new Fixed(s2)).toList()); return this; diff --git a/core/src/main/java/io/xpipe/core/process/OsType.java b/core/src/main/java/io/xpipe/core/process/OsType.java index 30992b951..30765336d 100644 --- a/core/src/main/java/io/xpipe/core/process/OsType.java +++ b/core/src/main/java/io/xpipe/core/process/OsType.java @@ -28,6 +28,8 @@ public interface OsType { } } + String makeFileSystemCompatible(String name); + List determineInterestingPaths(ShellControl pc) throws Exception; String getHomeDirectory(ShellControl pc) throws Exception; @@ -54,6 +56,11 @@ public interface OsType { final class Windows implements OsType, Local, Any { + @Override + public String makeFileSystemCompatible(String name) { + return name.replaceAll("[<>:\"/\\\\|?*]", "_").replaceAll("\\p{C}", ""); + } + @Override public List determineInterestingPaths(ShellControl pc) throws Exception { var home = getHomeDirectory(pc); @@ -116,6 +123,12 @@ public interface OsType { class Unix implements OsType { + @Override + public String makeFileSystemCompatible(String name) { + // Technically the backslash is supported, but it causes all kinds of troubles, so we also exclude it + return name.replaceAll("/\\\\", "_").replaceAll("\0", ""); + } + @Override public List determineInterestingPaths(ShellControl pc) throws Exception { var home = getHomeDirectory(pc); @@ -198,6 +211,12 @@ public interface OsType { final class MacOs implements OsType, Local, Any { + @Override + public String makeFileSystemCompatible(String name) { + // Technically the backslash is supported, but it causes all kinds of troubles, so we also exclude it + return name.replaceAll("[\\\\/:]", "_").replaceAll("\0", ""); + } + @Override public List determineInterestingPaths(ShellControl pc) throws Exception { var home = getHomeDirectory(pc); diff --git a/core/src/main/java/io/xpipe/core/process/ProcessControl.java b/core/src/main/java/io/xpipe/core/process/ProcessControl.java index d683fd08d..44edc59a8 100644 --- a/core/src/main/java/io/xpipe/core/process/ProcessControl.java +++ b/core/src/main/java/io/xpipe/core/process/ProcessControl.java @@ -1,7 +1,5 @@ package io.xpipe.core.process; -import io.xpipe.core.util.FailableFunction; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -17,7 +15,7 @@ public interface ProcessControl extends AutoCloseable { void resetData(boolean cache); String prepareTerminalOpen( - TerminalInitScriptConfig config, FailableFunction workingDirectory) + TerminalInitScriptConfig config, WorkingDirectoryFunction workingDirectory) throws Exception; void closeStdin() throws IOException; diff --git a/core/src/main/java/io/xpipe/core/process/ShellControl.java b/core/src/main/java/io/xpipe/core/process/ShellControl.java index 164660fd8..958c52dd5 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -23,7 +23,7 @@ public interface ShellControl extends ProcessControl { List getExitUuids(); - void setWorkingDirectory(FailableFunction workingDirectory); + void setWorkingDirectory(WorkingDirectoryFunction workingDirectory); Optional getSourceStore(); @@ -90,7 +90,7 @@ public interface ShellControl extends ProcessControl { String prepareIntermediateTerminalOpen( String content, TerminalInitScriptConfig config, - FailableFunction workingDirectory) + WorkingDirectoryFunction workingDirectory) throws Exception; FilePath getSystemTemporaryDirectory(); @@ -176,7 +176,7 @@ public interface ShellControl extends ProcessControl { @Override public CommandBuilder prepareWithoutInitCommand() { - return CommandBuilder.of().add(sc -> type.getLoginOpenCommand(sc)); + return CommandBuilder.of().addAll(sc -> type.getLaunchCommand().loginCommand(sc.getOsType())); } @Override @@ -194,7 +194,7 @@ public interface ShellControl extends ProcessControl { @Override public CommandBuilder prepareWithoutInitCommand() { - return CommandBuilder.of().add(sc -> sc.getShellDialect().getLoginOpenCommand(sc)); + return CommandBuilder.of().addAll(sc -> sc.getShellDialect().getLaunchCommand().loginCommand(sc.getOsType())); } @Override diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialect.java b/core/src/main/java/io/xpipe/core/process/ShellDialect.java index 3dae68186..b858cdc24 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialect.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialect.java @@ -132,14 +132,8 @@ public interface ShellDialect { return getPrintVariableCommand(name); } - String getOpenCommand(ShellControl shellControl); - CommandBuilder getOpenScriptCommand(String file); - default String getLoginOpenCommand(ShellControl shellControl) { - return getOpenCommand(shellControl); - } - default void prepareCommandForShell(CommandBuilder b) {} String prepareTerminalInitFileOpenCommand(ShellDialect parentDialect, ShellControl sc, String file); @@ -174,7 +168,7 @@ public interface ShellDialect { String clearDisplayCommand(); - String[] getLocalLaunchCommand(); + ShellLaunchCommand getLaunchCommand(); ShellDumbMode getDumbMode(); diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialects.java b/core/src/main/java/io/xpipe/core/process/ShellDialects.java index 1767e14c6..f4c4f95d6 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialects.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialects.java @@ -23,6 +23,7 @@ public class ShellDialects { public static ShellDialect CSH; public static ShellDialect FISH; + public static ShellDialect UNSUPPORTED; public static ShellDialect CISCO; public static ShellDialect MIKROTIK; public static ShellDialect RBASH; @@ -30,7 +31,7 @@ public class ShellDialects { public static List getStartableDialects() { return ALL.stream() - .filter(dialect -> dialect.getOpenCommand(null) != null) + .filter(dialect -> dialect.getLaunchCommand() != null) .toList(); } @@ -73,20 +74,11 @@ public class ShellDialects { CSH = byId("csh"); ASH = byId("ash"); SH = byId("sh"); + UNSUPPORTED = byId("unsupported"); CISCO = byId("cisco"); MIKROTIK = byId("mikrotik"); RBASH = byId("rbash"); OVH_BASTION = byId("ovhBastion"); } - - @Override - public boolean requiresFullDaemon() { - return false; - } - - @Override - public boolean prioritizeLoading() { - return true; - } } } diff --git a/core/src/main/java/io/xpipe/core/process/ShellLaunchCommand.java b/core/src/main/java/io/xpipe/core/process/ShellLaunchCommand.java new file mode 100644 index 000000000..f69d23cec --- /dev/null +++ b/core/src/main/java/io/xpipe/core/process/ShellLaunchCommand.java @@ -0,0 +1,17 @@ +package io.xpipe.core.process; + +import java.util.List; + +public interface ShellLaunchCommand { + + List localCommand(); + + default String loginCommand() { + return String.join(" ", loginCommand(null)); + } + + List loginCommand(OsType.Any os); + + List openCommand(); + +} diff --git a/core/src/main/java/io/xpipe/core/process/WorkingDirectoryFunction.java b/core/src/main/java/io/xpipe/core/process/WorkingDirectoryFunction.java new file mode 100644 index 000000000..0e5c9376a --- /dev/null +++ b/core/src/main/java/io/xpipe/core/process/WorkingDirectoryFunction.java @@ -0,0 +1,70 @@ +package io.xpipe.core.process; + +import io.xpipe.core.store.FilePath; +import io.xpipe.core.util.FailableFunction; + +public interface WorkingDirectoryFunction { + + static WorkingDirectoryFunction of(FailableFunction path) { + return new WorkingDirectoryFunction() { + @Override + public boolean isFixed() { + return false; + } + + @Override + public boolean isSpecified() { + return true; + } + + @Override + public FilePath apply(ShellControl shellControl) throws Exception { + return path.apply(shellControl); + } + }; + } + + static WorkingDirectoryFunction fixed(FilePath path) { + return new WorkingDirectoryFunction() { + @Override + public boolean isFixed() { + return true; + } + + @Override + public boolean isSpecified() { + return true; + } + + @Override + public FilePath apply(ShellControl shellControl) { + return path; + } + }; + } + + static WorkingDirectoryFunction none() { + return new WorkingDirectoryFunction() { + @Override + public boolean isFixed() { + return true; + } + + @Override + public boolean isSpecified() { + return false; + } + + @Override + public FilePath apply(ShellControl shellControl) { + return null; + } + }; + } + + boolean isFixed(); + + boolean isSpecified(); + + FilePath apply(ShellControl shellControl) throws Exception; +} diff --git a/core/src/main/java/io/xpipe/core/store/FilePath.java b/core/src/main/java/io/xpipe/core/store/FilePath.java index 61228982b..331c31d61 100644 --- a/core/src/main/java/io/xpipe/core/store/FilePath.java +++ b/core/src/main/java/io/xpipe/core/store/FilePath.java @@ -1,15 +1,26 @@ package io.xpipe.core.store; +import io.xpipe.core.process.OsType; import lombok.EqualsAndHashCode; import lombok.NonNull; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; @EqualsAndHashCode public final class FilePath { + public static boolean isProbableFilePath(OsType osType, String s) { + if (osType.equals(OsType.WINDOWS) && s.length() >= 2 && s.charAt(1) == ':') { + return true; + } + + return s.startsWith("/"); + } + @NonNull private final String value; @@ -23,6 +34,40 @@ public final class FilePath { } } + public FilePath fileSystemCompatible(OsType osType) { + var split = split(); + var needsReplacement = split.stream().anyMatch(s -> !s.equals(osType.makeFileSystemCompatible(s))); + if (!needsReplacement) { + return this; + } + + var backslash = value.contains("\\"); + var p = Pattern.compile("[^/\\\\]+"); + var m = p.matcher(value); + var replaced = m.replaceAll(matchResult -> osType.makeFileSystemCompatible(matchResult.group())); + return new FilePath(replaced); + } + + public FilePath getRoot() { + if (value.startsWith("/")) { + return new FilePath("/"); + } else if (value.length() >= 2 && value.charAt(1) == ':') { + // Without the trailing slash, many programs struggle with this + return new FilePath(value.substring(0, 2) + "\\"); + } else if (value.startsWith("\\\\")) { + var split = split(); + if (split.size() > 0) { + return new FilePath("\\\\" + split.getFirst()); + } + } + + throw new IllegalArgumentException("Unable to determine root of " + value); + } + + public Path toLocalPath() { + return Path.of(value); + } + public String toString() { return value; } @@ -102,7 +147,7 @@ public final class FilePath { public FilePath join(String... parts) { var joined = String.join("/", parts); - return new FilePath(value + "/" + joined); + return new FilePath(value + "/" + joined).normalize(); } public boolean isAbsolute() { diff --git a/core/src/main/java/io/xpipe/core/store/LaunchableStore.java b/core/src/main/java/io/xpipe/core/store/LaunchableStore.java index 234429453..b0a5b3e77 100644 --- a/core/src/main/java/io/xpipe/core/store/LaunchableStore.java +++ b/core/src/main/java/io/xpipe/core/store/LaunchableStore.java @@ -1,12 +1,6 @@ package io.xpipe.core.store; -import io.xpipe.core.process.ProcessControl; - public interface LaunchableStore extends DataStore { - default boolean canLaunch() { - return true; - } - - ProcessControl prepareLaunchCommand() throws Exception; + default void launch() throws Exception {} } diff --git a/core/src/main/java/io/xpipe/core/store/ShellStore.java b/core/src/main/java/io/xpipe/core/store/ShellStore.java index 51cdc2ce4..3d249b9ed 100644 --- a/core/src/main/java/io/xpipe/core/store/ShellStore.java +++ b/core/src/main/java/io/xpipe/core/store/ShellStore.java @@ -14,7 +14,6 @@ public interface ShellStore extends DataStore, LaunchableStore, FileSystemStore, return new ConnectionFileSystem(control(), this); } - @Override default ProcessControl prepareLaunchCommand() { return control(); } diff --git a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java index 1be9e5e63..216c97ec1 100644 --- a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java +++ b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java @@ -5,19 +5,10 @@ import java.util.function.Consumer; public interface ModuleLayerLoader { - static void loadAll( - ModuleLayer layer, boolean hasDaemon, boolean prioritization, Consumer errorHandler) { + static void loadAll(ModuleLayer layer, Consumer errorHandler) { ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> { var instance = moduleLayerLoaderProvider.get(); try { - if (instance.requiresFullDaemon() && !hasDaemon) { - return; - } - - if (instance.prioritizeLoading() != prioritization) { - return; - } - instance.init(layer); } catch (Throwable t) { errorHandler.accept(t); @@ -25,9 +16,7 @@ public interface ModuleLayerLoader { }); } - void init(ModuleLayer layer); + default void init(ModuleLayer layer) {} - boolean requiresFullDaemon(); - - boolean prioritizeLoading(); + default void reset() {} } diff --git a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java index 8aee357ec..c5a4083b1 100644 --- a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java +++ b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java @@ -295,6 +295,22 @@ public class XPipeInstallation { return path; } + public static Path getLangPath() { + if (!ModuleHelper.isImage()) { + return getCurrentInstallationBasePath().resolve("lang"); + } + + var install = getCurrentInstallationBasePath(); + var type = OsType.getLocal(); + if (type.equals(OsType.WINDOWS)) { + return install.resolve("app").resolve("lang"); + } else if (type.equals(OsType.LINUX)) { + return install.resolve("app").resolve("lang"); + } else { + return install.resolve("Contents").resolve("Resources").resolve("lang"); + } + } + public static Path getBundledFontsPath() { if (!ModuleHelper.isImage()) { return Path.of("dist", "fonts"); diff --git a/dist/base.gradle b/dist/base.gradle index 1530d6eaf..bb3f0aebd 100644 --- a/dist/base.gradle +++ b/dist/base.gradle @@ -30,6 +30,10 @@ if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { from "$projectDir/fonts" into "$distDir/base/app/fonts" } + copy { + from "$rootDir/lang" + into "$distDir/base/app/lang" + } def debugArguments = file("$projectDir/debug/debug_arguments.txt").text.lines().map(s -> '"' + s + '"').collect(Collectors.joining( ' ')) @@ -91,6 +95,10 @@ if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { from "$projectDir/fonts" into "$distDir/base/app/fonts" } + copy { + from "$rootDir/lang" + into "$distDir/base/app/lang" + } // Fixes a JPackage bug copy { @@ -183,6 +191,11 @@ if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { from "$projectDir/bundled_bin/$platformName" into "$distDir/$app/Contents/Resources/bundled" } + copy { + from "$rootDir/lang" + into "$distDir/$app/Contents/Resources/lang" + } + copy { from "$projectDir/PkgInstaller/darwin/Resources/uninstall.sh" diff --git a/dist/build.gradle b/dist/build.gradle index 22f199b12..dbea9df0a 100644 --- a/dist/build.gradle +++ b/dist/build.gradle @@ -91,6 +91,7 @@ if (rootProject.fullVersion) { apply from: 'choco.gradle' apply from: 'winget.gradle' apply from: 'install.gradle' + apply from: 'i18n.gradle' signing { useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) diff --git a/dist/changelogs/9.0.md b/dist/changelogs/9.0.md new file mode 100644 index 000000000..7fd529925 --- /dev/null +++ b/dist/changelogs/9.0.md @@ -0,0 +1,57 @@ +## Translations + +XPipe 9 now comes with many translations for the user interface. These were initially generated with DeepL and can be easily improved and corrected by anyone on GitHub. You can check them out in action and if there is any translation you don't like, submit a quick pull request to fix it. For instructions on how to do this, see https://github.com/xpipe-io/xpipe/lang. + +## VNC support + +This release comes with initial support for VNC. Any VNC connections are fully handled over automatic SSH tunnels and can therefore be established on top of any existing SSH connection you have in XPipe. + +Note that this feature right now is in an early stage and open for feedback. + +## RDP launcher + +RDP is a much more complex protocol than VNC, so for now RDP support is not built-in. It is instead realized similar to the terminal support, i.e. by launching your preferred RDP client with the connection information. The general implementation is also subject to change . + +Note that this feature right now is in an early stage and open for feedback. + +## SSH connection improvements + +- The custom SSH connections now properly apply all configuration options of your user configuration file. + +- There is now support defining multiple host entries in place in a custom SSH connection. This is useful for cases where you want to use ProxyJump hosts in place without having to define them elsewhere. + +- The connection establishment has been reworked to reduce the amount of double prompts, e.g. for smartcards of 2FA, where user input is required twice. + +- There's now an option to not let XPipe interact with the system. In case a system that does not run a known command shell, e.g. a router, link, or some IOT device, XPipe was previously unable to detect the shell type and errored out after some time. This option fixes this problem. + +- Any value specified for the `RemoteCommand` config option will now be properly applied when launching a terminal. This allows you to still use your preexisting init command setup, e.g. with tmux. + +## SSH X11 Forwarding + +You can now enable X11 forwarding for an SSH connection. + +XPipe allows you to use the WSL2 X11 capabilities on Windows for your SSH connection. The only thing you need for this is a [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) distribution installed on your local system. XPipe it will automatically choose a compatible installed distribution if possible, but you can also use another one in the settings menu. + +This means that you don't need to install a separate X11 server on Windows. However, if you are using one anyway, XPipe will detect that and use the currently running X11 server. + +## Terminal improvements + +The terminal integrations have been reworked across the board. To better show which terminals are well supported and which aren't, there is now a status indicator for every available terminal. This will show you how good the XPipe integration with each one is and which terminals are recommended to be used with XPipe. + +Furthermore, the kitty terminal is now fully supported with tabs on both Linux and macOS. + +## Improved keyboard control + +It is a goal to be able to use XPipe only with a keyboard. This can be done either for productivity reasons or for accessibility reasons. XPipe 9 introduces improved keyboard support with new shortcuts and improved focus control for navigating with the arrow keys, tab, space, and enter. + +## Improved logo + +The application logo has been improved with of regards to contrast and visibility, which often was a problem on dark backgrounds. It should now stand out on any background color. + +## Other changes + +- Fix macOS app failing to automatically restart after update +- The window title will now reflect which edition you use +- Fix file names not being properly adjusted when transferred across file systems and some characters were not supported on the target system +- Fix macOS desktop shortcuts not having an icon associated with them +- Upgrade to GraalVM 22 diff --git a/dist/licenses/vernacular-vnc.license b/dist/licenses/vernacular-vnc.license new file mode 100644 index 000000000..9b4ca945a --- /dev/null +++ b/dist/licenses/vernacular-vnc.license @@ -0,0 +1,19 @@ +Copyright (c) 2018 ShinyHut Solutions Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dist/licenses/vernacular-vnc.properties b/dist/licenses/vernacular-vnc.properties new file mode 100644 index 000000000..33c6bc829 --- /dev/null +++ b/dist/licenses/vernacular-vnc.properties @@ -0,0 +1,4 @@ +name=Vernacular VNC +version=1.17 +license=MIT License +link=https://github.com/shinyhut/vernacular-vnc \ No newline at end of file diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java index aec80275b..c4572d251 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java @@ -1,6 +1,6 @@ package io.xpipe.ext.base.action; -import io.xpipe.app.browser.BrowserModel; +import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.ext.ActionProvider; @@ -56,7 +56,7 @@ public class BrowseStoreAction implements ActionProvider { @Override public void execute() { - BrowserModel.DEFAULT.openFileSystemAsync(entry.ref(), null, new SimpleBooleanProperty()); + BrowserSessionModel.DEFAULT.openFileSystemAsync(entry.ref(), null, new SimpleBooleanProperty()); AppLayoutModel.get().selectBrowser(); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java index 874e2f9cb..178ca98bf 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java @@ -6,6 +6,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.TerminalLauncher; +import io.xpipe.core.store.DataStore; import io.xpipe.core.store.LaunchableStore; import io.xpipe.core.store.ShellStore; import io.xpipe.ext.base.script.ScriptStore; @@ -21,7 +22,7 @@ public class LaunchAction implements ActionProvider { @Override public DataStoreCallSite getDataStoreCallSite() { - return new DataStoreCallSite() { + return new DataStoreCallSite() { @Override public boolean canLinkTo() { @@ -29,27 +30,28 @@ public class LaunchAction implements ActionProvider { } @Override - public ActionProvider.Action createAction(DataStoreEntryRef store) { + public ActionProvider.Action createAction(DataStoreEntryRef store) { return new Action(store.get()); } @Override - public Class getApplicableClass() { - return LaunchableStore.class; + public Class getApplicableClass() { + return DataStore.class; } @Override - public boolean isApplicable(DataStoreEntryRef o) { - return o.get().getValidity().isUsable() && o.getStore().canLaunch(); + public boolean isApplicable(DataStoreEntryRef o) { + return o.get().getValidity().isUsable() && ( + o.getStore() instanceof LaunchableStore || o.get().getProvider().launchAction(o.get()) != null); } @Override - public ObservableValue getName(DataStoreEntryRef store) { + public ObservableValue getName(DataStoreEntryRef store) { return AppI18n.observable("launch"); } @Override - public String getIcon(DataStoreEntryRef store) { + public String getIcon(DataStoreEntryRef store) { return "mdi2p-play"; } }; @@ -57,21 +59,22 @@ public class LaunchAction implements ActionProvider { @Override public DefaultDataStoreCallSite getDefaultDataStoreCallSite() { - return new DefaultDataStoreCallSite() { + return new DefaultDataStoreCallSite() { @Override - public ActionProvider.Action createAction(DataStoreEntryRef store) { + public ActionProvider.Action createAction(DataStoreEntryRef store) { return new Action(store.get()); } @Override - public Class getApplicableClass() { - return LaunchableStore.class; + public Class getApplicableClass() { + return DataStore.class; } @Override - public boolean isApplicable(DataStoreEntryRef o) { - return o.get().getValidity().isUsable() && o.getStore().canLaunch(); + public boolean isApplicable(DataStoreEntryRef o) { + return o.get().getValidity().isUsable() && ( + o.getStore() instanceof LaunchableStore || o.get().getProvider().launchAction(o.get()) != null); } }; } @@ -95,12 +98,12 @@ public class LaunchAction implements ActionProvider { } if (entry.getStore() instanceof LaunchableStore s) { - var command = s.prepareLaunchCommand(); - if (command == null) { - return; - } + s.launch(); + return; + } - TerminalLauncher.open(entry, storeName, null, command); + if (entry.getProvider().launchAction(entry) != null) { + entry.getProvider().launchAction(entry).execute(); } } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchShortcutAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchShortcutAction.java deleted file mode 100644 index a0a7a27ba..000000000 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchShortcutAction.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.xpipe.ext.base.action; - -import io.xpipe.app.core.AppI18n; -import io.xpipe.app.ext.ActionProvider; -import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.storage.DataStoreEntryRef; -import io.xpipe.app.util.DesktopShortcuts; -import io.xpipe.core.store.LaunchableStore; -import javafx.beans.value.ObservableValue; -import lombok.Value; - -public class LaunchShortcutAction implements ActionProvider { - - @Override - public DataStoreCallSite getDataStoreCallSite() { - return new DataStoreCallSite() { - - @Override - public Action createAction(DataStoreEntryRef store) { - return new Action(store.get()); - } - - @Override - public Class getApplicableClass() { - return LaunchableStore.class; - } - - @Override - public ObservableValue getName(DataStoreEntryRef store) { - return AppI18n.observable("createShortcut"); - } - - @Override - public String getIcon(DataStoreEntryRef store) { - return "mdi2c-code-greater-than"; - } - }; - } - - @Value - static class Action implements ActionProvider.Action { - - DataStoreEntry entry; - - @Override - public boolean requiresJavaFXPlatform() { - return false; - } - - @Override - public void execute() throws Exception { - DesktopShortcuts.create("xpipe://launch/" + entry.getUuid().toString(), entry.getName()); - } - } -} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/XPipeUrlAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/XPipeUrlAction.java index c32c2eb99..f38d12fe8 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/XPipeUrlAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/XPipeUrlAction.java @@ -5,9 +5,7 @@ import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.util.TerminalLauncher; import io.xpipe.core.store.DataStore; -import io.xpipe.core.store.LaunchableStore; import io.xpipe.core.util.InPlaceSecretValue; import io.xpipe.core.util.JacksonMapper; import lombok.Value; @@ -43,7 +41,7 @@ public class XPipeUrlAction implements ActionProvider { if (!entry.getValidity().isUsable()) { return null; } - return new LaunchAction(entry); + return new LaunchAction.Action(entry); } case "action" -> { var id = args.get(1); @@ -87,30 +85,6 @@ public class XPipeUrlAction implements ActionProvider { } } - @Value - static class LaunchAction implements ActionProvider.Action { - - DataStoreEntry entry; - - @Override - public boolean requiresJavaFXPlatform() { - return false; - } - - @Override - public void execute() throws Exception { - var storeName = entry.getName(); - if (entry.getStore() instanceof LaunchableStore s) { - var command = s.prepareLaunchCommand(); - if (command == null) { - return; - } - - TerminalLauncher.open(storeName, command); - } - } - } - @Value static class AddStoreAction implements ActionProvider.Action { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java index 1a3c877a3..5b6a2ddca 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java @@ -1,8 +1,10 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -33,8 +35,8 @@ public class BackAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Back"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("back"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java index 5dd23c056..d6212caac 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java @@ -1,12 +1,14 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialect; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import java.util.List; @@ -58,11 +60,11 @@ public class BrowseInNativeManagerAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { return switch (OsType.getLocal()) { - case OsType.Windows windows -> "Browse in Windows Explorer"; - case OsType.Linux linux -> "Browse in default file manager"; - case OsType.MacOs macOs -> "Browse in Finder"; + case OsType.Windows windows -> AppI18n.observable("browseInWindowsExplorer"); + case OsType.Linux linux -> AppI18n.observable("browseInDefaultFileManager"); + case OsType.MacOs macOs -> AppI18n.observable("browseInFinder"); }; } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java index b64f5115e..4d8c958da 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java @@ -1,11 +1,14 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.OsType; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -24,8 +27,8 @@ public class ChmodAction implements BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Chmod"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("chmod"); } @Override @@ -55,8 +58,8 @@ public class ChmodAction implements BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return option; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return new SimpleStringProperty(option); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java index 084f1fac5..d88268b4c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java @@ -1,9 +1,11 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserClipboard; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -42,7 +44,7 @@ public class CopyAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Copy"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("copy"); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java index 9f866a43b..fd792d9a9 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java @@ -1,14 +1,17 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.ClipboardHelper; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileNames; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; @@ -29,8 +32,8 @@ public class CopyPathAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Copy location"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("copyLocation"); } @Override @@ -43,14 +46,13 @@ public class CopyPathAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return " " - + BrowserActionFormatter.centerEllipsis( - entries.getFirst().getRawFileEntry().getPath(), 50); + return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( + entries.getFirst().getRawFileEntry().getPath(), 50)); } - return "Absolute Paths"; + return AppI18n.observable("absolutePaths"); } @Override @@ -63,14 +65,13 @@ public class CopyPathAction implements BrowserAction, BranchAction { }, new LeafAction() { @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return " " - + BrowserActionFormatter.centerEllipsis( - entries.getFirst().getRawFileEntry().getPath(), 50); + return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( + entries.getFirst().getRawFileEntry().getPath(), 50)); } - return "Absolute Link Paths"; + return AppI18n.observable("absoluteLinkPaths"); } @Override @@ -95,15 +96,15 @@ public class CopyPathAction implements BrowserAction, BranchAction { }, new LeafAction() { @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return "\"" + return new SimpleObjectProperty<>("\"" + BrowserActionFormatter.centerEllipsis( entries.getFirst().getRawFileEntry().getPath(), 50) - + "\""; + + "\""); } - return "Absolute Paths (Quoted)"; + return AppI18n.observable("absolutePathsQuoted"); } @Override @@ -129,17 +130,15 @@ public class CopyPathAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return " " - + BrowserActionFormatter.centerEllipsis( - FileNames.getFileName(entries.getFirst() - .getRawFileEntry() - .getPath()), - 50); + return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( + FileNames.getFileName( + entries.getFirst().getRawFileEntry().getPath()), + 50)); } - return "File Names"; + return AppI18n.observable("fileNames"); } @Override @@ -153,17 +152,15 @@ public class CopyPathAction implements BrowserAction, BranchAction { }, new LeafAction() { @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return " " - + BrowserActionFormatter.centerEllipsis( - FileNames.getFileName(entries.getFirst() - .getRawFileEntry() - .getPath()), - 50); + return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( + FileNames.getFileName( + entries.getFirst().getRawFileEntry().getPath()), + 50)); } - return "Link File Names"; + return AppI18n.observable("linkFileNames"); } @Override @@ -195,18 +192,18 @@ public class CopyPathAction implements BrowserAction, BranchAction { }, new LeafAction() { @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { - return "\"" + return new SimpleObjectProperty<>("\"" + BrowserActionFormatter.centerEllipsis( FileNames.getFileName(entries.getFirst() .getRawFileEntry() .getPath()), 50) - + "\""; + + "\""); } - return "File Names (Quoted)"; + return AppI18n.observable("fileNamesQuoted"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java index f2b1fa34c..b5a86ea68 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java @@ -1,11 +1,13 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserAlerts; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.FileSystemHelper; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserAlerts; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.file.FileSystemHelper; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -43,9 +45,10 @@ public class DeleteAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Delete" - + (entries.stream() + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable( + "deleteFile", + entries.stream() .allMatch(browserEntry -> browserEntry.getRawFileEntry().getKind() == FileKind.LINK) ? " link" diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java index 47d316634..be7e0e62e 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.FileSystemHelper; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.file.FileSystemHelper; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -30,8 +32,8 @@ public class DeleteLinkAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Delete link"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("deleteLink"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java index 84591c684..50c1d7f8a 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java @@ -1,11 +1,13 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.FileOpener; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -31,9 +33,9 @@ public class EditFileAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { + public ObservableValue getName(OpenFileSystemModel model, List entries) { var e = AppPrefs.get().externalEditor().getValue(); - return "Edit with " + (e != null ? e.toTranslatedString().getValue() : "?"); + return AppI18n.observable("editWithEditor", e.toTranslatedString().getValue()); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java index 1705ae095..44363cc63 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BrowserAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.app.browser.icon.BrowserIcons; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java index 337f77747..6c2f92582 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileNames; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -30,8 +32,8 @@ public class FollowLinkAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Follow link"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("followLink"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java index 6179ac706..0aa860955 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java @@ -1,8 +1,10 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -33,8 +35,8 @@ public class ForwardAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Forward"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("goForward"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java index b8c10c902..12e13b85d 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java @@ -1,12 +1,14 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.MultiExecuteAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.ShellControl; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import java.util.List; @@ -18,8 +20,8 @@ public class JarAction extends MultiExecuteAction implements JavaAction, FileTyp } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "java -jar " + BrowserActionFormatter.filesArgument(entries); + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return new SimpleStringProperty("java -jar " + BrowserActionFormatter.filesArgument(entries)); } @Override @@ -29,7 +31,9 @@ public class JarAction extends MultiExecuteAction implements JavaAction, FileTyp @Override protected CommandBuilder createCommand(ShellControl sc, OpenFileSystemModel model, BrowserEntry entry) { - return CommandBuilder.of().add("java", "-jar").addFile(entry.getRawFileEntry().getPath()); + return CommandBuilder.of() + .add("java", "-jar") + .addFile(entry.getRawFileEntry().getPath()); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java index 2ecf3846a..2d30c0162 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.ToFileCommandAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import java.util.List; @@ -16,8 +18,8 @@ public class JavapAction extends ToFileCommandAction implements FileTypeAction, } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "javap -c -p " + BrowserActionFormatter.filesArgument(entries); + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return new SimpleStringProperty("javap -c -p " + BrowserActionFormatter.filesArgument(entries)); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java index f2da9b6e8..eb5a17411 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java @@ -1,16 +1,18 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIcons; import io.xpipe.app.comp.base.ModalOverlayComp; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.util.OptionsBuilder; import io.xpipe.core.process.OsType; import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.control.TextField; import org.kordamp.ikonli.javafx.FontIcon; @@ -35,8 +37,8 @@ public class NewItemAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "New"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("new"); } @Override @@ -76,8 +78,8 @@ public class NewItemAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "File"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("file"); } }, new LeafAction() { @@ -105,8 +107,8 @@ public class NewItemAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Directory"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("directory"); } }, new LeafAction() { @@ -137,8 +139,8 @@ public class NewItemAction implements BrowserAction, BranchAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Symbolic link"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("symbolicLink"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java index f1b9e60dd..b2e9e7dbc 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java @@ -1,9 +1,11 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -35,8 +37,8 @@ public class OpenDirectoryAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Open"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("open"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java index 4c00907f3..541be09ea 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java @@ -1,9 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.browser.session.BrowserSessionModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -13,11 +16,10 @@ public class OpenDirectoryInNewTabAction implements LeafAction { @Override public void execute(OpenFileSystemModel model, List entries) { - model.getBrowserModel() - .openFileSystemAsync( - model.getEntry(), - m -> entries.getFirst().getRawFileEntry().getPath(), - null); + if (model.getBrowserModel() instanceof BrowserSessionModel bm) { + bm.openFileSystemAsync( + model.getEntry(), m -> entries.getFirst().getRawFileEntry().getPath(), null); + } } @Override @@ -36,13 +38,14 @@ public class OpenDirectoryInNewTabAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Open in new tab"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("openInNewTab"); } @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return entries.size() == 1 + return model.getBrowserModel() instanceof BrowserSessionModel + && entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java index f56495a12..132fc2ec5 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.FileOpener; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -38,8 +40,8 @@ public class OpenFileDefaultAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Open with default application"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("openWithDefaultApplication"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java index 832126fd9..5a30be795 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java @@ -1,11 +1,13 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.FileOpener; import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -38,8 +40,8 @@ public class OpenFileWithAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Open with ..."; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("openFileWith"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java index c30caaf92..ea4519ad3 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java @@ -1,12 +1,14 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.LocalShell; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.store.FileNames; +import javafx.beans.value.ObservableValue; import java.util.List; @@ -70,8 +72,8 @@ public class OpenNativeFileDetailsAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Show details"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("showDetails"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java index cdfe1e673..f80fb474c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -50,8 +52,8 @@ public class OpenTerminalAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Open in terminal"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("openInTerminal"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java index 220a7c238..4c4051970 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java @@ -1,10 +1,12 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserClipboard; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -54,8 +56,8 @@ public class PasteAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Paste"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("paste"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java index 151007c7f..2afec70bb 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java @@ -1,8 +1,10 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -33,8 +35,8 @@ public class RefreshDirectoryAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Refresh"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("refresh"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java index 416e4e341..72883f5fe 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java @@ -1,9 +1,11 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -35,8 +37,8 @@ public class RenameAction implements LeafAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Rename"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("openWithDefaultApplication"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java index 70f79f750..4bc60f1ea 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java @@ -1,14 +1,16 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.MultiExecuteAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialects; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; +import javafx.beans.value.ObservableValue; import javafx.scene.Node; import org.kordamp.ikonli.javafx.FontIcon; @@ -61,8 +63,8 @@ public class RunAction extends MultiExecuteAction { } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "Run"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return AppI18n.observable("run"); } @Override @@ -71,6 +73,8 @@ public class RunAction extends MultiExecuteAction { } protected CommandBuilder createCommand(ShellControl sc, OpenFileSystemModel model, BrowserEntry entry) { - return CommandBuilder.of().add(sc.getShellDialect().runScriptCommand(sc, entry.getRawFileEntry().getPath())); + return CommandBuilder.of() + .add(sc.getShellDialect() + .runScriptCommand(sc, entry.getRawFileEntry().getPath())); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java index 962f9594c..2acc313e7 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java @@ -1,11 +1,13 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.BrowserEntry; -import io.xpipe.app.browser.OpenFileSystemModel; import io.xpipe.app.browser.action.ExecuteApplicationAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileNames; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.value.ObservableValue; import java.util.List; @@ -33,8 +35,8 @@ public class UnzipAction extends ExecuteApplicationAction implements FileTypeAct } @Override - public String getName(OpenFileSystemModel model, List entries) { - return "unzip [...]"; + public ObservableValue getName(OpenFileSystemModel model, List entries) { + return new SimpleStringProperty("unzip [...]"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java index 9aff81447..548b6c2bb 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java @@ -114,7 +114,9 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore, .mapToInt(value -> value.get().getName().hashCode() + value.getStore().hashCode()) .sum(); - var targetDir = ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts").join(proc.getShellDialect().getId()).toString(); + var targetDir = ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts") + .join(proc.getShellDialect().getId()) + .toString(); var hashFile = FileNames.join(targetDir, "hash"); var d = proc.getShellDialect(); if (d.createFileExistsCommand(proc, hashFile).executeAndCheck()) { @@ -136,7 +138,9 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore, for (DataStoreEntryRef scriptStore : refs) { var content = d.prepareScriptContent(scriptStore.getStore().getCommands()); - var fileName = scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_"); + var fileName = proc.getOsType() + .makeFileSystemCompatible( + scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_")); var scriptFile = FileNames.join(targetDir, fileName + "." + d.getScriptFileEnding()); d.createScriptTextFileWriteCommand(proc, content, scriptFile).execute(); } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/store/LaunchableTerminalStore.java b/ext/base/src/main/java/io/xpipe/ext/base/store/LaunchableTerminalStore.java new file mode 100644 index 000000000..8feb2ad24 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/store/LaunchableTerminalStore.java @@ -0,0 +1,16 @@ +package io.xpipe.ext.base.store; + +import io.xpipe.app.util.TerminalLauncher; +import io.xpipe.core.process.ProcessControl; +import io.xpipe.core.store.LaunchableStore; +import io.xpipe.ext.base.SelfReferentialStore; + +public interface LaunchableTerminalStore extends SelfReferentialStore, LaunchableStore { + + @Override + default void launch() throws Exception { + TerminalLauncher.open(getSelfEntry(), getSelfEntry().getName(), null, prepareLaunchCommand()); + } + + ProcessControl prepareLaunchCommand() throws Exception; +} diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_de.properties b/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_de.properties deleted file mode 100644 index d86dcac53..000000000 --- a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_de.properties +++ /dev/null @@ -1,3 +0,0 @@ -displayName=Mein Dateiformat -description=Meine Dateiformat-Beschreibung -fileName=Mein Dateiformat Datei \ No newline at end of file diff --git a/gradle/gradle_scripts/extension.gradle b/gradle/gradle_scripts/extension.gradle index 28c2c518e..7b60cc41e 100644 --- a/gradle/gradle_scripts/extension.gradle +++ b/gradle/gradle_scripts/extension.gradle @@ -8,6 +8,7 @@ // jar.dependsOn(copyRuntimeLibs) def dev = tasks.register('createDevOutput', Copy) { + dependsOn jar mustRunAfter jar if (project.allExtensions.contains(project)) { @@ -18,6 +19,10 @@ def dev = tasks.register('createDevOutput', Copy) { } jar.finalizedBy(dev) +project(':app').tasks.withType(JavaExec).configureEach { + dependsOn(dev) +} + tasks.register('createExtOutput', Copy) { mustRunAfter jar @@ -70,7 +75,7 @@ dependencies { exclude group: 'org.openjfx', module: 'javafx-base' exclude group: 'org.openjfx', module: 'javafx-controls' } - compileOnly 'commons-io:commons-io:2.15.1' + compileOnly 'commons-io:commons-io:2.16.1' compileOnly group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0" if (project != project(':base')) { diff --git a/gradle/gradle_scripts/vernacular-1.16.jar b/gradle/gradle_scripts/vernacular-1.16.jar new file mode 100644 index 0000000000000000000000000000000000000000..62fe1aa64ca7bf2f2398908b063c110890da0302 GIT binary patch literal 100150 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 literal 0 HcmV?d00001 diff --git a/lang/README.md b/lang/README.md new file mode 100644 index 000000000..4b65c50eb --- /dev/null +++ b/lang/README.md @@ -0,0 +1,39 @@ +# Translations + +This directory contains the translations for the strings and texts of the XPipe application. The original translations were created in english and initially translated automatically using [DeepL](https://www.deepl.com/en/translator). If you are interested in contributing to the translations, the main task is checking the automatically generated translations, which are pretty accurate most of the time. So you don't have to write long paragraphs, just perform occasional corrections. + +## How-to + +First of all, make sure that the language you want to contribute translations for is already set up here. If you don't find translations for your language in here, please create an issue in this repository and a maintainer will generate the initial automatic translations. This has to be done by a maintainer first as it requires a DeepL API subscription and some scripting. + +If your language exists in the translations, you can simply submit corrections via a pull request if you find strings that are wrong. + +### Correcting strings + +The strings in XPipe are located in one of the `.properties` files in the `strings` directories. The set of strings is constantly expanded and some existing strings are refined. Therefore, the translations are frequently regenerated/retranslated. If you want to correct a string, you have to mark it as custom to prevent it being overridden when the translations are updated. So a string in a translation like +``` +key=Wrong translation +``` +has to be transformed into +``` +#custom +key=Correct translation +``` +to mark it being a custom string that should be kept. + +### Correcting texts + +If you want to correct something in a text in a `.md` file, you don't have to do anything special as these are not being overwritten later on. Just perform and submit your changes. + +### Trying them out in action + +If you have cloned this repository, you can automatically run a developer build of XPipe by following the instructions in the [contribution guide](/CONTRIBUTING.md). This will use your modified translations, so you can see how they look and behave in practice. + +## Status + +Here you can see the current status of the translations. Verified means that these were proof-read and corrected by an actual human at a certain version. Later versions might introduce new strings that are not yet proof-read, this is why version information is included. + +| Language | Status | +|----------|----------------| +| English | Reference | +| German | Verified @ 9.0 | \ No newline at end of file diff --git a/lang/app/strings/fixed_en.properties b/lang/app/strings/fixed_en.properties new file mode 100644 index 000000000..ac98cef85 --- /dev/null +++ b/lang/app/strings/fixed_en.properties @@ -0,0 +1,59 @@ +cmd=cmd.exe +powershell=Powershell +pwsh=Powershell Core +windowsTerminal=Windows Terminal +windowsTerminalPreview=Windows Terminal Preview +gnomeTerminal=Gnome Terminal +createLock=Create lock +tilix=Tilix +wezterm=WezTerm +konsole=Konsole +xfce=Xfce 4 +elementaryTerminal=Elementary Terminal +macosTerminal=Terminal.app +iterm2=iTerm2 +warp=Warp +tabby=Tabby +alacritty=Alacritty +alacrittyMacOs=Alacritty +kittyMacOs=Kitty +bbedit=BBEdit +fleet=Fleet +intellij=IntelliJ IDEA +pycharm=PyCharm +webstorm=WebStorm +clion=CLion +tabbyMacOs=Tabby +notepad++=Notepad++ +notepad++Windows=Notepad++ +notepad++Linux=Notepad++ +notepad=Notepad +terminator=Terminator +kitty=Kitty +terminology=Terminology +coolRetroTerm=Cool Retro Term +guake=Guake +tilda=Tilda +xterm=XTerm +deepinTerminal=Deepin Terminal +qTerminal=QTerminal +vscode=Visual Studio Code +vscodium=VSCodium +vscodeInsiders=Visual Studio Code Insiders +kate=Kate +gedit=GEdit +gnomeTextEditor=Gnome Text Editor +leafpad=Leafpad +mousepad=Mousepad +pluma=Pluma +textEdit=Text Edit +sublime=Sublime Text +customTerminalPlaceholder=myterminal -e $CMD +customEditorPlaceholder=myeditor $FILE +nullPointer=Null Pointer +discord=Discord +slack=Slack +github=GitHub +mstsc=Microsoft Terminal Services Client (MSTSC) +remmina=Remmina +microsoftRemoteDesktopApp=Microsoft Remote Desktop.app diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties new file mode 100644 index 000000000..09a6356e2 --- /dev/null +++ b/lang/app/strings/translations_de.properties @@ -0,0 +1,436 @@ +delete=Löschen +rename=Umbenennen +properties=Eigenschaften +usedDate=Verwendet $DATE$ +openDir=Verzeichnis öffnen +sortLastUsed=Nach dem Datum der letzten Verwendung sortieren +sortAlphabetical=Alphabetisch nach Namen sortieren +restart=XPipe neu starten +restartDescription=Ein Neustart kann oft eine schnelle Lösung sein +reportIssue=Ein Problem melden +reportIssueDescription=Öffne den integrierten Issue Reporter +usefulActions=Nützliche Aktionen +stored=Gespeicherte +troubleshootingOptions=Werkzeuge zur Fehlersuche +troubleshoot=Fehlerbehebung +remote=Entfernte Datei +addShellStore=Shell hinzufügen ... +addShellTitle=Shell-Verbindung hinzufügen +savedConnections=Gespeicherte Verbindungen +save=Speichern +clean=Reinigen +refresh=Aktualisieren +#custom +moveTo=Kategorie ändern ... +addDatabase=Datenbank ... +browseInternalStorage=Internen Speicher durchsuchen +addTunnel=Tunnel ... +addScript=Skript ... +#custom +addHost=Remote Host ... +addShell=Shell-Umgebung ... +addCommand=Benutzerdefinierter Befehl ... +addAutomatically=Automatisch suchen ... +addOther=Andere hinzufügen ... +addConnection=Verbindung hinzufügen +skip=Überspringen +addConnections=Neu +selectType=Typ auswählen +selectTypeDescription=Verbindungstyp auswählen +selectShellType=Shell-Typ +selectShellTypeDescription=Wählen Sie den Typ der Shell-Verbindung +name=Name +storeIntroTitle=Verbindungs-Hub +storeIntroDescription=Hier kannst du alle deine lokalen und entfernten Shell-Verbindungen an einem Ort verwalten. Für den Anfang kannst du verfügbare Verbindungen schnell und automatisch erkennen und auswählen, welche du hinzufügen möchtest. +detectConnections=Suche nach Verbindungen +configuration=Konfiguration +dragAndDropFilesHere=Oder ziehe eine Datei einfach per Drag & Drop hierher +confirmDsCreationAbortTitle=Abbruch bestätigen +confirmDsCreationAbortHeader=Willst du die Erstellung der Datenquelle abbrechen? +confirmDsCreationAbortContent=Alle Fortschritte bei der Erstellung von Datenquellen gehen verloren. +confirmInvalidStoreTitle=Fehlgeschlagene Verbindung +confirmInvalidStoreHeader=Willst du die Verbindungsüberprüfung überspringen? +confirmInvalidStoreContent=Du kannst diese Verbindung hinzufügen, auch wenn sie nicht validiert werden konnte, und die Verbindungsprobleme später beheben. +#custom +none=Nichts +#custom +expand=Erweitern +accessSubConnections=Zugang zu Unterverbindungen +common=Allgemein +color=Farbe +alwaysConfirmElevation=Erlaubniserhöhung immer bestätigen +alwaysConfirmElevationDescription=Legt fest, wie mit Fällen umgegangen werden soll, in denen erhöhte Berechtigungen erforderlich sind, um einen Befehl auf einem System auszuführen, z. B. mit sudo.\n\nStandardmäßig werden alle sudo-Anmeldedaten während einer Sitzung zwischengespeichert und bei Bedarf automatisch bereitgestellt. Wenn diese Option aktiviert ist, wirst du jedes Mal aufgefordert, den erweiterten Zugriff zu bestätigen. +allow=Erlaube +ask=Frag +deny=Verweigern +share=Zum Git-Repository hinzufügen +unshare=Aus dem Git-Repository entfernen +remove=Entfernen +newCategory=Neue Unterkategorie +passwordManager=Passwort-Manager +prompt=Eingabeaufforderung +customCommand=Benutzerdefinierter Befehl +other=Andere +setLock=Sperre setzen +selectConnection=Verbindung auswählen +changeLock=Passphrase ändern +test=Test +lockCreationAlertTitle=Passphrase festlegen +lockCreationAlertHeader=Lege deine neue Master-Passphrase fest +#custom +finish=Fertigstellen +error=Ein Fehler ist aufgetreten +downloadStageDescription=Lädt Dateien auf deinen lokalen Rechner herunter, damit du sie per Drag & Drop in deine native Desktopumgebung ziehen kannst. +ok=Ok +search=Suche +newFile=Neue Datei +newDirectory=Neues Verzeichnis +passphrase=Passphrase +repeatPassphrase=Passphrase wiederholen +password=Passwort +unlockAlertTitle=Arbeitsbereich freischalten +unlockAlertHeader=Gib deine Tresor-Passphrase ein, um fortzufahren +enterLockPassword=Passwort für die Sperre eingeben +repeatPassword=Passwort wiederholen +askpassAlertTitle=Askpass +unsupportedOperation=Nicht unterstützte Operation: $MSG$ +fileConflictAlertTitle=Konflikt auflösen +fileConflictAlertHeader=Es ist ein Konflikt aufgetreten. Wie möchtest du vorgehen? +fileConflictAlertContent=Die Datei $FILE$ existiert bereits auf dem Zielsystem. +fileConflictAlertContentMultiple=Die Datei $FILE$ existiert bereits. Es kann weitere Konflikte geben, die du automatisch lösen kannst, indem du eine Option wählst, die für alle gilt. +moveAlertTitle=Umzug bestätigen +moveAlertHeader=Willst du die ($COUNT$) ausgewählten Elemente in $TARGET$ verschieben? +deleteAlertTitle=Bestätigung der Löschung +deleteAlertHeader=Willst du die ($COUNT$) ausgewählten Elemente löschen? +selectedElements=Ausgewählte Elemente: +mustNotBeEmpty=$VALUE$ darf nicht leer sein +valueMustNotBeEmpty=Der Wert darf nicht leer sein +transferDescription=Dateien zum Übertragen ablegen +dragFiles=Dateien im Browser ziehen +dragLocalFiles=Lokale Dateien von hier ziehen +null=$VALUE$ muss nicht null sein +roots=Wurzeln +scripts=Skripte +searchFilter=Suche ... +recent=Zuletzt +shortcut=Shortcut +browserWelcomeEmpty=Hier kannst du sehen, wo du beim letzten Mal aufgehört hast. +browserWelcomeSystems=Du warst vor kurzem mit den folgenden Systemen verbunden: +hostFeatureUnsupported=$FEATURE$ ist nicht auf dem Host installiert +missingStore=$NAME$ gibt es nicht +connectionName=Name der Verbindung +connectionNameDescription=Gib dieser Verbindung einen eigenen Namen +openFileTitle=Datei öffnen +unknown=Unbekannt +scanAlertTitle=Verbindungen hinzufügen +scanAlertChoiceHeader=Ziel +scanAlertChoiceHeaderDescription=Wähle aus, wo du nach Verbindungen suchen willst. Es wird zuerst nach allen verfügbaren Verbindungen gesucht. +scanAlertHeader=Verbindungsarten +scanAlertHeaderDescription=Wähle die Arten von Verbindungen aus, die du automatisch für das System hinzufügen möchtest. +noInformationAvailable=Keine Informationen verfügbar +localMachine=Lokale Maschine +yes=Ja +no=Nein +errorOccured=Ein Fehler ist aufgetreten +terminalErrorOccured=Ein Terminalfehler ist aufgetreten +errorTypeOccured=Eine Ausnahme des Typs $TYPE$ wurde ausgelöst +permissionsAlertTitle=Erforderliche Berechtigungen +permissionsAlertHeader=Für die Durchführung dieses Vorgangs sind zusätzliche Berechtigungen erforderlich. +permissionsAlertContent=Bitte folge dem Pop-up, um XPipe im Einstellungsmenü die erforderlichen Berechtigungen zu erteilen. +errorDetails=Details anzeigen +updateReadyAlertTitle=Update bereit +updateReadyAlertHeader=Ein Update auf die Version $VERSION$ ist bereit zur Installation +updateReadyAlertContent=Dadurch wird die neue Version installiert und XPipe neu gestartet, sobald die Installation abgeschlossen ist. +errorNoDetail=Es sind keine Fehlerdetails verfügbar +updateAvailableTitle=Update verfügbar +updateAvailableHeader=Ein XPipe-Update auf die Version $VERSION$ steht zur Installation bereit +updateAvailableContent=Auch wenn XPipe nicht gestartet werden konnte, kannst du versuchen, das Update zu installieren, um das Problem möglicherweise zu beheben. +clipboardActionDetectedTitle=Zwischenablage Aktion erkannt +clipboardActionDetectedHeader=Willst du den Inhalt deiner Zwischenablage importieren? +clipboardActionDetectedContent=XPipe hat einen Inhalt in deiner Zwischenablage entdeckt, der geöffnet werden kann. Willst du ihn jetzt öffnen? +install=Installieren ... +ignore=Ignorieren +possibleActions=Mögliche Aktionen +reportError=Fehler melden +reportOnGithub=Einen Fehlerbericht auf GitHub erstellen +reportOnGithubDescription=Eröffne ein neues Thema im GitHub-Repository +reportErrorDescription=Senden eines Fehlerberichts mit optionalem Benutzerfeedback und Diagnoseinformationen +ignoreError=Fehler ignorieren +ignoreErrorDescription=Ignoriere diesen Fehler und mach weiter, als wäre nichts passiert +provideEmail=Wie kann ich dich kontaktieren (optional, nur wenn du über Korrekturen benachrichtigt werden möchtest) +additionalErrorInfo=Zusätzliche Informationen bereitstellen (optional) +additionalErrorAttachments=Anhänge auswählen (optional) +dataHandlingPolicies=Datenschutzrichtlinie +sendReport=Bericht senden +errorHandler=Fehlerhandler +events=Ereignisse +method=Methode +validate=Validieren +stackTrace=Stack-Trace +previousStep=< Vorherige +nextStep=Weiter > +#custom +finishStep=Fertigstellen +edit=Bearbeiten +browseInternal=Intern durchsuchen +checkOutUpdate=Update auschecken +open=Öffnen +quit=Beenden +noTerminalSet=Es wurde keine Terminalanwendung automatisch eingestellt. Du kannst dies manuell im Einstellungsmenü tun. +connections=Verbindungen +settings=Einstellungen +explorePlans=Lizenz +help=Hilfe +#custom +about=Informationen +developer=Entwickler +browseFileTitle=Datei durchsuchen +browse=Durchsuchen +browser=Browser +selectFileFromComputer=Eine Datei von diesem Computer auswählen +links=Nützliche Links +website=Website +documentation=Dokumentation +discordDescription=Dem Discord-Server beitreten +security=Sicherheit +securityPolicy=Sicherheitsinformationen +securityPolicyDescription=Lies die detaillierte Sicherheitsrichtlinie +privacy=Datenschutzrichtlinie +privacyDescription=Lies die Datenschutzbestimmungen für die XPipe-Anwendung +slackDescription=Dem Slack-Arbeitsbereich beitreten +support=Unterstützung +githubDescription=Schau dir das GitHub-Repository an +openSourceNotices=Open-Source-Hinweise +xPipeClient=XPipe Desktop +checkForUpdates=Nach Updates suchen +checkForUpdatesDescription=Ein Update herunterladen, wenn es eins gibt +lastChecked=Zuletzt geprüft +version=Version +#custom +build=Build +runtimeVersion=Laufzeitversion +virtualMachine=Virtuelle Maschine +updateReady=Update installieren +updateReadyPortable=Update auschecken +updateReadyDescription=Ein Update wurde heruntergeladen und ist bereit zur Installation +updateReadyDescriptionPortable=Ein Update ist zum Download verfügbar +updateRestart=Neustart zur Aktualisierung +never=Niemals +updateAvailableTooltip=Update verfügbar +visitGithubRepository=GitHub Repository besuchen +updateAvailable=Update verfügbar: $VERSION$ +downloadUpdate=Update herunterladen +legalAccept=Ich akzeptiere die Endbenutzer-Lizenzvereinbarung +confirm=Bestätige +print=Drucken +whatsNew=Was ist neu in der Version $VERSION$ ($DATE$) +antivirusNoticeTitle=Ein Hinweis auf Antivirenprogramme +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Willkommen bei XPipe +gotIt=Verstanden +eula=Endbenutzer-Lizenzvertrag +news=Nachrichten +introduction=Einführung +privacyPolicy=Datenschutzrichtlinie +agree=Zustimmen +disagree=Widerspreche +directories=Verzeichnisse +logFile=Log-Datei +logFiles=Log-Dateien +logFilesAttachment=Log-Dateien +issueReporter=Fehlerberichterstatter +openCurrentLogFile=Log-Dateien +openCurrentLogFileDescription=Die Protokolldatei der aktuellen Sitzung öffnen +openLogsDirectory=Logs-Verzeichnis öffnen +installationFiles=Installationsdateien +openInstallationDirectory=Installationsdateien +openInstallationDirectoryDescription=XPipe-Installationsverzeichnis öffnen +launchDebugMode=Debug-Modus +launchDebugModeDescription=XPipe im Debug-Modus neu starten +extensionInstallTitle=Herunterladen +extensionInstallDescription=Diese Aktion erfordert zusätzliche Bibliotheken von Drittanbietern, die nicht von XPipe vertrieben werden. Du kannst sie hier automatisch installieren. Die Komponenten werden dann von der Website des Anbieters heruntergeladen: +extensionInstallLicenseNote=Durch das Herunterladen und die automatische Installation erklärst du dich mit den Bedingungen der Lizenzen von Drittanbietern einverstanden: +license=Lizenz +installRequired=Installation erforderlich +restore=Wiederherstellen +restoreAllSessions=Alle Sitzungen wiederherstellen +connectionTimeout=Zeitüberschreitung beim Verbindungsstart +connectionTimeoutDescription=Die Zeit in Sekunden, die auf eine Antwort gewartet wird, bevor eine Verbindung als beendet gilt. Wenn einige deiner Fernsysteme lange brauchen, um sich zu verbinden, kannst du versuchen, diesen Wert zu erhöhen. +useBundledTools=Gebündelte OpenSSH-Tools verwenden +useBundledToolsDescription=Verwende lieber die gebündelte Version des openssh-Clients als deine lokal installierte Version.\n\nDiese Version ist in der Regel aktueller als die auf deinem System mitgelieferte und unterstützt möglicherweise zusätzliche Funktionen. Damit entfällt auch die Notwendigkeit, diese Tools überhaupt erst zu installieren.\n\nErfordert einen Neustart zur Anwendung. +appearance=Erscheinungsbild +integrations=Integrationen +uiOptions=UI Optionen +theme=Thema +rdp=Remote-Desktop +rdpConfiguration=Konfiguration des Remote-Desktops +rdpClient=RDP-Client +rdpClientDescription=Das RDP-Client-Programm, das beim Starten von RDP-Verbindungen aufgerufen wird.\n\nBeachte, dass die verschiedenen Clients einen unterschiedlichen Grad an Fähigkeiten und Integrationen haben. Einige Clients unterstützen die automatische Übergabe von Passwörtern nicht, so dass du sie beim Start immer noch eingeben musst. +localShell=Lokale Shell +themeDescription=Dein bevorzugtes Anzeigethema +dontAutomaticallyStartVmSshServer=SSH-Server für VMs bei Bedarf nicht automatisch starten +dontAutomaticallyStartVmSshServerDescription=Jede Shell-Verbindung zu einer VM, die in einem Hypervisor läuft, wird über SSH hergestellt. XPipe kann bei Bedarf automatisch den installierten SSH-Server starten. Wenn du das aus Sicherheitsgründen nicht möchtest, kannst du dieses Verhalten mit dieser Option einfach deaktivieren. +confirmGitShareTitle=Bestätige die Git-Freigabe +confirmGitShareHeader=Dadurch wird die Datei in deinen Git-Datenspeicher kopiert und deine Änderungen werden übertragen. Willst du fortfahren? +gitShareFileTooltip=Füge die Datei zum Git Vault-Datenverzeichnis hinzu, damit sie automatisch synchronisiert wird.\n\nDiese Aktion kann nur verwendet werden, wenn der Git Tresor in den Einstellungen aktiviert ist. +performanceMode=Leistungsmodus +performanceModeDescription=Deaktiviert alle visuellen Effekte, die nicht benötigt werden, um die Leistung der Anwendung zu verbessern. +dontAcceptNewHostKeys=Neue SSH-Hostschlüssel nicht automatisch akzeptieren +dontAcceptNewHostKeysDescription=XPipe akzeptiert standardmäßig automatisch Host-Schlüssel von Systemen, für die dein SSH-Client noch keinen bekannten Host-Schlüssel gespeichert hat. Wenn sich jedoch ein bekannter Host-Schlüssel geändert hat, wird die Verbindung verweigert, bis du den neuen Schlüssel akzeptierst.\n\nWenn du dieses Verhalten deaktivierst, kannst du alle Host-Schlüssel überprüfen, auch wenn es zunächst keinen Konflikt gibt. +uiScale=UI-Skala +uiScaleDescription=Ein benutzerdefinierter Skalierungswert, der unabhängig von der systemweiten Anzeigeskala eingestellt werden kann. Die Werte sind in Prozent angegeben, d.h. ein Wert von 150 ergibt eine UI-Skalierung von 150%.\n\nZur Anwendung ist ein Neustart erforderlich. +editorProgram=Editor Programm +editorProgramDescription=Der Standard-Texteditor, der beim Bearbeiten von Textdaten aller Art verwendet wird. +windowOpacity=Fenster-Opazität +windowOpacityDescription=Ändert die Deckkraft des Fensters, um zu verfolgen, was im Hintergrund passiert. +useSystemFont=Systemschriftart verwenden +openDataDir=Verzeichnis der Tresordaten +openDataDirButton=Datenverzeichnis öffnen +openDataDirDescription=Wenn du zusätzliche Dateien, wie z.B. SSH-Schlüssel, systemübergreifend mit deinem Git-Repository synchronisieren möchtest, kannst du sie in das Verzeichnis Speicherdaten legen. Bei allen Dateien, die dort referenziert werden, werden die Dateipfade auf allen synchronisierten Systemen automatisch angepasst. +#custom +updates=Updates +passwordKey=Passwortschlüssel +selectAll=Alles auswählen +command=Befehl +advanced=Fortgeschrittene +thirdParty=Open-Source-Hinweise +eulaDescription=Lies die Endbenutzer-Lizenzvereinbarung für die XPipe-Anwendung +thirdPartyDescription=Die Open-Source-Lizenzen von Bibliotheken Dritter anzeigen +workspaceLock=Master-Passphrase +enableGitStorage=Git-Synchronisation einschalten +sharing=Teilen +sync=Synchronisation +enableGitStorageDescription=Wenn diese Option aktiviert ist, initialisiert XPipe ein Git-Repository für die Speicherung der Verbindungsdaten und überträgt alle Änderungen in dieses Repository. Beachte, dass dafür Git installiert sein muss und dass dies die Lade- und Speichervorgänge verlangsamen kann.\n\nAlle Kategorien, die synchronisiert werden sollen, müssen explizit als freigegeben gekennzeichnet werden.\n\nErfordert einen Neustart zur Anwendung. +storageGitRemote=Git Remote URL +storageGitRemoteDescription=Wenn diese Option aktiviert ist, zieht XPipe beim Laden automatisch alle Änderungen und überträgt sie beim Speichern in das entfernte Repository.\n\nSo kannst du deine Konfigurationsdaten zwischen mehreren XPipe-Installationen austauschen. Es werden sowohl HTTP- als auch SSH-URLs unterstützt. Beachte, dass dies die Lade- und Speichervorgänge verlangsamen kann.\n\nZur Anwendung ist ein Neustart erforderlich. +vault=Tresor +workspaceLockDescription=Legt ein benutzerdefiniertes Passwort fest, um alle in XPipe gespeicherten vertraulichen Informationen zu verschlüsseln.\n\nDies erhöht die Sicherheit, da es eine zusätzliche Verschlüsselungsebene für deine gespeicherten sensiblen Daten bietet. Du wirst dann beim Start von XPipe aufgefordert, das Passwort einzugeben. +useSystemFontDescription=Legt fest, ob die Systemschriftart oder die Roboto-Schriftart, die mit XPipe mitgeliefert wird, verwendet werden soll. +tooltipDelay=Tooltip-Verzögerung +tooltipDelayDescription=Die Anzahl der Millisekunden, die gewartet wird, bis ein Tooltip angezeigt wird. +fontSize=Schriftgröße +windowOptions=Fensteroptionen +saveWindowLocation=Speicherort des Fensters +saveWindowLocationDescription=Legt fest, ob die Fensterkoordinaten gespeichert und bei Neustarts wiederhergestellt werden sollen. +startupShutdown=Starten / Herunterfahren +showChildCategoriesInParentCategory=Unterkategorien in der übergeordneten Kategorie anzeigen +showChildCategoriesInParentCategoryDescription=Ob alle Verbindungen, die sich in Unterkategorien befinden, einbezogen werden sollen oder nicht, wenn eine bestimmte übergeordnete Kategorie ausgewählt wird.\n\nWenn diese Option deaktiviert ist, verhalten sich die Kategorien eher wie klassische Ordner, die nur ihren direkten Inhalt anzeigen, ohne Unterordner einzubeziehen. +condenseConnectionDisplay=Verbindungsanzeige verdichten +condenseConnectionDisplayDescription=Nimm für jede Verbindung der obersten Ebene weniger Platz in der Vertikalen ein, um die Verbindungsliste zu komprimieren. +enforceWindowModality=Fenstermodalität erzwingen +enforceWindowModalityDescription=Bewirkt, dass sekundäre Fenster, wie z. B. das Dialogfeld zum Herstellen einer Verbindung, alle Eingaben für das Hauptfenster blockieren, solange sie geöffnet sind. Das ist nützlich, wenn du manchmal falsch klickst. +openConnectionSearchWindowOnConnectionCreation=Fenster für die Verbindungssuche bei der Verbindungserstellung öffnen +openConnectionSearchWindowOnConnectionCreationDescription=Ob beim Hinzufügen einer neuen Shell-Verbindung automatisch das Fenster zur Suche nach verfügbaren Unterverbindungen geöffnet werden soll oder nicht. +workflow=Workflow +system=System +application=Anwendung +storage=Speicherung +runOnStartup=Beim Starten ausführen +closeBehaviour=Verhalten schließen +closeBehaviourDescription=Legt fest, wie XPipe beim Schließen des Hauptfensters vorgehen soll. +language=Sprache +languageDescription=Die zu verwendende Anzeigesprache.\n\nBeachte, dass die automatischen Übersetzungen als Grundlage dienen und von den Mitwirkenden manuell korrigiert und verbessert werden. Du kannst die Übersetzungsarbeit auch unterstützen, indem du Übersetzungsverbesserungen auf GitHub einreichst. +lightTheme=Licht-Thema +darkTheme=Dunkles Thema +exit=XPipe beenden +continueInBackground=Weiter im Hintergrund +minimizeToTray=In die Taskleiste minimieren +closeBehaviourAlertTitle=Schließverhalten einstellen +closeBehaviourAlertTitleHeader=Wähle aus, was beim Schließen des Fensters passieren soll. Alle aktiven Verbindungen werden geschlossen, wenn die Anwendung heruntergefahren wird. +startupBehaviour=Startverhalten +startupBehaviourDescription=Steuert das Standardverhalten der Desktop-Anwendung, wenn XPipe gestartet wird. +clearCachesAlertTitle=Cache säubern +clearCachesAlertTitleHeader=Willst du alle XPipe-Caches löschen? +clearCachesAlertTitleContent=Beachte, dass dadurch alle Daten gelöscht werden, die zur Verbesserung des Nutzererlebnisses gespeichert wurden. +startGui=GUI starten +startInTray=Start im Tray +startInBackground=Start im Hintergrund +clearCaches=Caches löschen ... +clearCachesDescription=Alle Cache-Daten löschen +apply=Anwenden +cancel=Abbrechen +notAnAbsolutePath=Kein absoluter Pfad +notADirectory=Nicht ein Verzeichnis +notAnEmptyDirectory=Kein leeres Verzeichnis +automaticallyUpdate=Nach Updates suchen +automaticallyUpdateDescription=Wenn diese Funktion aktiviert ist, werden Informationen über neue Versionen automatisch abgerufen, während XPipe läuft. Es wird kein Updater im Hintergrund ausgeführt, und du musst die Installation von Updates immer noch explizit bestätigen. +sendAnonymousErrorReports=Anonyme Fehlerberichte senden +sendUsageStatistics=Anonyme Nutzungsstatistiken senden +storageDirectory=Speicherverzeichnis +storageDirectoryDescription=Der Ort, an dem XPipe alle Verbindungsinformationen speichern soll. Diese Einstellung wird erst beim nächsten Neustart übernommen. Wenn du diese Einstellung änderst, werden die Daten aus dem alten Verzeichnis nicht in das neue kopiert. +logLevel=Log-Level +appBehaviour=Verhalten der Anwendung +logLevelDescription=Die Protokollstufe, die beim Schreiben von Protokolldateien verwendet werden sollte. +developerMode=Entwickler-Modus +developerModeDescription=Wenn diese Option aktiviert ist, hast du Zugriff auf eine Reihe von zusätzlichen Optionen, die für die Entwicklung nützlich sind. Nur aktiv nach einem Neustart. +editor=Editor +custom=Benutzerdefiniert +passwordManagerCommand=Passwortmanager-Befehl +passwordManagerCommandDescription=Der Befehl, der ausgeführt werden soll, um Passwörter abzurufen. Der Platzhalterstring $KEY wird beim Aufruf durch den zitierten Passwortschlüssel ersetzt. Dies sollte deinen Passwortmanager CLI aufrufen, um das Passwort auf stdout auszugeben, z. B. mypassmgr get $KEY.\n\nDu kannst den Schlüssel dann so einstellen, dass er immer dann abgefragt wird, wenn du eine Verbindung aufbaust, die ein Passwort erfordert. +passwordManagerCommandTest=Passwort-Manager testen +passwordManagerCommandTestDescription=Du kannst hier testen, ob die Ausgabe korrekt aussieht, wenn du einen Passwortmanager-Befehl eingerichtet hast. Der Befehl sollte nur das Passwort selbst auf stdout ausgeben, keine andere Formatierung sollte in der Ausgabe enthalten sein. +preferEditorTabs=Lieber neue Tabs öffnen +preferEditorTabsDescription=Legt fest, ob XPipe versuchen soll, neue Tabs in dem von dir gewählten Editor zu öffnen, anstatt neue Fenster zu öffnen.\n\nBeachte, dass nicht jeder Editor dies unterstützt. +customRdpClientCommand=Benutzerdefinierter Befehl +customRdpClientCommandDescription=Der Befehl, der ausgeführt werden soll, um den benutzerdefinierten RDP-Client zu starten.\n\nDer Platzhalter-String $FILE wird beim Aufruf durch den absoluten .rdp-Dateinamen in Anführungszeichen ersetzt. Vergiss nicht, den ausführbaren Pfad in Anführungszeichen zu setzen, wenn er Leerzeichen enthält. +customEditorCommand=Benutzerdefinierter Editor-Befehl +customEditorCommandDescription=Der Befehl, der ausgeführt werden muss, um den benutzerdefinierten Editor zu starten.\n\nDer Platzhalter-String $FILE wird beim Aufruf durch den absoluten Dateinamen in Anführungszeichen ersetzt. Denke daran, den ausführbaren Pfad deines Editors in Anführungszeichen zu setzen, wenn er Leerzeichen enthält. +editorReloadTimeout=Zeitüberschreitung beim Neuladen des Editors +editorReloadTimeoutDescription=Die Anzahl der Millisekunden, die gewartet wird, bevor eine Datei nach einer Aktualisierung gelesen wird. Dadurch werden Probleme vermieden, wenn dein Editor beim Schreiben oder Freigeben von Dateisperren langsam ist. +encryptAllVaultData=Alle Tresordaten verschlüsseln +encryptAllVaultDataDescription=Wenn diese Option aktiviert ist, wird jeder Teil der Verbindungsdaten im Tresor verschlüsselt, nicht nur die Geheimnisse in diesen Daten. Dies bietet eine zusätzliche Sicherheitsebene für andere Parameter wie Benutzernamen, Hostnamen usw., die im Tresor standardmäßig nicht verschlüsselt sind.\n\nDiese Option macht den Verlauf und die Diffs deines Git-Datenspeichers unbrauchbar, da du die ursprünglichen Änderungen nicht mehr sehen kannst, sondern nur noch die binären Änderungen. +vaultSecurity=Tresor-Sicherheit +developerDisableUpdateVersionCheck=Update-Versionsprüfung deaktivieren +developerDisableUpdateVersionCheckDescription=Legt fest, ob der Update-Checker die Versionsnummer bei der Suche nach einem Update ignorieren soll. +developerDisableGuiRestrictions=GUI-Einschränkungen deaktivieren +developerDisableGuiRestrictionsDescription=Steuert, ob bestimmte deaktivierte Aktionen noch über die Benutzeroberfläche ausgeführt werden können. +developerShowHiddenEntries=Versteckte Einträge anzeigen +developerShowHiddenEntriesDescription=Wenn aktiviert, werden versteckte und interne Datenquellen angezeigt. +developerShowHiddenProviders=Versteckte Anbieter anzeigen +developerShowHiddenProvidersDescription=Legt fest, ob versteckte und interne Verbindungs- und Datenquellenanbieter im Erstellungsdialog angezeigt werden sollen. +developerDisableConnectorInstallationVersionCheck=Connector-Versionsprüfung deaktivieren +developerDisableConnectorInstallationVersionCheckDescription=Legt fest, ob der Update-Checker die Versionsnummer ignoriert, wenn er die Version eines XPipe-Anschlusses prüft, der auf einem entfernten Computer installiert ist. +shellCommandTest=Shell-Befehlstest +shellCommandTestDescription=Führe einen Befehl in der Shell-Sitzung aus, die intern von XPipe verwendet wird. +terminal=Terminal +terminalEmulator=Terminal-Emulator +terminalConfiguration=Terminal-Konfiguration +editorConfiguration=Editor-Konfiguration +defaultApplication=Standardanwendung +terminalEmulatorDescription=Das Standardterminal, das beim Öffnen einer beliebigen Shell-Verbindung verwendet wird. Diese Anwendung wird nur zu Anzeigezwecken verwendet, das gestartete Shell-Programm hängt von der Shell-Verbindung selbst ab.\n\nDer Grad der Funktionsunterstützung ist von Terminal zu Terminal unterschiedlich, deshalb ist jedes Terminal entweder als empfohlen oder nicht empfohlen gekennzeichnet. Alle nicht empfohlenen Terminals funktionieren mit XPipe, haben aber möglicherweise keine Funktionen wie Tabs, Titelfarben, Shell-Unterstützung und mehr. Die besten Ergebnisse erzielst du, wenn du ein empfohlenes Terminal verwendest. +program=Programm +customTerminalCommand=Benutzerdefinierter Terminalbefehl +customTerminalCommandDescription=Der Befehl, der ausgeführt werden soll, um das benutzerdefinierte Terminal mit einem bestimmten Befehl zu öffnen.\n\nXPipe erstellt ein temporäres Launcher-Shell-Skript für dein Terminal, das ausgeführt wird. Die Platzhalterzeichenfolge $CMD in dem von dir angegebenen Befehl wird beim Aufruf durch das eigentliche Launcher-Skript ersetzt. Denke daran, den ausführbaren Pfad deines Terminals in Anführungszeichen zu setzen, wenn er Leerzeichen enthält. +clearTerminalOnInit=Terminal bei Init löschen +clearTerminalOnInitDescription=Wenn diese Funktion aktiviert ist, führt XPipe einen Löschbefehl aus, wenn eine neue Terminalsitzung gestartet wird, um unnötige Ausgaben zu entfernen. +enableFastTerminalStartup=Schnelles Starten des Terminals aktivieren +enableFastTerminalStartupDescription=Wenn diese Option aktiviert ist, wird versucht, Terminalsitzungen schneller zu starten, wenn dies möglich ist.\n\nDadurch werden einige Startprüfungen übersprungen und die angezeigten Systeminformationen nicht aktualisiert. Eventuelle Verbindungsfehler werden nur im Terminal angezeigt. +dontCachePasswords=Aufgeforderte Passwörter nicht zwischenspeichern +dontCachePasswordsDescription=Legt fest, ob abgefragte Kennwörter von XPipe intern zwischengespeichert werden sollen, damit du sie in der aktuellen Sitzung nicht erneut eingeben musst.\n\nWenn dieses Verhalten deaktiviert ist, musst du die abgefragten Anmeldedaten jedes Mal neu eingeben, wenn sie vom System verlangt werden. +denyTempScriptCreation=Temporäre Skripterstellung verweigern +denyTempScriptCreationDescription=Um einige seiner Funktionen zu realisieren, erstellt XPipe manchmal temporäre Shell-Skripte auf einem Zielsystem, um die einfache Ausführung einfacher Befehle zu ermöglichen. Diese enthalten keine sensiblen Informationen und werden nur zu Implementierungszwecken erstellt.\n\nWenn dieses Verhalten deaktiviert ist, erstellt XPipe keine temporären Dateien auf einem entfernten System. Diese Option ist in hochsicheren Kontexten nützlich, in denen jede Dateisystemänderung überwacht wird. Wenn diese Option deaktiviert ist, funktionieren einige Funktionen, z. B. Shell-Umgebungen und Skripte, nicht wie vorgesehen. +disableCertutilUse=Die Verwendung von certutil unter Windows deaktivieren +useLocalFallbackShell=Lokale Fallback-Shell verwenden +useLocalFallbackShellDescription=Wechsle zur Verwendung einer anderen lokalen Shell, um lokale Operationen durchzuführen. Das wäre die PowerShell unter Windows und die Bourne Shell auf anderen Systemen.\n\nDiese Option kann verwendet werden, wenn die normale lokale Standardshell deaktiviert oder in gewissem Maße beschädigt ist. Einige Funktionen funktionieren möglicherweise nicht wie erwartet, wenn diese Option aktiviert ist.\n\nZur Anwendung ist ein Neustart erforderlich. +disableCertutilUseDescription=Aufgrund verschiedener Unzulänglichkeiten und Bugs in cmd.exe werden temporäre Shell-Skripte mit certutil erstellt, indem es zur Dekodierung von base64-Eingaben verwendet wird, da cmd.exe bei Nicht-ASCII-Eingaben versagt. XPipe kann auch die PowerShell dafür verwenden, aber das ist langsamer.\n\nDadurch wird die Verwendung von certutil auf Windows-Systemen deaktiviert, um einige Funktionen zu realisieren und stattdessen auf die PowerShell zurückzugreifen. Das könnte einige AVs freuen, da einige von ihnen die Verwendung von certutil blockieren. +disableTerminalRemotePasswordPreparation=Terminal-Fernpasswortvorbereitung deaktivieren +disableTerminalRemotePasswordPreparationDescription=In Situationen, in denen eine Remote-Shell-Verbindung über mehrere Zwischensysteme im Terminal hergestellt werden soll, kann es erforderlich sein, alle erforderlichen Passwörter auf einem der Zwischensysteme vorzubereiten, um ein automatisches Ausfüllen der Eingabeaufforderungen zu ermöglichen.\n\nWenn du nicht möchtest, dass die Passwörter jemals an ein Zwischensystem übertragen werden, kannst du dieses Verhalten deaktivieren. Jedes erforderliche Zwischen-System-Passwort wird dann beim Öffnen des Terminals selbst abgefragt. +more=Mehr +translate=Übersetzungen +allConnections=Alle Verbindungen +allScripts=Alle Skripte +predefined=Vordefiniert +default=Standard +goodMorning=Guten Morgen +goodAfternoon=Guten Tag +goodEvening=Guten Abend +#custom +addVisual=Visuell ... +ssh=SSH +sshConfiguration=SSH-Konfiguration +size=Größe +attributes=Attribute +modified=Geändert +isOnlySupported=wird nur mit einer professionellen Lizenz unterstützt +areOnlySupported=werden nur mit einer professionellen Lizenz unterstützt +updateReadyTitle=Update auf $VERSION$ bereit diff --git a/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties b/lang/app/strings/translations_en.properties similarity index 55% rename from app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties rename to lang/app/strings/translations_en.properties index 202d35c5c..183b35ee7 100644 --- a/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties +++ b/lang/app/strings/translations_en.properties @@ -1,21 +1,283 @@ +delete=Delete +rename=Rename +properties=Properties +usedDate=Used $DATE$ +openDir=Open Directory +sortLastUsed=Sort by last used date +sortAlphabetical=Sort alphabetical by name +restart=Restart XPipe +restartDescription=A restart can often be a quick fix +reportIssue=Report an issue +reportIssueDescription=Open the integrated issue reporter +usefulActions=Useful actions +stored=Saved +troubleshootingOptions=Troubleshooting tools +troubleshoot=Troubleshoot +remote=Remote File +addShellStore=Add Shell ... +addShellTitle=Add Shell Connection +savedConnections=Saved Connections +save=Save +#context: verb +clean=Clean +refresh=Refresh +moveTo=Move to ... +addDatabase=Database ... +browseInternalStorage=Browse internal storage +addTunnel=Tunnel ... +addScript=Script ... +addHost=Remote Host ... +addShell=Shell Environment ... +addCommand=Custom Command ... +addAutomatically=Search Automatically ... +addOther=Add Other ... +addConnection=Add Connection +skip=Skip +addConnections=New +selectType=Select Type +selectTypeDescription=Select connection type +selectShellType=Shell Type +selectShellTypeDescription=Select the Type of the Shell Connection +name=Name +storeIntroTitle=Connection Hub +storeIntroDescription=Here you can manage all your local and remote shell connections in one place. To start off, you can quickly detect available connections automatically and choose which ones to add. +detectConnections=Search for connections +configuration=Configuration +dragAndDropFilesHere=Or just drag and drop a file here +confirmDsCreationAbortTitle=Confirm abort +confirmDsCreationAbortHeader=Do you want to abort the data source creation? +confirmDsCreationAbortContent=Any data source creation progress will be lost. +confirmInvalidStoreTitle=Failed connection +confirmInvalidStoreHeader=Do you want to skip connection validation? +confirmInvalidStoreContent=You can add this connection even if it could not be validated and fix the connection problems later on. +none=None +expand=Expand +accessSubConnections=Access sub connections +#context: noun, not rare +common=Common +color=Color +alwaysConfirmElevation=Always confirm permission elevation +alwaysConfirmElevationDescription=Controls how to handle cases when elevated permissions are required to run a command on a system, e.g. with sudo.\n\nBy default, any sudo credentials are cached during a session and automatically provided when needed. If this option is enabled, it will ask you to confirm the elevation access every time. +allow=Allow +ask=Ask +deny=Deny +share=Add to git repository +unshare=Remove from git repository +remove=Remove +newCategory=New subcategory +passwordManager=Password manager +prompt=Prompt +customCommand=Custom command +other=Other +setLock=Set lock +selectConnection=Select connection +changeLock=Change passphrase +test=Test +lockCreationAlertTitle=Set passphrase +lockCreationAlertHeader=Set your new master passphrase +#context: verb, exit +finish=Finish +error=An error occurred +downloadStageDescription=Downloads files to your local machine, so you can drag and drop them into your native desktop environment. +ok=Ok +search=Search +newFile=New file +newDirectory=New directory +passphrase=Passphrase +repeatPassphrase=Repeat passphrase +password=Password +unlockAlertTitle=Unlock workspace +unlockAlertHeader=Enter your vault passphrase to continue +enterLockPassword=Enter lock password +repeatPassword=Repeat password +askpassAlertTitle=Askpass +unsupportedOperation=Unsupported operation: $MSG$ +fileConflictAlertTitle=Resolve conflict +fileConflictAlertHeader=A conflict was encountered. How would you like to proceed? +fileConflictAlertContent=The file $FILE$ does already exist on the target system. +fileConflictAlertContentMultiple=The file $FILE$ already exists. There might be more conflicts that you can automatically resolve by choosing an option that applies to all. +moveAlertTitle=Confirm move +moveAlertHeader=Do you want to move the ($COUNT$) selected elements into $TARGET$? +deleteAlertTitle=Confirm deletion +deleteAlertHeader=Do you want to delete the ($COUNT$) selected elements? +selectedElements=Selected elements: +mustNotBeEmpty=$VALUE$ must not be empty +valueMustNotBeEmpty=Value must not be empty +transferDescription=Drop files to transfer +dragFiles=Drag files within browser +dragLocalFiles=Drag local files from here +null=$VALUE$ must be not null +roots=Roots +scripts=Scripts +searchFilter=Search ... +#context: last used +recent=Recent +shortcut=Shortcut +browserWelcomeEmpty=Here you will be able to see where you left off last time. +browserWelcomeSystems=You were recently connected to the following systems: +hostFeatureUnsupported=$FEATURE$ is not installed on the host +missingStore=$NAME$ does not exist +connectionName=Connection name +connectionNameDescription=Give this connection a custom name +openFileTitle=Open file +unknown=Unknown +scanAlertTitle=Add connections +scanAlertChoiceHeader=Target +scanAlertChoiceHeaderDescription=Choose where to search for connections. This will look for all available connections first. +scanAlertHeader=Connection types +scanAlertHeaderDescription=Select types of connections you want to automatically add for the system. +noInformationAvailable=No information available +localMachine=Local Machine +yes=Yes +no=No +errorOccured=An error occured +terminalErrorOccured=A terminal error occured +errorTypeOccured=An exception of type $TYPE$ was thrown +permissionsAlertTitle=Permissions required +permissionsAlertHeader=Additional permissions are required to perform this operation. +permissionsAlertContent=Please follow the pop-up to give XPipe the required permissions in the settings menu. +errorDetails=Show details +updateReadyAlertTitle=Update Ready +updateReadyAlertHeader=An update to version $VERSION$ is ready to be installed +updateReadyAlertContent=This will install the new version and restart XPipe once the installation finished. +errorNoDetail=No error details are available +updateAvailableTitle=Update Available +updateAvailableHeader=An XPipe update to version $VERSION$ is available to install +updateAvailableContent=Even though XPipe could not be started, you can attempt to install the update to potentially fix the issue. +clipboardActionDetectedTitle=Clipboard Action detected +clipboardActionDetectedHeader=Do you want to import your clipboard content? +clipboardActionDetectedContent=XPipe detected content in your clipboard that can be opened. Do you want to open it now? +install=Install ... +ignore=Ignore +possibleActions=Possible actions +reportError=Report error +reportOnGithub=Create an issue report on GitHub +reportOnGithubDescription=Open a new issue in the GitHub repository +reportErrorDescription=Send an error report with optional user feedback and diagnostics info +ignoreError=Ignore error +ignoreErrorDescription=Ignore this error and continue like nothing happened +provideEmail=How to contact you (optional, only if you want to get notified about fixes) +additionalErrorInfo=Provide additional information (optional) +additionalErrorAttachments=Select attachments (optional) +dataHandlingPolicies=Privacy policy +sendReport=Send report +errorHandler=Error handler +events=Events +method=Method +validate=Validate +stackTrace=Stack trace +previousStep=< Previous +nextStep=Next > +#context: verb, to complete a task +finishStep=Finish +edit=Edit +browseInternal=Browse Internal +checkOutUpdate=Check out update +open=Open +quit=Quit +noTerminalSet=No terminal application has been set automatically. You can do so manually in the settings menu. +connections=Connections +settings=Settings +explorePlans=License +help=Help +about=About +developer=Developer +browseFileTitle=Browse file +browse=Browse +browser=Browser +selectFileFromComputer=Select a file from this computer +links=Useful links +website=Website +documentation=Documentation +discordDescription=Join the Discord server +security=Security +securityPolicy=Security information +securityPolicyDescription=Read the detailed security policy +privacy=Privacy Policy +privacyDescription=Read the privacy policy for the XPipe application +slackDescription=Join the Slack workspace +support=Support +githubDescription=Check out the GitHub repository +openSourceNotices=Open Source Notices +xPipeClient=XPipe Desktop +checkForUpdates=Check for updates +checkForUpdatesDescription=Download an update if there is one +lastChecked=Last checked +version=Version +build=Build version +runtimeVersion=Runtime version +virtualMachine=Virtual machine +updateReady=Install update +updateReadyPortable=Check out update +updateReadyDescription=An update was downloaded and is ready to be installed +updateReadyDescriptionPortable=An update is available to download +updateRestart=Restart to update +never=Never +updateAvailableTooltip=Update available +visitGithubRepository=Visit GitHub repository +updateAvailable=Update available: $VERSION$ +downloadUpdate=Download update +legalAccept=I accept the End User License Agreement +#context: verb +confirm=Confirm +#context: verb +print=Print +whatsNew=What's new in version $VERSION$ ($DATE$) +antivirusNoticeTitle=A note on Antivirus programs +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Welcome to XPipe +#context: understood +gotIt=Got It +eula=End User License Agreement +news=News +introduction=Introduction +privacyPolicy=Privacy Policy +agree=Agree +disagree=Disagree +directories=Directories +logFile=Log File +logFiles=Log Files +logFilesAttachment=Log Files +#context: Error reporter +issueReporter=Issue Reporter +openCurrentLogFile=Log files +openCurrentLogFileDescription=Open the log file of the current session +openLogsDirectory=Open logs directory +installationFiles=Installation Files +openInstallationDirectory=Installation files +openInstallationDirectoryDescription=Open XPipe installation directory +launchDebugMode=Debug mode +launchDebugModeDescription=Restart XPipe in debug mode +extensionInstallTitle=Download +extensionInstallDescription=This action requires additional third party libraries that are not distributed by XPipe. You can automatically install them here. The components are then downloaded from the vendor website: +extensionInstallLicenseNote=By performing the download and automatic installation you agree to the terms of the third party licenses: +license=License +installRequired=Installation Required +restore=Restore +restoreAllSessions=Restore all sessions connectionTimeout=Connection start timeout connectionTimeoutDescription=The time in seconds to wait for a response before considering a connection to be timed out. If some of your remote systems take long to connect, you can try to increase this value. useBundledTools=Use bundled OpenSSH tools useBundledToolsDescription=Prefer to use bundled version of the openssh client instead of your locally installed one.\n\nThis version is usually more up-to-date than the ones shipped on your system and might support additional features. This also removes the requirement to have these tools installed in the first place.\n\nRequires restart to apply. -connections=Connections appearance=Appearance integrations=Integrations uiOptions=UI Options +#context: display theme theme=Theme +rdp=Remote desktop +rdpConfiguration=Remote desktop configuration +rdpClient=RDP client +rdpClientDescription=The RDP client program to call when launching RDP connections.\n\nNote that various clients have different degrees of abilities and integrations. Some clients don't support passing passwords automatically, so you still have to fill them in on launch. localShell=Local shell -themeDescription=You preferred theme +#context: display theme +themeDescription=Your preferred display theme dontAutomaticallyStartVmSshServer=Don't automatically start SSH server for VMs when needed dontAutomaticallyStartVmSshServerDescription=Any shell connection to a VM running in a hypervisor is made through SSH. XPipe can automatically start the installed SSH server when needed. If you don't want this for security reasons, then you can just disable this behavior with this option. confirmGitShareTitle=Confirm git sharing confirmGitShareHeader=This will copy the file into your git vault and commit your changes. Do you want to continue? gitShareFileTooltip=Add file to the git vault data directory so that it is automatically synced.\n\nThis action can only be used when the git vault is enabled in the settings. performanceMode=Performance mode -performanceModeDescription=Disables all visual effects that are not required to improve the application performance. +performanceModeDescription=Disables all visual effects that are not required in order to improve the application performance. dontAcceptNewHostKeys=Don't accept new SSH host keys automatically dontAcceptNewHostKeysDescription=XPipe will automatically accept host keys by default from systems where your SSH client has no known host key already saved. If any known host key has changed however, it will refuse to connect unless you accept the new one.\n\nDisabling this behavior allows you to check all host keys, even if there is no conflict initially. uiScale=UI Scale @@ -23,8 +285,6 @@ uiScaleDescription=A custom scaling value that can be set independently of your editorProgram=Editor Program editorProgramDescription=The default text editor to use when editing any kind of text data. windowOpacity=Window opacity -customTerminalPlaceholder=myterminal -e $CMD -customEditorPlaceholder=myeditor $FILE windowOpacityDescription=Changes the window opacity to keep track of what is happening in the background. useSystemFont=Use system font openDataDir=Vault data directory @@ -47,7 +307,7 @@ storageGitRemote=Git remote URL storageGitRemoteDescription=When set, XPipe will automatically pull any changes when loading and push any changes to the remote repository when saving.\n\nThis allows you to share your configuration data between multiple XPipe installations. Both HTTP and SSH URLs are supported. Note that this might slow down loading and saving operations.\n\nRequires a restart to apply. vault=Vault workspaceLockDescription=Sets a custom password to encrypt any sensitive information stored in XPipe.\n\nThis results in increased security as it provides an additional layer of encryption for your stored sensitive information. You will then be prompted to enter the password when XPipe starts. -useSystemFontDescription=Controls whether to use your system font or the default font used by XPipe (Roboto). +useSystemFontDescription=Controls whether to use your system font or the Roboto font which is bundled with XPipe. tooltipDelay=Tooltip delay tooltipDelayDescription=The amount of milliseconds to wait until a tooltip is displayed. fontSize=Font size @@ -66,14 +326,16 @@ openConnectionSearchWindowOnConnectionCreationDescription=Whether or not to auto workflow=Workflow system=System application=Application -updateToPrereleases=Include prereleases -updateToPrereleasesDescription=When enabled, the update check will also look for available prereleases in addition to full releases. storage=Storage runOnStartup=Run on startup +#context: setting closeBehaviour=Close behaviour closeBehaviourDescription=Controls how XPipe should proceed upon closing its main window. language=Language +languageDescription=The display language to use.\n\nNote that the translations use automatically generated translations as a base and are manually fixed and improved by contributors. You can also help the translation effort by submitting translation fixes on GitHub. +#context: display theme lightTheme=Light Theme +#context: display theme darkTheme=Dark Theme exit=Quit XPipe continueInBackground=Continue in background @@ -90,7 +352,6 @@ startInTray=Start in tray startInBackground=Start in background clearCaches=Clear caches ... clearCachesDescription=Delete all cache data -ok=OK apply=Apply cancel=Cancel notAnAbsolutePath=Not an absolute path @@ -115,6 +376,8 @@ passwordManagerCommandTest=Test password manager passwordManagerCommandTestDescription=You can test here whether the output looks correct if you have set up a password manager command. The command should only output the password itself to stdout, no other formatting should be included in the output. preferEditorTabs=Prefer to open new tabs preferEditorTabsDescription=Controls whether XPipe will try to open new tabs in your chosen editor instead of new windows.\n\nNote that not every editor supports this. +customRdpClientCommand=Custom command +customRdpClientCommandDescription=The command to execute to start the custom RDP client.\n\nThe placeholder string $FILE will be replaced by the quoted absolute .rdp file name when called. Remember to quote your executable path if it contains spaces. customEditorCommand=Custom editor command customEditorCommandDescription=The command to execute to start the custom editor.\n\nThe placeholder string $FILE will be replaced by the quoted absolute file name when called. Remember to quote your editor executable path if it contains spaces. editorReloadTimeout=Editor reload timeout @@ -122,13 +385,6 @@ editorReloadTimeoutDescription=The amount of milliseconds to wait before reading encryptAllVaultData=Encrypt all vault data encryptAllVaultDataDescription=When enabled, every part of the vault connection data will be encrypted as opposed to only secrets within in that data. This adds another layer of security for other parameters like usernames, hostnames, etc., that are not encrypted by default in the vault.\n\nThis option will render your git vault history and diffs useless as you can't see the original changes anymore, only binary changes. vaultSecurity=Vault security -securityPolicy=Security policy -notepad++=Notepad++ -notepad++Windows=Notepad++ -notepad++Linux=Notepad++ -notepad=Notepad -security=Security -developer=Developer developerDisableUpdateVersionCheck=Disable Update Version Check developerDisableUpdateVersionCheckDescription=Controls whether the update checker will ignore the version number when looking for an update. developerDisableGuiRestrictions=Disable GUI restrictions @@ -141,35 +397,15 @@ developerDisableConnectorInstallationVersionCheck=Disable Connector Version Chec developerDisableConnectorInstallationVersionCheckDescription=Controls whether the update checker will ignore the version number when inspecting the version of an XPipe connector installed on a remote machine. shellCommandTest=Shell Command Test shellCommandTestDescription=Run a command in the shell session used internally by XPipe. -konsole=Konsole -xfce=Xfce 4 -elementaryTerminal=Elementary Terminal -macosTerminal=Terminal.app -iterm2=iTerm2 -warp=Warp -tabby=Tabby -alacritty=Alacritty -alacrittyMacOs=Alacritty -kittyMacOs=Kitty -bbedit=BBEdit -fleet=Fleet -intellij=IntelliJ IDEA -pycharm=PyCharm -webstorm=WebStorm -clion=CLion -tabbyMacOs=Tabby terminal=Terminal terminalEmulator=Terminal emulator terminalConfiguration=Terminal configuration editorConfiguration=Editor configuration defaultApplication=Default application -terminalEmulatorDescription=The default terminal to use when opening any kind of shell connection. This application is only used for display purposes, the started shell program depends on the shell connection itself. +terminalEmulatorDescription=The default terminal to use when opening any kind of shell connection. This application is only used for display purposes, the started shell program depends on the shell connection itself.\n\nThe level of feature support varies by terminal, that is why each one is marked as either recommended or not recommended. All non-recommended terminals work with XPipe but might lack features like tabs, title colors, shell support, and more. Your user experience will be best when using a recommended terminal. program=Program customTerminalCommand=Custom terminal command customTerminalCommandDescription=The command to execute to open the custom terminal with a given command.\n\nXPipe will create a temporary launcher shell script for your terminal to execute. The placeholder string $CMD in the command you supply will be replaced by the actual launcher script when called. Remember to quote your terminal executable path if it contains spaces. -preferTerminalTabs=Prefer to open new tabs -preferTerminalTabsDisabled=Prefer to open new tabs.\n\nThe currently selected terminal $TERM$ does not support opening tabs from the CLI. -preferTerminalTabsDescription=Controls whether XPipe will try to open new tabs in your chosen terminal instead of new windows.\n\nNote that not every terminal supports this. clearTerminalOnInit=Clear terminal on init clearTerminalOnInitDescription=When enabled, XPipe will run a clear command when a new terminal session is launched to remove any unnecessary output. enableFastTerminalStartup=Enable fast terminal startup @@ -184,12 +420,22 @@ useLocalFallbackShellDescription=Switch to using another local shell to handle l disableCertutilUseDescription=Due to several shortcomings and bugs in cmd.exe, temporary shell scripts are created with certutil by using it to decode base64 input as cmd.exe breaks on non-ASCII input. XPipe can also use PowerShell for that but this will be slower.\n\nThis disables any use of certutil on Windows systems to realize some functionality and fall back to PowerShell instead. This might please some AVs as some of them block certutil usage. disableTerminalRemotePasswordPreparation=Disable terminal remote password preparation disableTerminalRemotePasswordPreparationDescription=In situations where a remote shell connection that goes through multiple intermediate systems should be established in the terminal, there might be a requirement to prepare any required passwords on one of the intermediate systems to allow for an automatic filling of any prompts.\n\nIf you don't want the passwords to ever be transferred to any intermediate system, you can disable this behavior. Any required intermediate password will then be queried in the terminal itself when opened. -cmd=cmd.exe -powershell=Powershell -pwsh=Powershell Core -windowsTerminal=Windows Terminal -windowsTerminalPreview=Windows Terminal Preview -gnomeTerminal=Gnome Terminal -createLock=Create lock -tilix=Tilix -wezterm=WezTerm +more=More +translate=Translations +allConnections=All connections +allScripts=All scripts +predefined=Predefined +default=Default +goodMorning=Good morning +goodAfternoon=Good afternoon +goodEvening=Good evening +addVisual=Visual ... +ssh=SSH +sshConfiguration=SSH Configuration +size=Size +attributes=Attributes +#context: title, last modified date +modified=Modified +isOnlySupported=is only supported with a professional license +areOnlySupported=are only supported with a professional license +updateReadyTitle=Update to $VERSION$ ready diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties new file mode 100644 index 000000000..cc75dbbc7 --- /dev/null +++ b/lang/app/strings/translations_es.properties @@ -0,0 +1,426 @@ +delete=Borrar +rename=Cambia el nombre de +properties=Propiedades +usedDate=Utilizado $DATE$ +openDir=Directorio abierto +sortLastUsed=Ordenar por fecha de último uso +sortAlphabetical=Ordenar alfabéticamente por nombre +restart=Reiniciar XPipe +restartDescription=Un reinicio a menudo puede ser una solución rápida +reportIssue=Informar de un problema +reportIssueDescription=Abre el notificador de incidencias integrado +usefulActions=Acciones útiles +stored=Guardado +troubleshootingOptions=Herramientas de solución de problemas +troubleshoot=Solucionar problemas +remote=Archivo remoto +addShellStore=Añadir Shell ... +addShellTitle=Añadir conexión Shell +savedConnections=Conexiones guardadas +save=Guardar +clean=Limpiar +refresh=Actualizar +moveTo=Pasar a ... +addDatabase=Base de datos ... +browseInternalStorage=Explorar el almacenamiento interno +addTunnel=Túnel ... +addScript=Script ... +addHost=Host remoto ... +addShell=Entorno Shell ... +addCommand=Comando personalizado ... +addAutomatically=Buscar automáticamente ... +addOther=Añadir otros ... +addConnection=Añadir conexión +skip=Saltar +addConnections=Nuevo +selectType=Seleccionar tipo +selectTypeDescription=Selecciona el tipo de conexión +selectShellType=Tipo de carcasa +selectShellTypeDescription=Selecciona el tipo de conexión Shell +name=Nombre +storeIntroTitle=Hub de conexión +storeIntroDescription=Aquí puedes gestionar todas tus conexiones shell locales y remotas en un solo lugar. Para empezar, puedes detectar rápidamente las conexiones disponibles de forma automática y elegir cuáles añadir. +detectConnections=Buscar conexiones +configuration=Configuración +dragAndDropFilesHere=O simplemente arrastra y suelta un archivo aquí +confirmDsCreationAbortTitle=Confirmar anulación +confirmDsCreationAbortHeader=¿Quieres abortar la creación de la fuente de datos? +confirmDsCreationAbortContent=Se perderá cualquier progreso en la creación de fuentes de datos. +confirmInvalidStoreTitle=Conexión fallida +confirmInvalidStoreHeader=¿Quieres omitir la validación de la conexión? +confirmInvalidStoreContent=Puedes añadir esta conexión aunque no se haya podido validar y solucionar los problemas de conexión más adelante. +none=Ninguno +expand=Expandir +accessSubConnections=Subconexiones de acceso +common=Común +color=Color +alwaysConfirmElevation=Confirma siempre la elevación del permiso +alwaysConfirmElevationDescription=Controla cómo manejar los casos en los que se requieren permisos elevados para ejecutar un comando en un sistema, por ejemplo, con sudo.\n\nPor defecto, cualquier credencial sudo se almacena en caché durante una sesión y se proporciona automáticamente cuando se necesita. Si esta opción está activada, te pedirá que confirmes el acceso elevado cada vez. +allow=Permitir +ask=Pregunta a +deny=Denegar +share=Añadir al repositorio git +unshare=Eliminar del repositorio git +remove=Elimina +newCategory=Nueva subcategoría +passwordManager=Gestor de contraseñas +prompt=Pregunta +customCommand=Comando personalizado +other=Otros +setLock=Fijar bloqueo +selectConnection=Seleccionar conexión +changeLock=Cambiar frase de contraseña +test=Prueba +lockCreationAlertTitle=Establecer frase de contraseña +lockCreationAlertHeader=Establece tu nueva frase de contraseña maestra +finish=Terminar +error=Se ha producido un error +downloadStageDescription=Descarga archivos a tu máquina local, para que puedas arrastrarlos y soltarlos en tu entorno de escritorio nativo. +ok=Ok +search=Busca en +newFile=Nuevo archivo +newDirectory=Nuevo directorio +passphrase=Frase de contraseña +repeatPassphrase=Repetir frase de contraseña +password=Contraseña +unlockAlertTitle=Desbloquear el espacio de trabajo +unlockAlertHeader=Introduce la contraseña de tu bóveda para continuar +enterLockPassword=Introducir contraseña de bloqueo +repeatPassword=Repetir contraseña +askpassAlertTitle=Askpass +unsupportedOperation=Operación no admitida: $MSG$ +fileConflictAlertTitle=Resolver un conflicto +fileConflictAlertHeader=Se ha producido un conflicto. ¿Cómo quieres proceder? +fileConflictAlertContent=El archivo $FILE$ ya existe en el sistema de destino. +fileConflictAlertContentMultiple=El archivo $FILE$ ya existe. Puede haber más conflictos que puedes resolver automáticamente eligiendo una opción que se aplique a todos. +moveAlertTitle=Confirmar movimiento +moveAlertHeader=¿Quieres mover los ($COUNT$) elementos seleccionados a $TARGET$? +deleteAlertTitle=Confirmar la eliminación +deleteAlertHeader=¿Quieres borrar los ($COUNT$) elementos seleccionados? +selectedElements=Elementos seleccionados: +mustNotBeEmpty=$VALUE$ no debe estar vacío +valueMustNotBeEmpty=El valor no debe estar vacío +transferDescription=Soltar archivos para transferir +dragFiles=Arrastrar archivos dentro del navegador +dragLocalFiles=Arrastra archivos locales desde aquí +null=$VALUE$ debe ser no nulo +roots=Raíces +scripts=Guiones +searchFilter=Busca ... +recent=Reciente +shortcut=Atajo +browserWelcomeEmpty=Aquí podrás ver dónde lo dejaste la última vez. +browserWelcomeSystems=Hace poco te conectaste a los siguientes sistemas: +hostFeatureUnsupported=$FEATURE$ no está instalado en el host +missingStore=$NAME$ no existe +connectionName=Nombre de la conexión +connectionNameDescription=Dale a esta conexión un nombre personalizado +openFileTitle=Abrir archivo +unknown=Desconocido +scanAlertTitle=Añadir conexiones +scanAlertChoiceHeader=Objetivo +scanAlertChoiceHeaderDescription=Elige dónde buscar las conexiones. Esto buscará primero todas las conexiones disponibles. +scanAlertHeader=Tipos de conexión +scanAlertHeaderDescription=Selecciona los tipos de conexiones que quieres añadir automáticamente para el sistema. +noInformationAvailable=No hay información disponible +localMachine=Máquina local +yes=Sí +no=No +errorOccured=Se ha producido un error +terminalErrorOccured=Se ha producido un error de terminal +errorTypeOccured=Se ha lanzado una excepción de tipo $TYPE$ +permissionsAlertTitle=Permisos necesarios +permissionsAlertHeader=Se necesitan permisos adicionales para realizar esta operación. +permissionsAlertContent=Por favor, sigue la ventana emergente para dar a XPipe los permisos necesarios en el menú de configuración. +errorDetails=Mostrar detalles +updateReadyAlertTitle=Actualizar listo +updateReadyAlertHeader=Una actualización a la versión $VERSION$ está lista para ser instalada +updateReadyAlertContent=Esto instalará la nueva versión y reiniciará XPipe una vez finalizada la instalación. +errorNoDetail=No hay detalles de error disponibles +updateAvailableTitle=Actualización disponible +updateAvailableHeader=Se puede instalar una actualización de XPipe a la versión $VERSION$ +updateAvailableContent=Aunque XPipe no se haya podido iniciar, puedes intentar instalar la actualización para solucionar potencialmente el problema. +clipboardActionDetectedTitle=Acción del portapapeles detectada +clipboardActionDetectedHeader=¿Quieres importar el contenido de tu portapapeles? +clipboardActionDetectedContent=XPipe ha detectado contenido en tu portapapeles que se puede abrir. ¿Quieres abrirlo ahora? +install=Instalar ... +ignore=Ignora +possibleActions=Acciones posibles +reportError=Informar de un error +reportOnGithub=Crear un informe de incidencia en GitHub +reportOnGithubDescription=Abre una nueva incidencia en el repositorio de GitHub +reportErrorDescription=Enviar un informe de error con comentarios opcionales del usuario e información de diagnóstico +ignoreError=Ignorar error +ignoreErrorDescription=Ignora este error y continúa como si no hubiera pasado nada +provideEmail=Cómo contactar contigo (opcional, sólo si quieres recibir notificaciones sobre correcciones) +additionalErrorInfo=Proporcionar información adicional (opcional) +additionalErrorAttachments=Selecciona archivos adjuntos (opcional) +dataHandlingPolicies=Política de privacidad +sendReport=Enviar informe +errorHandler=Gestor de errores +events=Eventos +method=Método +validate=Valida +stackTrace=Rastreo de pila +previousStep=< Anterior +nextStep=Siguiente +finishStep=Terminar +edit=Edita +browseInternal=Navegar internamente +checkOutUpdate=Comprueba la actualización +open=Abre +quit=Salir de +noTerminalSet=No se ha configurado automáticamente ninguna aplicación terminal. Puedes hacerlo manualmente en el menú de configuración. +connections=Conexiones +settings=Configuración +explorePlans=Licencia +help=Ayuda +about=Acerca de +developer=Desarrollador +browseFileTitle=Examinar archivo +browse=Navega por +browser=Navegador +selectFileFromComputer=Selecciona un archivo de este ordenador +links=Enlaces útiles +website=Página web +documentation=Documentación +discordDescription=Únete al servidor Discord +security=Seguridad +securityPolicy=Información de seguridad +securityPolicyDescription=Lee la política de seguridad detallada +privacy=Política de privacidad +privacyDescription=Lee la política de privacidad de la aplicación XPipe +slackDescription=Únete al espacio de trabajo Slack +support=Soporte +githubDescription=Consulta el repositorio GitHub +openSourceNotices=Avisos de código abierto +xPipeClient=XPipe Escritorio +checkForUpdates=Buscar actualizaciones +checkForUpdatesDescription=Descargar una actualización si la hay +lastChecked=Última comprobación +version=Versión +build=Versión de construcción +runtimeVersion=Versión en tiempo de ejecución +virtualMachine=Máquina virtual +updateReady=Instalar actualización +updateReadyPortable=Comprobar la actualización +updateReadyDescription=Se ha descargado una actualización y está lista para ser instalada +updateReadyDescriptionPortable=Se puede descargar una actualización +updateRestart=Reiniciar para actualizar +never=Nunca +updateAvailableTooltip=Actualización disponible +visitGithubRepository=Visita el repositorio GitHub +updateAvailable=Actualización disponible: $VERSION$ +downloadUpdate=Descargar actualización +legalAccept=Acepto el Acuerdo de Licencia de Usuario Final +confirm=Confirmar +print=Imprimir +whatsNew=Novedades de la versión $VERSION$ ($DATE$) +antivirusNoticeTitle=Una nota sobre los programas antivirus +updateChangelogAlertTitle=Registro de cambios +greetingsAlertTitle=Bienvenido a XPipe +gotIt=Entendido +eula=Acuerdo de licencia de usuario final +news=Noticias +introduction=Introducción +privacyPolicy=Política de privacidad +agree=Acuerda +disagree=En desacuerdo +directories=Directorios +logFile=Archivo de registro +logFiles=Archivos de registro +logFilesAttachment=Archivos de registro +issueReporter=Informador de incidencias +openCurrentLogFile=Archivos de registro +openCurrentLogFileDescription=Abrir el archivo de registro de la sesión actual +openLogsDirectory=Abrir directorio de registros +installationFiles=Archivos de instalación +openInstallationDirectory=Ficheros de instalación +openInstallationDirectoryDescription=Abre el directorio de instalación de XPipe +launchDebugMode=Modo depuración +launchDebugModeDescription=Reinicia XPipe en modo depuración +extensionInstallTitle=Descargar +extensionInstallDescription=Esta acción requiere bibliotecas adicionales de terceros que no distribuye XPipe. Puedes instalarlas automáticamente aquí. Los componentes se descargan del sitio web del proveedor: +extensionInstallLicenseNote=Al realizar la descarga y la instalación automática, aceptas los términos de las licencias de terceros: +license=Licencia +installRequired=Instalación necesaria +restore=Restaurar +restoreAllSessions=Restaurar todas las sesiones +connectionTimeout=Tiempo de espera de inicio de conexión +connectionTimeoutDescription=El tiempo en segundos que hay que esperar una respuesta antes de considerar que la conexión ha caducado. Si algunos de tus sistemas remotos tardan mucho en conectarse, puedes intentar aumentar este valor. +useBundledTools=Utilizar las herramientas OpenSSH incluidas +useBundledToolsDescription=Prefiere utilizar la versión incluida del cliente openssh en lugar de la que tengas instalada localmente.\n\nEsta versión suele estar más actualizada que la incluida en tu sistema y puede admitir funciones adicionales. Esto también elimina el requisito de tener instaladas estas herramientas en primer lugar.\n\nRequiere reiniciar para aplicarse. +appearance=Apariencia +integrations=Integraciones +uiOptions=Opciones de IU +theme=Tema +rdp=Escritorio remoto +rdpConfiguration=Configuración del escritorio remoto +rdpClient=Cliente RDP +rdpClientDescription=El programa cliente RDP al que llamar al iniciar conexiones RDP.\n\nTen en cuenta que los distintos clientes tienen diferentes grados de capacidades e integraciones. Algunos clientes no admiten la transmisión automática de contraseñas, por lo que tendrás que introducirlas al iniciar la conexión. +localShell=Shell local +themeDescription=Tu tema de visualización preferido +dontAutomaticallyStartVmSshServer=No iniciar automáticamente el servidor SSH para las máquinas virtuales cuando sea necesario +dontAutomaticallyStartVmSshServerDescription=Cualquier conexión shell a una máquina virtual que se ejecute en un hipervisor se realiza a través de SSH. XPipe puede iniciar automáticamente el servidor SSH instalado cuando sea necesario. Si no quieres esto por razones de seguridad, puedes desactivar este comportamiento con esta opción. +confirmGitShareTitle=Confirmar compartición git +confirmGitShareHeader=Esto copiará el archivo en tu almacén git y confirmará tus cambios. ¿Quieres continuar? +gitShareFileTooltip=Añade el archivo al directorio de datos de la bóveda git para que se sincronice automáticamente.\n\nEsta acción sólo puede utilizarse cuando la bóveda git está activada en los ajustes. +performanceMode=Modo de funcionamiento +performanceModeDescription=Desactiva todos los efectos visuales que no sean necesarios para mejorar el rendimiento de la aplicación. +dontAcceptNewHostKeys=No aceptar automáticamente nuevas claves de host SSH +dontAcceptNewHostKeysDescription=XPipe aceptará automáticamente por defecto claves de host de sistemas en los que su cliente SSH no tenga ya guardada ninguna clave de host conocida. Sin embargo, si alguna clave de host conocida ha cambiado, se negará a conectarse a menos que aceptes la nueva.\n\nDesactivar este comportamiento te permite comprobar todas las claves de host, aunque inicialmente no haya ningún conflicto. +uiScale=Escala de IU +uiScaleDescription=Un valor de escala personalizado que puede establecerse independientemente de la escala de visualización de todo el sistema. Los valores están en porcentaje, por lo que, por ejemplo, un valor de 150 dará como resultado una escala de interfaz de usuario del 150%.\n\nRequiere un reinicio para aplicarse. +editorProgram=Programa Editor +editorProgramDescription=El editor de texto predeterminado que se utiliza al editar cualquier tipo de datos de texto. +windowOpacity=Opacidad de la ventana +windowOpacityDescription=Cambia la opacidad de la ventana para controlar lo que ocurre en segundo plano. +useSystemFont=Utilizar la fuente del sistema +openDataDir=Directorio de datos de la bóveda +openDataDirButton=Directorio de datos abierto +openDataDirDescription=Si quieres sincronizar archivos adicionales, como claves SSH, entre sistemas con tu repositorio git, puedes ponerlos en el directorio de datos de almacenamiento. Cualquier archivo al que se haga referencia allí tendrá sus rutas de archivo adaptadas automáticamente en cualquier sistema sincronizado. +updates=Actualiza +passwordKey=Clave de acceso +selectAll=Seleccionar todo +command=Comando +advanced=Avanzado +thirdParty=Avisos de código abierto +eulaDescription=Lee el Contrato de Licencia de Usuario Final de la aplicación XPipe +thirdPartyDescription=Ver las licencias de código abierto de bibliotecas de terceros +workspaceLock=Frase maestra +enableGitStorage=Activar la sincronización git +sharing=Compartir +sync=Sincronización +enableGitStorageDescription=Cuando está activado, XPipe inicializará un repositorio git para el almacenamiento de datos de conexión y consignará en él cualquier cambio. Ten en cuenta que esto requiere que git esté instalado y puede ralentizar las operaciones de carga y guardado.\n\nLas categorías que deban sincronizarse deben designarse explícitamente como compartidas.\n\nRequiere un reinicio para aplicarse. +storageGitRemote=URL remota de Git +storageGitRemoteDescription=Cuando se establece, XPipe extraerá automáticamente cualquier cambio al cargar y empujará cualquier cambio al repositorio remoto al guardar.\n\nEsto te permite compartir tus datos de configuración entre varias instalaciones de XPipe. Se admiten tanto URL HTTP como SSH. Ten en cuenta que esto puede ralentizar las operaciones de carga y guardado.\n\nRequiere un reinicio para aplicarse. +vault=Bóveda +workspaceLockDescription=Establece una contraseña personalizada para encriptar cualquier información sensible almacenada en XPipe.\n\nEsto aumenta la seguridad, ya que proporciona una capa adicional de encriptación para tu información sensible almacenada. Se te pedirá que introduzcas la contraseña cuando se inicie XPipe. +useSystemFontDescription=Controla si utilizar la fuente de tu sistema o la fuente Roboto que se incluye con XPipe. +tooltipDelay=Retraso de la información sobre herramientas +tooltipDelayDescription=La cantidad de milisegundos que hay que esperar hasta que se muestre una descripción emergente. +fontSize=Tamaño de letra +windowOptions=Opciones de ventana +saveWindowLocation=Guardar ubicación de la ventana +saveWindowLocationDescription=Controla si las coordenadas de la ventana deben guardarse y restaurarse al reiniciar. +startupShutdown=Inicio / Apagado +showChildCategoriesInParentCategory=Mostrar categorías hijas en la categoría padre +showChildCategoriesInParentCategoryDescription=Incluir o no todas las conexiones situadas en subcategorías cuando se selecciona una determinada categoría padre.\n\nSi se desactiva, las categorías se comportan más como carpetas clásicas que sólo muestran su contenido directo sin incluir las subcarpetas. +condenseConnectionDisplay=Condensar la visualización de la conexión +condenseConnectionDisplayDescription=Haz que cada conexión de nivel superior ocupe menos espacio vertical para permitir una lista de conexiones más condensada. +enforceWindowModality=Aplicar la modalidad de ventana +enforceWindowModalityDescription=Hace que las ventanas secundarias, como el diálogo de creación de conexión, bloqueen todas las entradas de la ventana principal mientras están abiertas. Esto es útil si a veces haces clic mal. +openConnectionSearchWindowOnConnectionCreation=Abrir la ventana de búsqueda de conexión al crear la conexión +openConnectionSearchWindowOnConnectionCreationDescription=Si abrir o no automáticamente la ventana de búsqueda de subconexiones disponibles al añadir una nueva conexión shell. +workflow=Flujo de trabajo +system=Sistema +application=Aplicación +storage=Almacenamiento +runOnStartup=Ejecutar al iniciar +closeBehaviour=Cerrar comportamiento +closeBehaviourDescription=Controla cómo debe proceder XPipe al cerrar su ventana principal. +language=Idioma +languageDescription=El lenguaje de visualización a utilizar.\n\nTen en cuenta que éstas utilizan traducciones automáticas como base y que los colaboradores las corrigen y mejoran manualmente. También puedes ayudar al esfuerzo de traducción enviando correcciones de traducción en GitHub. +lightTheme=Tema luminoso +darkTheme=Tema oscuro +exit=Salir de XPipe +continueInBackground=Continuar en segundo plano +minimizeToTray=Minimizar a la bandeja +closeBehaviourAlertTitle=Establecer el comportamiento de cierre +closeBehaviourAlertTitleHeader=Selecciona lo que debe ocurrir al cerrar la ventana. Cualquier conexión activa se cerrará cuando se cierre la aplicación. +startupBehaviour=Comportamiento de inicio +startupBehaviourDescription=Controla el comportamiento por defecto de la aplicación de escritorio cuando se inicia XPipe. +clearCachesAlertTitle=Limpiar caché +clearCachesAlertTitleHeader=¿Quieres limpiar todas las cachés de XPipe? +clearCachesAlertTitleContent=Ten en cuenta que esto eliminará todos los datos almacenados para mejorar la experiencia del usuario. +startGui=Iniciar GUI +startInTray=Inicio en bandeja +startInBackground=Iniciar en segundo plano +clearCaches=Borrar cachés ... +clearCachesDescription=Borrar todos los datos de la caché +apply=Aplica +cancel=Cancelar +notAnAbsolutePath=No es una ruta absoluta +notADirectory=No es un directorio +notAnEmptyDirectory=No es un directorio vacío +automaticallyUpdate=Buscar actualizaciones +automaticallyUpdateDescription=Cuando está activada, la información de las nuevas versiones se obtiene automáticamente mientras XPipe se está ejecutando. No se ejecuta ningún actualizador en segundo plano, y sigues teniendo que confirmar explícitamente la instalación de cualquier actualización. +sendAnonymousErrorReports=Enviar informes de error anónimos +sendUsageStatistics=Enviar estadísticas de uso anónimas +storageDirectory=Directorio de almacenamiento +storageDirectoryDescription=La ubicación donde XPipe debe almacenar toda la información de conexión. Esta configuración sólo se aplicará en el siguiente reinicio. Al cambiarla, los datos del directorio antiguo no se copiarán en el nuevo. +logLevel=Nivel de registro +appBehaviour=Comportamiento de la aplicación +logLevelDescription=El nivel de registro que debe utilizarse al escribir archivos de registro. +developerMode=Modo desarrollador +developerModeDescription=Cuando esté activado, tendrás acceso a una serie de opciones adicionales útiles para el desarrollo. Sólo se activa tras un reinicio. +editor=Editor +custom=Personalizado +passwordManagerCommand=Comando del gestor de contraseñas +passwordManagerCommandDescription=El comando a ejecutar para obtener las contraseñas. La cadena de texto $KEY se sustituirá por la clave de contraseña citada cuando se llame. Esto debería llamar a la CLI de tu gestor de contraseñas para que imprima la contraseña en stdout, por ejemplo, mypassmgr get $KEY.\n\nA continuación, puedes configurar la clave para que se recupere siempre que establezcas una conexión que requiera una contraseña. +passwordManagerCommandTest=Gestor de contraseñas de prueba +passwordManagerCommandTestDescription=Aquí puedes comprobar si la salida parece correcta si has configurado un comando gestor de contraseñas. El comando sólo debe mostrar la contraseña en la salida estándar, no debe incluir ningún otro formato. +preferEditorTabs=Prefiere abrir nuevas pestañas +preferEditorTabsDescription=Controla si XPipe intentará abrir nuevas pestañas en el editor que elijas en lugar de nuevas ventanas.\n\nTen en cuenta que no todos los editores admiten esta opción. +customRdpClientCommand=Comando personalizado +customRdpClientCommandDescription=El comando a ejecutar para iniciar el cliente RDP personalizado.\n\nLa cadena de texto $FILE se sustituirá por el nombre de archivo .rdp absoluto entre comillas cuando se ejecute. Recuerda entrecomillar la ruta de tu ejecutable si contiene espacios. +customEditorCommand=Comando de editor personalizado +customEditorCommandDescription=El comando a ejecutar para iniciar el editor personalizado.\n\nLa cadena de texto $FICHERO se sustituirá por el nombre absoluto del archivo entre comillas cuando se ejecute. Recuerda entrecomillar la ruta ejecutable de tu editor si contiene espacios. +editorReloadTimeout=Tiempo de espera de recarga del editor +editorReloadTimeoutDescription=La cantidad de milisegundos que hay que esperar antes de leer un archivo después de que se haya actualizado. Esto evita problemas en los casos en que tu editor sea lento escribiendo o liberando bloqueos de archivos. +encryptAllVaultData=Cifrar todos los datos de la bóveda +encryptAllVaultDataDescription=Cuando está activada, se encriptarán todos los datos de conexión de la bóveda, en lugar de sólo los secretos que contengan. Esto añade otra capa de seguridad para otros parámetros como nombres de usuario, nombres de host, etc., que no están encriptados por defecto en la bóveda.\n\nEsta opción hará que el historial y los diffs de tu bóveda git sean inútiles, ya que no podrás ver los cambios originales, sólo los cambios binarios. +vaultSecurity=Seguridad de la bóveda +developerDisableUpdateVersionCheck=Desactivar la comprobación de la versión de actualización +developerDisableUpdateVersionCheckDescription=Controla si el comprobador de actualizaciones ignorará el número de versión al buscar una actualización. +developerDisableGuiRestrictions=Desactivar las restricciones de la GUI +developerDisableGuiRestrictionsDescription=Controla si algunas acciones desactivadas pueden seguir ejecutándose desde la interfaz de usuario. +developerShowHiddenEntries=Mostrar entradas ocultas +developerShowHiddenEntriesDescription=Cuando esté activado, se mostrarán las fuentes de datos ocultas e internas. +developerShowHiddenProviders=Mostrar proveedores ocultos +developerShowHiddenProvidersDescription=Controla si los proveedores ocultos e internos de conexión y fuente de datos se mostrarán en el diálogo de creación. +developerDisableConnectorInstallationVersionCheck=Desactivar la comprobación de la versión del conector +developerDisableConnectorInstallationVersionCheckDescription=Controla si el comprobador de actualizaciones ignorará el número de versión al inspeccionar la versión de un conector XPipe instalado en una máquina remota. +shellCommandTest=Prueba de comandos Shell +shellCommandTestDescription=Ejecuta un comando en la sesión shell utilizada internamente por XPipe. +terminal=Terminal +terminalEmulator=Emulador de terminal +terminalConfiguration=Configuración del terminal +editorConfiguration=Configuración del editor +defaultApplication=Aplicación por defecto +terminalEmulatorDescription=El terminal por defecto que se utiliza al abrir cualquier tipo de conexión shell. Esta aplicación sólo se utiliza a efectos de visualización, el programa shell iniciado depende de la propia conexión shell.\n\nEl nivel de compatibilidad de funciones varía según el terminal, por eso cada uno está marcado como recomendado o no recomendado. Todos los terminales no recomendados funcionan con XPipe, pero pueden carecer de características como pestañas, colores de título, soporte de shell y otras. Tu experiencia de usuario será mejor si utilizas un terminal recomendado. +program=Programa +customTerminalCommand=Comando de terminal personalizado +customTerminalCommandDescription=El comando a ejecutar para abrir el terminal personalizado con un comando determinado.\n\nXPipe creará un script shell lanzador temporal para que lo ejecute tu terminal. La cadena $CMD del marcador de posición del comando que proporciones será sustituida por el script lanzador real cuando sea llamado. Recuerda entrecomillar la ruta ejecutable de tu terminal si contiene espacios. +clearTerminalOnInit=Borrar terminal al iniciar +clearTerminalOnInitDescription=Cuando está activado, XPipe ejecuta un comando de limpieza cuando se inicia una nueva sesión de terminal para eliminar cualquier salida innecesaria. +enableFastTerminalStartup=Activar el inicio rápido del terminal +enableFastTerminalStartupDescription=Cuando está activada, se intenta que las sesiones de terminal se inicien más rápido siempre que sea posible.\n\nEsto omitirá varias comprobaciones de inicio y no actualizará ninguna información mostrada del sistema. Cualquier error de conexión sólo se mostrará en el terminal. +dontCachePasswords=No almacenar en caché las contraseñas solicitadas +dontCachePasswordsDescription=Controla si las contraseñas consultadas deben ser cacheadas internamente por XPipe para que no tengas que introducirlas de nuevo en la sesión actual.\n\nSi este comportamiento está desactivado, tendrás que volver a introducir las credenciales solicitadas cada vez que sean requeridas por el sistema. +denyTempScriptCreation=Denegar la creación de un script temporal +denyTempScriptCreationDescription=Para realizar algunas de sus funciones, XPipe a veces crea scripts shell temporales en un sistema de destino para permitir una fácil ejecución de comandos sencillos. Éstos no contienen ninguna información sensible y sólo se crean con fines de implementación.\n\nSi se desactiva este comportamiento, XPipe no creará ningún archivo temporal en un sistema remoto. Esta opción es útil en contextos de alta seguridad en los que se supervisa cada cambio en el sistema de archivos. Si se desactiva, algunas funcionalidades, como los entornos shell y los scripts, no funcionarán como está previsto. +disableCertutilUse=Desactivar el uso de certutil en Windows +useLocalFallbackShell=Utilizar el shell local de reserva +useLocalFallbackShellDescription=Pasa a utilizar otro shell local para gestionar las operaciones locales. Esto sería PowerShell en Windows y bourne shell en otros sistemas.\n\nEsta opción puede utilizarse en caso de que el shell local normal por defecto esté desactivado o roto en algún grado. Sin embargo, algunas funciones pueden no funcionar como se espera cuando esta opción está activada.\n\nRequiere un reinicio para aplicarse. +disableCertutilUseDescription=Debido a varias deficiencias y errores de cmd.exe, se crean scripts shell temporales con certutil utilizándolo para descodificar la entrada base64, ya que cmd.exe se rompe con la entrada no ASCII. XPipe también puede utilizar PowerShell para ello, pero será más lento.\n\nEsto deshabilita cualquier uso de certutil en sistemas Windows para realizar algunas funciones y recurrir a PowerShell en su lugar. Esto podría complacer a algunos antivirus, ya que algunos bloquean el uso de certutil. +disableTerminalRemotePasswordPreparation=Desactivar la preparación de la contraseña remota del terminal +disableTerminalRemotePasswordPreparationDescription=En situaciones en las que deba establecerse en el terminal una conexión shell remota que atraviese varios sistemas intermedios, puede ser necesario preparar las contraseñas necesarias en uno de los sistemas intermedios para permitir la cumplimentación automática de cualquier solicitud.\n\nSi no quieres que las contraseñas se transfieran nunca a ningún sistema intermedio, puedes desactivar este comportamiento. Cualquier contraseña intermedia requerida se consultará entonces en el propio terminal cuando se abra. +more=Más +translate=Traducciones +allConnections=Todas las conexiones +allScripts=Todos los guiones +predefined=Predefinido +default=Por defecto +goodMorning=Buenos días +goodAfternoon=Buenas tardes +goodEvening=Buenas noches +addVisual=Visual ... +ssh=SSH +sshConfiguration=Configuración SSH +size=Tamaño +attributes=Atributos +modified=Modificado +isOnlySupported=sólo es compatible con una licencia profesional +areOnlySupported=sólo son compatibles con una licencia profesional +updateReadyTitle=Actualiza a $VERSION$ ready diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties new file mode 100644 index 000000000..b1ee2eb1f --- /dev/null +++ b/lang/app/strings/translations_fr.properties @@ -0,0 +1,426 @@ +delete=Effacer +rename=Renommer +properties=Propriétés +usedDate=Utilisé $DATE$ +openDir=Répertoire ouvert +sortLastUsed=Trier par date de dernière utilisation +sortAlphabetical=Tri alphabétique par nom +restart=Redémarrer XPipe +restartDescription=Un redémarrage peut souvent être une solution rapide +reportIssue=Signaler un problème +reportIssueDescription=Ouvre le rapporteur de questions intégré +usefulActions=Actions utiles +stored=Sauvegardé +troubleshootingOptions=Outils de dépannage +troubleshoot=Dépannage +remote=Fichier distant +addShellStore=Ajouter une coquille ... +addShellTitle=Ajouter une connexion Shell +savedConnections=Connexions sauvegardées +save=Sauvegarde +clean=Nettoyer +refresh=Rafraîchir +moveTo=Déplacer vers ... +addDatabase=Base de données ... +browseInternalStorage=Parcourir la mémoire interne +addTunnel=Tunnel ... +addScript=Script ... +addHost=Hôte distant ... +addShell=Environnement Shell ... +addCommand=Commande personnalisée ... +addAutomatically=Recherche automatique ... +addOther=Ajouter d'autres... +addConnection=Ajouter une connexion +skip=Sauter +addConnections=Nouveau +selectType=Sélectionner un type +selectTypeDescription=Sélectionne le type de connexion +selectShellType=Type de coquille +selectShellTypeDescription=Sélectionne le type de connexion Shell +name=Nom +storeIntroTitle=Hub de connexion +storeIntroDescription=Ici, tu peux gérer toutes tes connexions shell locales et distantes en un seul endroit. Pour commencer, tu peux rapidement détecter automatiquement les connexions disponibles et choisir celles que tu veux ajouter. +detectConnections=Recherche de connexions +configuration=Configuration +dragAndDropFilesHere=Ou bien tu peux simplement glisser et déposer un fichier ici +confirmDsCreationAbortTitle=Confirmer l'abandon +confirmDsCreationAbortHeader=Veux-tu interrompre la création de la source de données ? +confirmDsCreationAbortContent=Tout progrès dans la création de la source de données sera perdu. +confirmInvalidStoreTitle=Échec de la connexion +confirmInvalidStoreHeader=Veux-tu ignorer la validation de la connexion ? +confirmInvalidStoreContent=Tu peux ajouter cette connexion même si elle n'a pas pu être validée et régler les problèmes de connexion ultérieurement. +none=Aucun +expand=Élargir +accessSubConnections=Accès aux sous-connexions +common=Commun +color=Couleur +alwaysConfirmElevation=Toujours confirmer l'élévation de la permission +alwaysConfirmElevationDescription=Contrôle la façon de gérer les cas où des autorisations élevées sont nécessaires pour exécuter une commande sur un système, par exemple avec sudo.\n\nPar défaut, toutes les informations d'identification sudo sont mises en cache au cours d'une session et fournies automatiquement en cas de besoin. Si cette option est activée, il te sera demandé de confirmer l'accès en élévation à chaque fois. +allow=Permettre +ask=Demande +deny=Refuser +share=Ajouter au dépôt git +unshare=Retirer du dépôt git +remove=Enlever +newCategory=Nouvelle sous-catégorie +passwordManager=Gestionnaire de mots de passe +prompt=Invite +customCommand=Commande personnalisée +other=Autre +setLock=Verrouiller +selectConnection=Sélectionner une connexion +changeLock=Changer de phrase de passe +test=Test +lockCreationAlertTitle=Définir une phrase de passe +lockCreationAlertHeader=Définis ta nouvelle phrase de passe principale +finish=Finir +error=Une erreur s'est produite +downloadStageDescription=Télécharge les fichiers sur ta machine locale, afin que tu puisses les faire glisser et les déposer dans ton environnement de bureau natif. +ok=Ok +search=Rechercher +newFile=Nouveau fichier +newDirectory=Nouveau répertoire +passphrase=Phrase de passe +repeatPassphrase=Répéter la phrase de passe +password=Mot de passe +unlockAlertTitle=Déverrouiller l'espace de travail +unlockAlertHeader=Saisis ta phrase d'authentification du coffre-fort pour continuer +enterLockPassword=Saisir le mot de passe de la serrure +repeatPassword=Répéter le mot de passe +askpassAlertTitle=Askpass +unsupportedOperation=Opération non prise en charge : $MSG$ +fileConflictAlertTitle=Résoudre un conflit +fileConflictAlertHeader=Un conflit a été rencontré. Comment veux-tu procéder ? +fileConflictAlertContent=Le fichier $FILE$ existe déjà sur le système cible. +fileConflictAlertContentMultiple=Le fichier $FILE$ existe déjà. Il peut y avoir d'autres conflits que tu peux résoudre automatiquement en choisissant une option qui s'applique à tous. +moveAlertTitle=Confirmer un mouvement +moveAlertHeader=Veux-tu déplacer les ($COUNT$) éléments sélectionnés dans $TARGET$? +deleteAlertTitle=Confirmer la suppression +deleteAlertHeader=Veux-tu supprimer les ($COUNT$) éléments sélectionnés ? +selectedElements=Éléments sélectionnés : +mustNotBeEmpty=$VALUE$ ne doit pas être vide +valueMustNotBeEmpty=La valeur ne doit pas être vide +transferDescription=Dépose des fichiers à transférer +dragFiles=Faire glisser des fichiers dans le navigateur +dragLocalFiles=Fais glisser des fichiers locaux à partir d'ici +null=$VALUE$ doit être non nul +roots=Racines +scripts=Scripts +searchFilter=Recherche ... +recent=Récent +shortcut=Raccourci +browserWelcomeEmpty=Ici, tu pourras voir où tu t'es arrêté la dernière fois. +browserWelcomeSystems=Tu as récemment été connecté aux systèmes suivants : +hostFeatureUnsupported=$FEATURE$ n'est pas installé sur l'hôte +missingStore=$NAME$ n'existe pas +connectionName=Nom de la connexion +connectionNameDescription=Donne un nom personnalisé à cette connexion +openFileTitle=Ouvrir un fichier +unknown=Inconnu +scanAlertTitle=Ajouter des connexions +scanAlertChoiceHeader=Cible +scanAlertChoiceHeaderDescription=Choisis où rechercher les connexions. Cela permet de rechercher d'abord toutes les connexions disponibles. +scanAlertHeader=Types de connexion +scanAlertHeaderDescription=Sélectionne les types de connexions que tu veux ajouter automatiquement pour le système. +noInformationAvailable=Aucune information disponible +localMachine=Machine locale +yes=Oui +no=Non +errorOccured=Une erreur s'est produite +terminalErrorOccured=Une erreur de terminal s'est produite +errorTypeOccured=Une exception de type $TYPE$ a été lancée +permissionsAlertTitle=Permissions requises +permissionsAlertHeader=Des autorisations supplémentaires sont nécessaires pour effectuer cette opération. +permissionsAlertContent=Suis le pop-up pour donner à XPipe les autorisations nécessaires dans le menu des paramètres. +errorDetails=Afficher les détails +updateReadyAlertTitle=Prêt pour la mise à jour +updateReadyAlertHeader=Une mise à jour de la version $VERSION$ est prête à être installée +updateReadyAlertContent=Cela installera la nouvelle version et redémarrera XPipe une fois l'installation terminée. +errorNoDetail=Aucun détail d'erreur n'est disponible +updateAvailableTitle=Mise à jour disponible +updateAvailableHeader=Une mise à jour de XPipe vers la version $VERSION$ est disponible à l'installation +updateAvailableContent=Même si XPipe n'a pas pu être démarré, tu peux essayer d'installer la mise à jour pour éventuellement résoudre le problème. +clipboardActionDetectedTitle=Action du presse-papiers détectée +clipboardActionDetectedHeader=Veux-tu importer le contenu de ton presse-papiers ? +clipboardActionDetectedContent=XPipe a détecté dans ton presse-papiers un contenu qui peut être ouvert. Veux-tu l'ouvrir maintenant ? +install=Installer ... +ignore=Ignorer +possibleActions=Actions possibles +reportError=Erreur de rapport +reportOnGithub=Créer un rapport de problème sur GitHub +reportOnGithubDescription=Ouvre un nouveau problème dans le dépôt GitHub +reportErrorDescription=Envoyer un rapport d'erreur avec un retour d'information optionnel de l'utilisateur et des informations de diagnostic +ignoreError=Ignorer l'erreur +ignoreErrorDescription=Ignore cette erreur et continue comme si de rien n'était +provideEmail=Comment te contacter (facultatif, uniquement si tu veux être informé des correctifs) +additionalErrorInfo=Fournir des informations supplémentaires (facultatif) +additionalErrorAttachments=Sélectionne les pièces jointes (facultatif) +dataHandlingPolicies=Politique de confidentialité +sendReport=Envoyer un rapport +errorHandler=Gestionnaire d'erreurs +events=Les événements +method=Méthode +validate=Valider +stackTrace=Trace de pile +previousStep=< Précédent +nextStep=Suivant > +finishStep=Finir +edit=Éditer +browseInternal=Parcourir l'intérieur +checkOutUpdate=Vérifier la mise à jour +open=Ouvrir +quit=Quitter +noTerminalSet=Aucune application de terminal n'a été réglée automatiquement. Tu peux le faire manuellement dans le menu des paramètres. +connections=Raccordements +settings=Paramètres +explorePlans=Licence +help=Aide +about=A propos de +developer=Développeur +browseFileTitle=Parcourir le fichier +browse=Parcourir +browser=Navigateur +selectFileFromComputer=Sélectionne un fichier sur cet ordinateur +links=Liens utiles +website=Site web +documentation=Documentation +discordDescription=Rejoins le serveur Discord +security=Sécurité +securityPolicy=Informations de sécurité +securityPolicyDescription=Lire la politique de sécurité détaillée +privacy=Politique de confidentialité +privacyDescription=Lis la politique de confidentialité de l'application XPipe +slackDescription=Rejoins l'espace de travail Slack +support=Support +githubDescription=Jette un coup d'œil au dépôt GitHub +openSourceNotices=Avis Open Source +xPipeClient=XPipe Desktop +checkForUpdates=Vérifier les mises à jour +checkForUpdatesDescription=Télécharger une mise à jour s'il y en a une +lastChecked=Dernière vérification +version=Version +build=Version de construction +runtimeVersion=Version d'exécution +virtualMachine=Machine virtuelle +updateReady=Installer une mise à jour +updateReadyPortable=Vérifier la mise à jour +updateReadyDescription=Une mise à jour a été téléchargée et est prête à être installée +updateReadyDescriptionPortable=Une mise à jour est disponible au téléchargement +updateRestart=Redémarre pour mettre à jour +never=Jamais +updateAvailableTooltip=Mise à jour disponible +visitGithubRepository=Visiter le dépôt GitHub +updateAvailable=Mise à jour disponible : $VERSION$ +downloadUpdate=Télécharger la mise à jour +legalAccept=J'accepte le contrat de licence de l'utilisateur final +confirm=Confirmer +print=Imprimer +whatsNew=Nouveautés de la version $VERSION$ ($DATE$) +antivirusNoticeTitle=Une note sur les programmes antivirus +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Bienvenue à XPipe +gotIt=Compris +eula=Contrat de licence de l'utilisateur final +news=Nouvelles +introduction=Introduction +privacyPolicy=Politique de confidentialité +agree=Accepte +disagree=Ne pas être d'accord +directories=Répertoires +logFile=Fichier journal +logFiles=Fichiers journaux +logFilesAttachment=Fichiers journaux +issueReporter=Rapporteur de problèmes +openCurrentLogFile=Fichiers journaux +openCurrentLogFileDescription=Ouvrir le fichier journal de la session en cours +openLogsDirectory=Ouvrir le répertoire des journaux +installationFiles=Fichiers d'installation +openInstallationDirectory=Fichiers d'installation +openInstallationDirectoryDescription=Ouvrir le répertoire d'installation de XPipe +launchDebugMode=Mode débogage +launchDebugModeDescription=Redémarre XPipe en mode débogage +extensionInstallTitle=Télécharger +extensionInstallDescription=Cette action nécessite des bibliothèques tierces supplémentaires qui ne sont pas distribuées par XPipe. Tu peux les installer automatiquement ici. Les composants sont ensuite téléchargés à partir du site web du fournisseur : +extensionInstallLicenseNote=En effectuant le téléchargement et l'installation automatique, tu acceptes les termes des licences des tiers : +license=Licence +installRequired=Installation requise +restore=Restaurer +restoreAllSessions=Restaurer toutes les sessions +connectionTimeout=Délai de démarrage de la connexion +connectionTimeoutDescription=Le temps en secondes à attendre une réponse avant de considérer qu'une connexion est dépassée. Si certains de tes systèmes distants mettent du temps à se connecter, tu peux essayer d'augmenter cette valeur. +useBundledTools=Utilise les outils OpenSSH fournis +useBundledToolsDescription=Préfère utiliser la version fournie du client openssh plutôt que celle installée localement.\n\nCette version est généralement plus à jour que celles livrées sur ton système et peut prendre en charge des fonctionnalités supplémentaires. Cela élimine également la nécessité d'installer ces outils en premier lieu.\n\nUn redémarrage est nécessaire pour l'appliquer. +appearance=Apparence +integrations=Intégrations +uiOptions=Options de l'interface utilisateur +theme=Thème +rdp=Bureau à distance +rdpConfiguration=Configuration du bureau à distance +rdpClient=Client RDP +rdpClientDescription=Le programme client RDP à appeler lors du lancement des connexions RDP.\n\nNote que les divers clients ont différents degrés de capacités et d'intégrations. Certains clients ne prennent pas en charge le passage automatique des mots de passe, tu dois donc toujours les remplir au lancement. +localShell=Shell local +themeDescription=Ton thème d'affichage préféré +dontAutomaticallyStartVmSshServer=Ne démarre pas automatiquement le serveur SSH pour les machines virtuelles lorsque c'est nécessaire +dontAutomaticallyStartVmSshServerDescription=Toute connexion shell à une VM fonctionnant dans un hyperviseur se fait par l'intermédiaire de SSH. XPipe peut démarrer automatiquement le serveur SSH installé lorsque cela est nécessaire. Si tu ne le souhaites pas pour des raisons de sécurité, tu peux simplement désactiver ce comportement avec cette option. +confirmGitShareTitle=Confirmer le partage git +confirmGitShareHeader=Cela copiera le fichier dans ton coffre-fort git et validera tes modifications. Veux-tu continuer ? +gitShareFileTooltip=Ajoute un fichier au répertoire de données de git vault pour qu'il soit automatiquement synchronisé.\n\nCette action ne peut être utilisée que lorsque le git vault est activé dans les paramètres. +performanceMode=Mode performance +performanceModeDescription=Désactive tous les effets visuels qui ne sont pas nécessaires afin d'améliorer les performances de l'application. +dontAcceptNewHostKeys=N'accepte pas automatiquement les nouvelles clés d'hôte SSH +dontAcceptNewHostKeysDescription=XPipe acceptera automatiquement par défaut les clés d'hôte des systèmes pour lesquels ton client SSH n'a pas de clé d'hôte connue déjà enregistrée. Cependant, si une clé d'hôte connue a changé, il refusera de se connecter si tu n'acceptes pas la nouvelle.\n\nLa désactivation de ce comportement te permet de vérifier toutes les clés d'hôte, même s'il n'y a pas de conflit au départ. +uiScale=Échelle de l'interface utilisateur +uiScaleDescription=Une valeur d'échelle personnalisée qui peut être définie indépendamment de l'échelle d'affichage du système. Les valeurs sont exprimées en pourcentage. Ainsi, une valeur de 150 se traduira par une échelle d'affichage de 150 %.\n\nIl faut redémarrer l'ordinateur pour l'appliquer. +editorProgram=Programme d'édition +editorProgramDescription=L'éditeur de texte par défaut à utiliser lors de l'édition de n'importe quel type de données textuelles. +windowOpacity=Opacité de la fenêtre +windowOpacityDescription=Modifie l'opacité de la fenêtre pour suivre ce qui se passe en arrière-plan. +useSystemFont=Utilise la police du système +openDataDir=Répertoire de données de voûte +openDataDirButton=Répertoire de données ouvertes +openDataDirDescription=Si tu veux synchroniser des fichiers supplémentaires, comme les clés SSH, entre les systèmes avec ton dépôt git, tu peux les mettre dans le répertoire storage data. Tous les fichiers qui y sont référencés verront leur chemin de fichier automatiquement adapté sur n'importe quel système synchronisé. +updates=Mises à jour +passwordKey=Clé de mot de passe +selectAll=Sélectionne tout +command=Commande +advanced=Avancé +thirdParty=Avis de source ouverte +eulaDescription=Lis le contrat de licence de l'utilisateur final pour l'application XPipe +thirdPartyDescription=Voir les licences open source des bibliothèques tierces +workspaceLock=Phrase de passe principale +enableGitStorage=Activer la synchronisation git +sharing=Partage +sync=Synchronisation +enableGitStorageDescription=Lorsqu'il est activé, XPipe initialisera un dépôt git pour le stockage des données de connexion et y livrera toutes les modifications. Note que cela nécessite l'installation de git et peut ralentir les opérations de chargement et d'enregistrement.\n\nToutes les catégories qui doivent être synchronisées doivent être explicitement désignées comme partagées.\n\nNécessite un redémarrage pour être appliqué. +storageGitRemote=URL distante de Git +storageGitRemoteDescription=Lorsque cette option est activée, XPipe récupère automatiquement toutes les modifications lors du chargement et les transfère vers le référentiel distant lors de l'enregistrement.\n\nCela te permet de partager tes données de configuration entre plusieurs installations de XPipe. Les URL HTTP et SSH sont prises en charge. Note que cela peut ralentir les opérations de chargement et d'enregistrement.\n\nL'application nécessite un redémarrage. +vault=Voûte +workspaceLockDescription=Définit un mot de passe personnalisé pour crypter toute information sensible stockée dans XPipe.\n\nCela se traduit par une sécurité accrue car cela fournit une couche supplémentaire de cryptage pour tes informations sensibles stockées. Tu seras alors invité à saisir le mot de passe au démarrage de XPipe. +useSystemFontDescription=Contrôle l'utilisation de la police de ton système ou de la police Roboto fournie avec XPipe. +tooltipDelay=Délai de l'infobulle +tooltipDelayDescription=Le nombre de millisecondes à attendre avant l'affichage d'une info-bulle. +fontSize=Taille de la police +windowOptions=Options de la fenêtre +saveWindowLocation=Emplacement de la fenêtre de sauvegarde +saveWindowLocationDescription=Contrôle si les coordonnées de la fenêtre doivent être sauvegardées et restaurées lors des redémarrages. +startupShutdown=Démarrage / Arrêt +showChildCategoriesInParentCategory=Afficher les catégories enfants dans la catégorie parent +showChildCategoriesInParentCategoryDescription=Inclure ou non toutes les connexions situées dans les sous-catégories lorsqu'une certaine catégorie parentale est sélectionnée.\n\nSi cette option est désactivée, les catégories se comportent davantage comme des dossiers classiques qui n'affichent que leur contenu direct sans inclure les sous-dossiers. +condenseConnectionDisplay=Condenser l'affichage des connexions +condenseConnectionDisplayDescription=Faire en sorte que chaque connexion de niveau supérieur prenne moins d'espace vertical pour permettre une liste de connexions plus condensée. +enforceWindowModality=Modalité de la fenêtre d'application +enforceWindowModalityDescription=Fait en sorte que les fenêtres secondaires, telles que la boîte de dialogue de création de connexion, bloquent toute saisie pour la fenêtre principale tant qu'elles sont ouvertes. C'est utile s'il t'arrive de mal cliquer. +openConnectionSearchWindowOnConnectionCreation=Ouvrir la fenêtre de recherche de connexion lors de la création de la connexion +openConnectionSearchWindowOnConnectionCreationDescription=Ouverture automatique ou non de la fenêtre de recherche des sous-connexions disponibles lors de l'ajout d'une nouvelle connexion shell. +workflow=Flux de travail +system=Système +application=Application +storage=Stockage +runOnStartup=Exécuter au démarrage +closeBehaviour=Fermer le comportement +closeBehaviourDescription=Contrôle la façon dont XPipe doit procéder à la fermeture de sa fenêtre principale. +language=Langue +languageDescription=La langue d'affichage à utiliser.\n\nNote que celles-ci utilisent les traductions automatiques comme base et sont corrigées et améliorées manuellement par les contributeurs. Tu peux également contribuer à l'effort de traduction en soumettant des correctifs de traduction sur GitHub. +lightTheme=Thème lumineux +darkTheme=Thème sombre +exit=Quitter XPipe +continueInBackground=Continue en arrière-plan +minimizeToTray=Minimiser dans la barre d'état +closeBehaviourAlertTitle=Définir le comportement de fermeture +closeBehaviourAlertTitleHeader=Sélectionne ce qui doit se passer lors de la fermeture de la fenêtre. Toutes les connexions actives seront fermées lorsque l'application sera arrêtée. +startupBehaviour=Comportement au démarrage +startupBehaviourDescription=Contrôle le comportement par défaut de l'application de bureau lorsque XPipe est démarré. +clearCachesAlertTitle=Nettoyer le cache +clearCachesAlertTitleHeader=Veux-tu nettoyer tous les caches de XPipe ? +clearCachesAlertTitleContent=Note que cela supprimera toutes les données qui sont stockées pour améliorer l'expérience de l'utilisateur. +startGui=Démarrer l'interface graphique +startInTray=Démarrer dans la barre d'état +startInBackground=Démarrer en arrière-plan +clearCaches=Vider les caches ... +clearCachesDescription=Efface toutes les données du cache +apply=Appliquer +cancel=Annuler +notAnAbsolutePath=Pas un chemin absolu +notADirectory=Pas un répertoire +notAnEmptyDirectory=Pas un répertoire vide +automaticallyUpdate=Vérifier les mises à jour +automaticallyUpdateDescription=Lorsque cette option est activée, les informations sur les nouvelles versions sont automatiquement récupérées lorsque XPipe est en cours d'exécution. Aucun programme de mise à jour n'est exécuté en arrière-plan, et tu dois toujours confirmer explicitement l'installation d'une mise à jour. +sendAnonymousErrorReports=Envoyer des rapports d'erreur anonymes +sendUsageStatistics=Envoyer des statistiques d'utilisation anonymes +storageDirectory=Répertoire de stockage +storageDirectoryDescription=L'emplacement où XPipe doit stocker toutes les informations de connexion. Ce paramètre ne sera appliqué qu'au prochain redémarrage. Lorsqu'on le modifie, les données de l'ancien répertoire ne sont pas copiées dans le nouveau. +logLevel=Niveau du journal +appBehaviour=Comportement de l'application +logLevelDescription=Le niveau de journal qui doit être utilisé lors de l'écriture des fichiers journaux. +developerMode=Mode développeur +developerModeDescription=Lorsque cette option est activée, tu as accès à toute une série d'options supplémentaires utiles pour le développement. N'est actif qu'après un redémarrage. +editor=Éditeur +custom=Personnalisé +passwordManagerCommand=Commande du gestionnaire de mots de passe +passwordManagerCommandDescription=La commande à exécuter pour récupérer les mots de passe. La chaîne de caractères de remplacement $KEY sera remplacée par la clé de mot de passe citée lorsqu'elle sera appelée. Cette commande devrait appeler ton gestionnaire de mots de passe CLI pour imprimer le mot de passe sur stdout, par exemple mypassmgr get $KEY.\n\nTu peux ensuite configurer la clé pour qu'elle soit récupérée chaque fois que tu établis une connexion qui nécessite un mot de passe. +passwordManagerCommandTest=Test du gestionnaire de mot de passe +passwordManagerCommandTestDescription=Tu peux tester ici si la sortie semble correcte si tu as mis en place une commande de gestionnaire de mot de passe. La commande ne doit sortir que le mot de passe lui-même sur stdout, aucun autre formatage ne doit être inclus dans la sortie. +preferEditorTabs=Préfère ouvrir de nouveaux onglets +preferEditorTabsDescription=Contrôle si XPipe essaiera d'ouvrir de nouveaux onglets dans l'éditeur que tu as choisi au lieu de nouvelles fenêtres.\n\nNote que ce n'est pas le cas de tous les éditeurs. +customRdpClientCommand=Commande personnalisée +customRdpClientCommandDescription=La commande à exécuter pour démarrer le client RDP personnalisé.\n\nLa chaîne de caractères $FILE sera remplacée par le nom du fichier .rdp absolu entre guillemets lorsqu'elle sera appelée. N'oublie pas de citer ton chemin d'accès à l'exécutable s'il contient des espaces. +customEditorCommand=Commande personnalisée de l'éditeur +customEditorCommandDescription=La commande à exécuter pour démarrer l'éditeur personnalisé.\n\nLa chaîne de caractères de remplacement $FILE sera remplacée par le nom de fichier absolu entre guillemets lorsqu'elle sera appelée. N'oublie pas de citer le chemin d'accès à l'exécutable de ton éditeur s'il contient des espaces. +editorReloadTimeout=Délai de rechargement de l'éditeur +editorReloadTimeoutDescription=Le nombre de millisecondes à attendre avant de lire un fichier après sa mise à jour. Cela permet d'éviter les problèmes dans les cas où ton éditeur est lent à écrire ou à libérer les verrous de fichiers. +encryptAllVaultData=Crypte toutes les données du coffre-fort +encryptAllVaultDataDescription=Lorsque cette option est activée, toutes les données de connexion au coffre-fort sont cryptées, alors que seuls les secrets contenus dans ces données le sont. Cela ajoute une couche de sécurité supplémentaire pour d'autres paramètres tels que les noms d'utilisateur, les noms d'hôte, etc. qui ne sont pas cryptés par défaut dans le coffre-fort.\n\nCette option rendra l'historique de ton coffre-fort git et les diffs inutiles car tu ne pourras plus voir les modifications originales, seulement les modifications binaires. +vaultSecurity=Sécurité des voûtes +developerDisableUpdateVersionCheck=Désactiver la vérification de la version de la mise à jour +developerDisableUpdateVersionCheckDescription=Contrôle si le vérificateur de mise à jour ignore le numéro de version lorsqu'il recherche une mise à jour. +developerDisableGuiRestrictions=Désactiver les restrictions de l'interface graphique +developerDisableGuiRestrictionsDescription=Contrôle si certaines actions désactivées peuvent encore être exécutées à partir de l'interface utilisateur. +developerShowHiddenEntries=Afficher les entrées cachées +developerShowHiddenEntriesDescription=Lorsque cette option est activée, les sources de données cachées et internes sont affichées. +developerShowHiddenProviders=Afficher les fournisseurs cachés +developerShowHiddenProvidersDescription=Contrôle si les fournisseurs de connexion et de source de données cachés et internes seront affichés dans la boîte de dialogue de création. +developerDisableConnectorInstallationVersionCheck=Désactiver la vérification de la version du connecteur +developerDisableConnectorInstallationVersionCheckDescription=Contrôle si le vérificateur de mise à jour ignore le numéro de version lorsqu'il inspecte la version d'un connecteur XPipe installé sur une machine distante. +shellCommandTest=Test de commande Shell +shellCommandTestDescription=Exécute une commande dans la session shell utilisée en interne par XPipe. +terminal=Terminal +terminalEmulator=Émulateur de terminal +terminalConfiguration=Configuration du terminal +editorConfiguration=Configuration de l'éditeur +defaultApplication=Application par défaut +terminalEmulatorDescription=Le terminal par défaut à utiliser lors de l'ouverture de tout type de connexion shell. Cette application n'est utilisée qu'à des fins d'affichage, le programme shell démarré dépend de la connexion shell elle-même.\n\nLe niveau de prise en charge des fonctionnalités varie d'un terminal à l'autre, c'est pourquoi chacun d'entre eux est marqué comme recommandé ou non recommandé. Tous les terminaux non recommandés fonctionnent avec XPipe mais peuvent manquer de fonctionnalités comme les onglets, les couleurs de titre, la prise en charge de l'interpréteur de commandes, et plus encore. Ton expérience d'utilisateur sera meilleure si tu utilises un terminal recommandé. +program=Programme +customTerminalCommand=Commande de terminal personnalisée +customTerminalCommandDescription=La commande à exécuter pour ouvrir le terminal personnalisé avec une commande donnée.\n\nXPipe créera un script de lancement temporaire pour ton terminal à exécuter. La chaîne de caractères de remplacement $CMD dans la commande que tu fournis sera remplacée par le script de lancement réel lorsqu'il sera appelé. N'oublie pas de citer le chemin d'accès à l'exécutable de ton terminal s'il contient des espaces. +clearTerminalOnInit=Effacer le terminal au démarrage +clearTerminalOnInitDescription=Lorsque cette option est activée, XPipe exécute une commande d'effacement lorsqu'une nouvelle session de terminal est lancée afin de supprimer toute sortie inutile. +enableFastTerminalStartup=Activation du démarrage rapide du terminal +enableFastTerminalStartupDescription=Lorsque cette option est activée, on essaie de démarrer les sessions de terminal plus rapidement lorsque c'est possible.\n\nCela permet d'ignorer plusieurs vérifications au démarrage et de ne pas mettre à jour les informations système affichées. Toute erreur de connexion ne sera affichée que dans le terminal. +dontCachePasswords=Ne pas mettre en cache les mots de passe demandés +dontCachePasswordsDescription=Contrôle si les mots de passe demandés doivent être mis en cache en interne par XPipe afin que tu n'aies pas à les saisir à nouveau dans la session en cours.\n\nSi ce comportement est désactivé, tu devras saisir à nouveau les informations d'identification demandées chaque fois qu'elles seront exigées par le système. +denyTempScriptCreation=Refuser la création de scripts temporaires +denyTempScriptCreationDescription=Pour réaliser certaines de ses fonctionnalités, XPipe crée parfois des scripts shell temporaires sur un système cible pour permettre une exécution facile de commandes simples. Ceux-ci ne contiennent aucune information sensible et sont simplement créés à des fins de mise en œuvre.\n\nSi ce comportement est désactivé, XPipe ne créera aucun fichier temporaire sur un système distant. Cette option est utile dans les contextes de haute sécurité où chaque modification du système de fichiers est surveillée. Si cette option est désactivée, certaines fonctionnalités, par exemple les environnements shell et les scripts, ne fonctionneront pas comme prévu. +disableCertutilUse=Désactiver l'utilisation de certutil sur Windows +useLocalFallbackShell=Utiliser le shell local de secours +useLocalFallbackShellDescription=Passe à l'utilisation d'un autre shell local pour gérer les opérations locales. Il s'agirait de PowerShell sur Windows et de l'interpréteur de commandes bourne sur d'autres systèmes.\n\nCette option peut être utilisée dans le cas où le shell local normal par défaut est désactivé ou cassé dans une certaine mesure. Certaines fonctionnalités peuvent ne pas fonctionner comme prévu lorsque cette option est activée.\n\nUn redémarrage est nécessaire pour l'appliquer. +disableCertutilUseDescription=En raison de plusieurs lacunes et bogues dans cmd.exe, des scripts shell temporaires sont créés avec certutil en l'utilisant pour décoder l'entrée base64 car cmd.exe s'interrompt sur l'entrée non ASCII. XPipe peut également utiliser PowerShell pour cela, mais cela sera plus lent.\n\nCela désactive toute utilisation de certutil sur les systèmes Windows pour réaliser certaines fonctionnalités et se rabat sur PowerShell à la place. Cela pourrait plaire à certains antivirus, car certains d'entre eux bloquent l'utilisation de certutil. +disableTerminalRemotePasswordPreparation=Désactiver la préparation du mot de passe à distance du terminal +disableTerminalRemotePasswordPreparationDescription=Dans les situations où une connexion shell à distance qui passe par plusieurs systèmes intermédiaires doit être établie dans le terminal, il peut être nécessaire de préparer tous les mots de passe requis sur l'un des systèmes intermédiaires pour permettre un remplissage automatique de toutes les invites.\n\nSi tu ne veux pas que les mots de passe soient transférés vers un système intermédiaire, tu peux désactiver ce comportement. Tout mot de passe intermédiaire requis sera alors demandé dans le terminal lui-même lorsqu'il sera ouvert. +more=Plus +translate=Traductions +allConnections=Toutes les connexions +allScripts=Tous les scripts +predefined=Prédéfini +default=Défaut +goodMorning=Bonjour +goodAfternoon=Bon après-midi +goodEvening=Bonne soirée +addVisual=Visual ... +ssh=SSH +sshConfiguration=Configuration SSH +size=Taille +attributes=Attributs +modified=Modifié +isOnlySupported=n'est pris en charge qu'avec une licence professionnelle +areOnlySupported=ne sont pris en charge qu'avec une licence professionnelle +updateReadyTitle=Mise à jour de $VERSION$ ready diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties new file mode 100644 index 000000000..9a08d8a15 --- /dev/null +++ b/lang/app/strings/translations_it.properties @@ -0,0 +1,426 @@ +delete=Eliminare +rename=Rinominare +properties=Proprietà +usedDate=Utilizzato $DATE$ +openDir=Elenco aperto +sortLastUsed=Ordina per data di ultimo utilizzo +sortAlphabetical=Ordinamento alfabetico per nome +restart=Riavviare XPipe +restartDescription=Un riavvio può spesso essere una soluzione rapida +reportIssue=Segnalare un problema +reportIssueDescription=Apri il segnalatore di problemi integrato +usefulActions=Azioni utili +stored=Salvato +troubleshootingOptions=Strumenti per la risoluzione dei problemi +troubleshoot=Risoluzione dei problemi +remote=File remoto +addShellStore=Aggiungi Shell ... +addShellTitle=Aggiungi connessione alla shell +savedConnections=Connessioni salvate +save=Salva +clean=Pulire +refresh=Aggiornare +moveTo=Passare a ... +addDatabase=Database ... +browseInternalStorage=Sfogliare la memoria interna +addTunnel=Tunnel ... +addScript=Script ... +addHost=Host remoto ... +addShell=Ambiente Shell ... +addCommand=Comando personalizzato ... +addAutomatically=Ricerca automatica ... +addOther=Aggiungi altro ... +addConnection=Aggiungi connessione +skip=Saltare +addConnections=Nuovo +selectType=Seleziona il tipo +selectTypeDescription=Seleziona il tipo di connessione +selectShellType=Tipo di conchiglia +selectShellTypeDescription=Seleziona il tipo di connessione della shell +name=Nome +storeIntroTitle=Hub di connessione +storeIntroDescription=Qui puoi gestire tutte le tue connessioni shell locali e remote in un unico posto. Per iniziare, puoi rilevare rapidamente le connessioni disponibili in modo automatico e scegliere quali aggiungere. +detectConnections=Ricerca di connessioni +configuration=Configurazione +dragAndDropFilesHere=Oppure trascina e rilascia un file qui +confirmDsCreationAbortTitle=Conferma l'interruzione +confirmDsCreationAbortHeader=Vuoi interrompere la creazione dell'origine dati? +confirmDsCreationAbortContent=Qualsiasi progresso nella creazione di un'origine dati andrà perso. +confirmInvalidStoreTitle=Connessione fallita +confirmInvalidStoreHeader=Vuoi saltare la convalida della connessione? +confirmInvalidStoreContent=Puoi aggiungere questa connessione anche se non è stato possibile convalidarla e risolvere i problemi di connessione in un secondo momento. +none=Nessuno +expand=Espandi +accessSubConnections=Connessioni secondarie di accesso +common=Comune +color=Colore +alwaysConfirmElevation=Conferma sempre l'elevazione del permesso +alwaysConfirmElevationDescription=Controlla come gestire i casi in cui sono necessari permessi elevati per eseguire un comando su un sistema, ad esempio con sudo.\n\nPer impostazione predefinita, le credenziali sudo vengono memorizzate nella cache durante una sessione e fornite automaticamente quando necessario. Se l'opzione è attivata, ti verrà chiesto di confermare l'accesso all'elevazione ogni volta. +allow=Consenti +ask=Chiedere +deny=Rifiuta +share=Aggiungi al repository git +unshare=Rimuovere dal repository git +remove=Rimuovere +newCategory=Nuova sottocategoria +passwordManager=Gestore di password +prompt=Prompt +customCommand=Comando personalizzato +other=Altro +setLock=Imposta blocco +selectConnection=Seleziona la connessione +changeLock=Modifica della passphrase +test=Test +lockCreationAlertTitle=Imposta una passphrase +lockCreationAlertHeader=Imposta la tua nuova passphrase principale +finish=Terminare +error=Si è verificato un errore +downloadStageDescription=Scarica i file sul tuo computer locale, in modo che tu possa trascinarli e rilasciarli nel tuo ambiente desktop nativo. +ok=Ok +search=Ricerca +newFile=Nuovo file +newDirectory=Nuova directory +passphrase=Passphrase +repeatPassphrase=Ripeti la passphrase +password=Password +unlockAlertTitle=Sbloccare l'area di lavoro +unlockAlertHeader=Inserisci la passphrase del tuo vault per continuare +enterLockPassword=Inserisci la password di blocco +repeatPassword=Ripeti la password +askpassAlertTitle=Askpass +unsupportedOperation=Operazione non supportata: $MSG$ +fileConflictAlertTitle=Risolvere un conflitto +fileConflictAlertHeader=È stato riscontrato un conflitto. Come vuoi procedere? +fileConflictAlertContent=Il file $FILE$ esiste già sul sistema di destinazione. +fileConflictAlertContentMultiple=Il file $FILE$ esiste già. Potrebbero esserci altri conflitti che puoi risolvere automaticamente scegliendo un'opzione valida per tutti. +moveAlertTitle=Conferma la mossa +moveAlertHeader=Vuoi spostare gli elementi selezionati ($COUNT$) in $TARGET$? +deleteAlertTitle=Conferma l'eliminazione +deleteAlertHeader=Vuoi cancellare gli elementi ($COUNT$) selezionati? +selectedElements=Elementi selezionati: +mustNotBeEmpty=$VALUE$ non deve essere vuoto +valueMustNotBeEmpty=Il valore non deve essere vuoto +transferDescription=Rilasciare i file da trasferire +dragFiles=Trascinare i file nel browser +dragLocalFiles=Trascina i file locali da qui +null=$VALUE$ deve essere non nullo +roots=Radici +scripts=Script +searchFilter=Ricerca ... +recent=Recente +shortcut=Scorciatoia +browserWelcomeEmpty=Qui potrai vedere dove ti sei fermato l'ultima volta. +browserWelcomeSystems=Recentemente sei stato collegato ai seguenti sistemi: +hostFeatureUnsupported=$FEATURE$ non è installato sull'host +missingStore=$NAME$ non esiste +connectionName=Nome della connessione +connectionNameDescription=Assegna a questa connessione un nome personalizzato +openFileTitle=Aprire un file +unknown=Sconosciuto +scanAlertTitle=Aggiungi connessioni +scanAlertChoiceHeader=Obiettivo +scanAlertChoiceHeaderDescription=Scegli dove cercare le connessioni. In questo modo verranno cercate prima tutte le connessioni disponibili. +scanAlertHeader=Tipi di connessione +scanAlertHeaderDescription=Seleziona i tipi di connessioni che vuoi aggiungere automaticamente al sistema. +noInformationAvailable=Nessuna informazione disponibile +localMachine=Macchina locale +yes=Sì +no=No +errorOccured=Si è verificato un errore +terminalErrorOccured=Si è verificato un errore del terminale +errorTypeOccured=È stata lanciata un'eccezione del tipo $TYPE$ +permissionsAlertTitle=Permessi richiesti +permissionsAlertHeader=Per eseguire questa operazione sono necessari ulteriori permessi. +permissionsAlertContent=Segui il pop-up per dare a XPipe i permessi richiesti nel menu delle impostazioni. +errorDetails=Mostra i dettagli +updateReadyAlertTitle=Aggiornamento pronto +updateReadyAlertHeader=L'aggiornamento alla versione $VERSION$ è pronto per essere installato +updateReadyAlertContent=Questo installerà la nuova versione e riavvierà XPipe al termine dell'installazione. +errorNoDetail=Non sono disponibili dettagli sull'errore +updateAvailableTitle=Aggiornamento disponibile +updateAvailableHeader=È disponibile l'aggiornamento di XPipe alla versione $VERSION$ +updateAvailableContent=Anche se non è stato possibile avviare XPipe, puoi provare a installare l'aggiornamento per risolvere il problema. +clipboardActionDetectedTitle=Azione Appunti rilevata +clipboardActionDetectedHeader=Vuoi importare il contenuto dei tuoi appunti? +clipboardActionDetectedContent=XPipe ha rilevato un contenuto negli appunti che può essere aperto. Vuoi aprirlo ora? +install=Installare ... +ignore=Ignorare +possibleActions=Azioni possibili +reportError=Segnala un errore +reportOnGithub=Crea una segnalazione di problema su GitHub +reportOnGithubDescription=Apri un nuovo problema nel repository di GitHub +reportErrorDescription=Inviare un rapporto di errore con un feedback opzionale dell'utente e informazioni di diagnostica +ignoreError=Ignora errore +ignoreErrorDescription=Ignora questo errore e continua come se niente fosse +provideEmail=Come contattarti (facoltativo, solo se vuoi essere avvisato delle correzioni) +additionalErrorInfo=Fornisce informazioni aggiuntive (facoltative) +additionalErrorAttachments=Seleziona gli allegati (opzionale) +dataHandlingPolicies=Politica sulla privacy +sendReport=Invia un rapporto +errorHandler=Gestore degli errori +events=Eventi +method=Metodo +validate=Convalidare +stackTrace=Traccia dello stack +previousStep=< Precedente +nextStep=Avanti > +finishStep=Terminare +edit=Modifica +browseInternal=Sfogliare interno +checkOutUpdate=Aggiornamento del check out +open=Aprire +quit=Abbandono +noTerminalSet=Nessuna applicazione terminale è stata impostata automaticamente. Puoi farlo manualmente nel menu delle impostazioni. +connections=Connessioni +settings=Impostazioni +explorePlans=Licenza +help=Aiuto +about=Informazioni su +developer=Sviluppatore +browseFileTitle=Sfogliare un file +browse=Sfogliare +browser=Browser +selectFileFromComputer=Seleziona un file da questo computer +links=Link utili +website=Sito web +documentation=Documentazione +discordDescription=Unisciti al server Discord +security=Sicurezza +securityPolicy=Informazioni sulla sicurezza +securityPolicyDescription=Leggi la politica di sicurezza dettagliata +privacy=Informativa sulla privacy +privacyDescription=Leggi l'informativa sulla privacy dell'applicazione XPipe +slackDescription=Unisciti allo spazio di lavoro Slack +support=Supporto +githubDescription=Scopri il repository GitHub +openSourceNotices=Avvisi Open Source +xPipeClient=XPipe Desktop +checkForUpdates=Controlla gli aggiornamenti +checkForUpdatesDescription=Scaricare un aggiornamento, se presente +lastChecked=Ultimo controllo +version=Versione +build=Versione di costruzione +runtimeVersion=Versione runtime +virtualMachine=Macchina virtuale +updateReady=Installare l'aggiornamento +updateReadyPortable=Aggiornamento del check out +updateReadyDescription=Un aggiornamento è stato scaricato ed è pronto per essere installato +updateReadyDescriptionPortable=Un aggiornamento è disponibile per il download +updateRestart=Riavviare per aggiornare +never=Mai +updateAvailableTooltip=Aggiornamento disponibile +visitGithubRepository=Visita il repository GitHub +updateAvailable=Aggiornamento disponibile: $VERSION$ +downloadUpdate=Scarica l'aggiornamento +legalAccept=Accetto il Contratto di licenza con l'utente finale +confirm=Confermare +print=Stampare +whatsNew=Cosa c'è di nuovo nella versione $VERSION$ ($DATE$) +antivirusNoticeTitle=Una nota sui programmi antivirus +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Benvenuto in XPipe +gotIt=Capito +eula=Contratto di licenza con l'utente finale +news=Notizie +introduction=Introduzione +privacyPolicy=Informativa sulla privacy +agree=Accettare +disagree=Non sono d'accordo +directories=Elenchi +logFile=File di log +logFiles=File di log +logFilesAttachment=File di log +issueReporter=Segnalatore di problemi +openCurrentLogFile=File di log +openCurrentLogFileDescription=Aprire il file di log della sessione corrente +openLogsDirectory=Aprire la directory dei log +installationFiles=File di installazione +openInstallationDirectory=File di installazione +openInstallationDirectoryDescription=Aprire la directory di installazione di XPipe +launchDebugMode=Modalità di debug +launchDebugModeDescription=Riavviare XPipe in modalità debug +extensionInstallTitle=Scarica +extensionInstallDescription=Questa azione richiede librerie aggiuntive di terze parti che non sono distribuite da XPipe. Puoi installarle automaticamente qui. I componenti vengono poi scaricati dal sito web del fornitore: +extensionInstallLicenseNote=Effettuando il download e l'installazione automatica accetti i termini delle licenze di terze parti: +license=Licenza +installRequired=Installazione richiesta +restore=Ripristino +restoreAllSessions=Ripristina tutte le sessioni +connectionTimeout=Timeout di avvio della connessione +connectionTimeoutDescription=Il tempo in secondi per attendere una risposta prima di considerare la connessione interrotta. Se alcuni dei tuoi sistemi remoti impiegano molto tempo per connettersi, puoi provare ad aumentare questo valore. +useBundledTools=Usa gli strumenti OpenSSH in dotazione +useBundledToolsDescription=Preferisci utilizzare la versione del client openssh in bundle invece di quella installata localmente.\n\nQuesta versione è solitamente più aggiornata di quella fornita sul tuo sistema e potrebbe supportare funzionalità aggiuntive. In questo modo si elimina anche la necessità di installare questi strumenti.\n\nRichiede il riavvio per essere applicato. +appearance=Aspetto +integrations=Integrazioni +uiOptions=Opzioni UI +theme=Tema +rdp=Desktop remoto +rdpConfiguration=Configurazione del desktop remoto +rdpClient=Client RDP +rdpClientDescription=Il programma client RDP da richiamare quando si avviano le connessioni RDP.\n\nSi noti che i vari client hanno diversi gradi di abilità e integrazioni. Alcuni client non supportano il passaggio automatico delle password, per cui è necessario inserirle all'avvio. +localShell=Guscio locale +themeDescription=Il tema di visualizzazione che preferisci +dontAutomaticallyStartVmSshServer=Non avviare automaticamente il server SSH per le macchine virtuali quando necessario +dontAutomaticallyStartVmSshServerDescription=Qualsiasi connessione shell a una macchina virtuale in esecuzione in un hypervisor viene effettuata tramite SSH. XPipe può avviare automaticamente il server SSH installato quando necessario. Se non vuoi che ciò avvenga per motivi di sicurezza, puoi disabilitare questo comportamento con questa opzione. +confirmGitShareTitle=Conferma la condivisione di git +confirmGitShareHeader=In questo modo il file verrà copiato nel tuo git vault e le tue modifiche verranno inviate. Vuoi continuare? +gitShareFileTooltip=Aggiungi un file alla directory dei dati di git vault in modo che venga sincronizzato automaticamente.\n\nQuesta azione può essere utilizzata solo se il git vault è abilitato nelle impostazioni. +performanceMode=Modalità di prestazione +performanceModeDescription=Disattiva tutti gli effetti visivi non necessari per migliorare le prestazioni dell'applicazione. +dontAcceptNewHostKeys=Non accettare automaticamente le nuove chiavi host SSH +dontAcceptNewHostKeysDescription=XPipe accetta automaticamente le chiavi host per impostazione predefinita dai sistemi in cui il tuo client SSH non ha una chiave host nota già salvata. Tuttavia, se la chiave host conosciuta è cambiata, si rifiuterà di connettersi a meno che tu non accetti quella nuova.\n\nDisabilitare questo comportamento ti permette di controllare tutte le chiavi host, anche se inizialmente non c'è alcun conflitto. +uiScale=Scala UI +uiScaleDescription=Un valore di scala personalizzato che può essere impostato indipendentemente dalla scala di visualizzazione del sistema. I valori sono espressi in percentuale, quindi, ad esempio, un valore di 150 corrisponde a una scala dell'interfaccia utente del 150%.\n\nRichiede un riavvio per essere applicato. +editorProgram=Programma Editor +editorProgramDescription=L'editor di testo predefinito da utilizzare per modificare qualsiasi tipo di dato testuale. +windowOpacity=Opacità della finestra +windowOpacityDescription=Cambia l'opacità della finestra per tenere traccia di ciò che accade sullo sfondo. +useSystemFont=Usa il font di sistema +openDataDir=Directory di dati del caveau +openDataDirButton=Elenco di dati aperti +openDataDirDescription=Se vuoi sincronizzare altri file, come le chiavi SSH, tra i vari sistemi con il tuo repository git, puoi inserirli nella directory dei dati di archiviazione. Tutti i file che vi fanno riferimento avranno il loro percorso adattato automaticamente su ogni sistema sincronizzato. +updates=Aggiornamenti +passwordKey=Chiave password +selectAll=Seleziona tutti +command=Comando +advanced=Avanzato +thirdParty=Avvisi open source +eulaDescription=Leggi il Contratto di licenza con l'utente finale per l'applicazione XPipe +thirdPartyDescription=Visualizza le licenze open source delle librerie di terze parti +workspaceLock=Passphrase principale +enableGitStorage=Abilita la sincronizzazione git +sharing=Condivisione +sync=Sincronizzazione +enableGitStorageDescription=Se abilitato, XPipe inizializzerà un repository git per l'archiviazione dei dati di connessione e vi apporterà tutte le modifiche. Questo richiede l'installazione di git e potrebbe rallentare le operazioni di caricamento e salvataggio.\n\nTutte le categorie che devono essere sincronizzate devono essere esplicitamente designate come condivise.\n\nRichiede un riavvio per essere applicato. +storageGitRemote=URL remoto di Git +storageGitRemoteDescription=Se impostato, XPipe preleverà automaticamente le modifiche al momento del caricamento e le invierà al repository remoto al momento del salvataggio.\n\nQuesto ti permette di condividere i dati di configurazione tra più installazioni di XPipe. Sono supportati sia gli URL HTTP che SSH. Si noti che questo potrebbe rallentare le operazioni di caricamento e salvataggio.\n\nRichiede un riavvio per essere applicata. +vault=Volta +workspaceLockDescription=Imposta una password personalizzata per criptare le informazioni sensibili memorizzate in XPipe.\n\nQuesto aumenta la sicurezza in quanto fornisce un ulteriore livello di crittografia per le informazioni sensibili memorizzate. All'avvio di XPipe ti verrà richiesto di inserire la password. +useSystemFontDescription=Controlla se utilizzare il font di sistema o il font Roboto fornito con XPipe. +tooltipDelay=Ritardo del tooltip +tooltipDelayDescription=La quantità di millisecondi da attendere prima che venga visualizzato un tooltip. +fontSize=Dimensione del carattere +windowOptions=Opzioni della finestra +saveWindowLocation=Posizione della finestra di salvataggio +saveWindowLocationDescription=Controlla se le coordinate della finestra devono essere salvate e ripristinate al riavvio. +startupShutdown=Avvio / Spegnimento +showChildCategoriesInParentCategory=Mostra le categorie figlio nella categoria padre +showChildCategoriesInParentCategoryDescription=Se includere o meno tutte le connessioni situate nelle sottocategorie quando viene selezionata una determinata categoria madre.\n\nSe questa opzione è disattivata, le categorie si comportano come le classiche cartelle che mostrano solo il loro contenuto diretto senza includere le sottocartelle. +condenseConnectionDisplay=Visualizzazione condensata delle connessioni +condenseConnectionDisplayDescription=Fai in modo che ogni connessione di primo livello occupi meno spazio in verticale per consentire un elenco di connessioni più sintetico. +enforceWindowModality=Applicare la modalità della finestra +enforceWindowModalityDescription=Fa sì che le finestre secondarie, come la finestra di dialogo per la creazione di una connessione, blocchino tutti gli input della finestra principale mentre sono aperte. Questo è utile se a volte sbagli a cliccare. +openConnectionSearchWindowOnConnectionCreation=Aprire la finestra di ricerca delle connessioni alla creazione della connessione +openConnectionSearchWindowOnConnectionCreationDescription=Se aprire o meno automaticamente la finestra per la ricerca delle sottoconnessioni disponibili quando si aggiunge una nuova connessione shell. +workflow=Flusso di lavoro +system=Sistema +application=Applicazione +storage=Conservazione +runOnStartup=Eseguire all'avvio +closeBehaviour=Comportamento di chiusura +closeBehaviourDescription=Controlla come XPipe deve procedere alla chiusura della sua finestra principale. +language=Lingua +languageDescription=Il linguaggio di visualizzazione da utilizzare.\n\nSi noti che queste traduzioni utilizzano le traduzioni automatiche come base e vengono corrette e migliorate manualmente dai collaboratori. Puoi anche aiutare il lavoro di traduzione inviando correzioni di traduzione su GitHub. +lightTheme=Tema luminoso +darkTheme=Tema scuro +exit=Esci da XPipe +continueInBackground=Continua sullo sfondo +minimizeToTray=Ridurre a icona la barra delle applicazioni +closeBehaviourAlertTitle=Imposta il comportamento di chiusura +closeBehaviourAlertTitleHeader=Seleziona cosa deve accadere alla chiusura della finestra. Tutte le connessioni attive verranno chiuse quando l'applicazione verrà chiusa. +startupBehaviour=Comportamento all'avvio +startupBehaviourDescription=Controlla il comportamento predefinito dell'applicazione desktop all'avvio di XPipe. +clearCachesAlertTitle=Pulire la cache +clearCachesAlertTitleHeader=Vuoi pulire tutte le cache di XPipe? +clearCachesAlertTitleContent=Si noti che in questo modo verranno eliminati tutti i dati memorizzati per migliorare l'esperienza dell'utente. +startGui=Avvio dell'interfaccia grafica +startInTray=Avvio in tray +startInBackground=Avvio in background +clearCaches=Cancella le cache ... +clearCachesDescription=Elimina tutti i dati della cache +apply=Applicare +cancel=Annulla +notAnAbsolutePath=Non è un percorso assoluto +notADirectory=Non una directory +notAnEmptyDirectory=Non una directory vuota +automaticallyUpdate=Controlla gli aggiornamenti +automaticallyUpdateDescription=Se abilitato, le informazioni sulle nuove versioni vengono recuperate automaticamente mentre XPipe è in esecuzione. Non viene eseguito alcun programma di aggiornamento in background e devi comunque confermare esplicitamente l'installazione di qualsiasi aggiornamento. +sendAnonymousErrorReports=Invia segnalazioni di errore anonime +sendUsageStatistics=Inviare statistiche d'uso anonime +storageDirectory=Directory di archiviazione +storageDirectoryDescription=La posizione in cui XPipe deve memorizzare tutte le informazioni sulla connessione. Questa impostazione verrà applicata solo al successivo riavvio. Quando si modifica questa impostazione, i dati presenti nella vecchia directory non vengono copiati in quella nuova. +logLevel=Livello di log +appBehaviour=Comportamento dell'applicazione +logLevelDescription=Il livello di log da utilizzare per la scrittura dei file di log. +developerMode=Modalità sviluppatore +developerModeDescription=Se abilitato, avrai accesso a una serie di opzioni aggiuntive utili per lo sviluppo. Si attiva solo dopo un riavvio. +editor=Editore +custom=Personalizzato +passwordManagerCommand=Comando del gestore di password +passwordManagerCommandDescription=Il comando da eseguire per recuperare le password. La stringa segnaposto $KEY sarà sostituita dalla chiave della password citata quando verrà richiamata. Questo comando dovrebbe richiamare la CLI del tuo gestore di password per stampare la password su stdout, ad esempio mypassmgr get $KEY.\n\nPuoi quindi impostare la chiave da recuperare ogni volta che imposti una connessione che richiede una password. +passwordManagerCommandTest=Test del gestore di password +passwordManagerCommandTestDescription=Puoi verificare se l'output è corretto se hai impostato un comando di gestione delle password. Il comando deve inviare a stdout solo la password stessa e non deve includere nessun'altra formattazione nell'output. +preferEditorTabs=Preferisce aprire nuove schede +preferEditorTabsDescription=Controlla se XPipe cercherà di aprire nuove schede nell'editor scelto invece che nuove finestre.\n\nNota che non tutti gli editor supportano questa opzione. +customRdpClientCommand=Comando personalizzato +customRdpClientCommandDescription=Il comando da eseguire per avviare il client RDP personalizzato.\n\nLa stringa segnaposto $FILE sarà sostituita dal nome assoluto del file .rdp quotato quando verrà richiamata. Ricordati di citare il percorso dell'eseguibile se contiene spazi. +customEditorCommand=Comando dell'editor personalizzato +customEditorCommandDescription=Il comando da eseguire per avviare l'editor personalizzato.\n\nLa stringa segnaposto $FILE sarà sostituita dal nome assoluto del file quotato quando verrà richiamata. Ricordati di citare il percorso dell'editor eseguibile se contiene spazi. +editorReloadTimeout=Timeout di ricarica dell'editor +editorReloadTimeoutDescription=Il numero di millisecondi da attendere prima di leggere un file dopo che è stato aggiornato. In questo modo si evitano problemi nei casi in cui l'editor è lento a scrivere o a rilasciare i blocchi dei file. +encryptAllVaultData=Crittografa tutti i dati del caveau +encryptAllVaultDataDescription=Quando è abilitato, ogni parte dei dati di connessione al vault sarà crittografata, anziché solo i segreti contenuti in tali dati. Questo aggiunge un ulteriore livello di sicurezza per altri parametri come nomi utente, hostname e così via, che non sono crittografati di default nel vault.\n\nQuesta opzione renderà inutile la cronologia e i diff del tuo vault git, in quanto non potrai più vedere le modifiche originali, ma solo quelle binarie. +vaultSecurity=Sicurezza del caveau +developerDisableUpdateVersionCheck=Disabilita il controllo della versione dell'aggiornamento +developerDisableUpdateVersionCheckDescription=Controlla se il verificatore di aggiornamenti ignora il numero di versione quando cerca un aggiornamento. +developerDisableGuiRestrictions=Disabilita le restrizioni della GUI +developerDisableGuiRestrictionsDescription=Controlla se alcune azioni disabilitate possono essere eseguite dall'interfaccia utente. +developerShowHiddenEntries=Mostra voci nascoste +developerShowHiddenEntriesDescription=Se abilitato, le fonti di dati nascoste e interne verranno mostrate. +developerShowHiddenProviders=Mostra fornitori nascosti +developerShowHiddenProvidersDescription=Controlla se i provider di connessione e di origine dati nascosti e interni saranno mostrati nella finestra di dialogo di creazione. +developerDisableConnectorInstallationVersionCheck=Disabilita il controllo della versione del connettore +developerDisableConnectorInstallationVersionCheckDescription=Controlla se il verificatore di aggiornamenti ignora il numero di versione quando controlla la versione di un connettore XPipe installato su un computer remoto. +shellCommandTest=Test dei comandi di shell +shellCommandTestDescription=Eseguire un comando nella sessione di shell utilizzata internamente da XPipe. +terminal=Terminale +terminalEmulator=Emulatore di terminale +terminalConfiguration=Configurazione del terminale +editorConfiguration=Configurazione dell'editor +defaultApplication=Applicazione predefinita +terminalEmulatorDescription=Il terminale predefinito da utilizzare quando si apre una connessione shell di qualsiasi tipo. Questa applicazione è utilizzata solo a scopo di visualizzazione, il programma di shell avviato dipende dalla connessione di shell stessa.\n\nIl livello di supporto delle funzioni varia a seconda del terminale, per questo motivo ognuno di essi è contrassegnato come raccomandato o non raccomandato. Tutti i terminali non raccomandati funzionano con XPipe ma potrebbero mancare di funzioni come le schede, i colori dei titoli, il supporto alla shell e altro ancora. La tua esperienza d'uso sarà migliore quando userai un terminale raccomandato. +program=Programma +customTerminalCommand=Comando di terminale personalizzato +customTerminalCommandDescription=Il comando da eseguire per aprire il terminale personalizzato con un determinato comando.\n\nXPipe creerà uno script di lancio temporaneo da eseguire sul tuo terminale. La stringa segnaposto $CMD nel comando fornito verrà sostituita dallo script di avvio effettivo quando verrà richiamato. Ricordati di citare il percorso dell'eseguibile del tuo terminale se contiene spazi. +clearTerminalOnInit=Cancella il terminale all'avvio +clearTerminalOnInitDescription=Quando è abilitato, XPipe esegue un comando di cancellazione quando viene avviata una nuova sessione di terminale per rimuovere qualsiasi output non necessario. +enableFastTerminalStartup=Abilita l'avvio rapido del terminale +enableFastTerminalStartupDescription=Quando è abilitato, le sessioni del terminale vengono avviate più rapidamente quando possibile.\n\nIn questo modo verranno saltati diversi controlli all'avvio e non verranno aggiornate le informazioni di sistema visualizzate. Eventuali errori di connessione saranno visualizzati solo nel terminale. +dontCachePasswords=Non memorizzare nella cache le password richieste +dontCachePasswordsDescription=Controlla se le password interrogate devono essere memorizzate nella cache interna di XPipe in modo da non doverle inserire nuovamente nella sessione corrente.\n\nSe questo comportamento è disattivato, dovrai reinserire le credenziali richieste ogni volta che il sistema le richiederà. +denyTempScriptCreation=Rifiuta la creazione di script temporanei +denyTempScriptCreationDescription=Per realizzare alcune delle sue funzionalità, XPipe a volte crea degli script di shell temporanei sul sistema di destinazione per consentire una facile esecuzione di semplici comandi. Questi non contengono informazioni sensibili e vengono creati solo a scopo di implementazione.\n\nSe questo comportamento è disattivato, XPipe non creerà alcun file temporaneo su un sistema remoto. Questa opzione è utile in contesti ad alta sicurezza in cui ogni modifica del file system viene monitorata. Se questa opzione è disattivata, alcune funzionalità, ad esempio gli ambienti di shell e gli script, non funzioneranno come previsto. +disableCertutilUse=Disabilitare l'uso di certutil su Windows +useLocalFallbackShell=Usa la shell di fallback locale +useLocalFallbackShellDescription=Passa all'utilizzo di un'altra shell locale per gestire le operazioni locali. Si tratta di PowerShell su Windows e di bourne shell su altri sistemi.\n\nQuesta opzione può essere utilizzata nel caso in cui la normale shell locale predefinita sia disabilitata o in qualche modo danneggiata. Alcune funzioni potrebbero però non funzionare come previsto quando questa opzione è attivata.\n\nRichiede un riavvio per essere applicata. +disableCertutilUseDescription=A causa di diverse carenze e bug di cmd.exe, gli script di shell temporanei vengono creati con certutil utilizzandolo per decodificare l'input base64, dato che cmd.exe si interrompe in caso di input non ASCII. XPipe può anche utilizzare PowerShell per questo scopo, ma sarà più lento.\n\nQuesto disabilita l'uso di certutil sui sistemi Windows per realizzare alcune funzionalità e si ripiega su PowerShell. Questo potrebbe far piacere ad alcuni AV che bloccano l'uso di certutil. +disableTerminalRemotePasswordPreparation=Disabilita la preparazione della password remota del terminale +disableTerminalRemotePasswordPreparationDescription=Nelle situazioni in cui è necessario stabilire nel terminale una connessione shell remota che attraversa più sistemi intermedi, potrebbe essere necessario preparare le password richieste su uno dei sistemi intermedi per consentire la compilazione automatica di eventuali richieste.\n\nSe non vuoi che le password vengano mai trasferite a un sistema intermedio, puoi disabilitare questo comportamento. Le password intermedie richieste verranno quindi richieste nel terminale stesso all'apertura. +more=Di più +translate=Traduzioni +allConnections=Tutte le connessioni +allScripts=Tutti gli script +predefined=Predefinito +default=Predefinito +goodMorning=Buongiorno +goodAfternoon=Buon pomeriggio +goodEvening=Buona sera +addVisual=Visual ... +ssh=SSH +sshConfiguration=Configurazione SSH +size=Dimensione +attributes=Attributi +modified=Modificato +isOnlySupported=è supportato solo con una licenza professionale +areOnlySupported=sono supportati solo con una licenza professionale +updateReadyTitle=Aggiornamento a $VERSION$ ready diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties new file mode 100644 index 000000000..7e341d191 --- /dev/null +++ b/lang/app/strings/translations_ja.properties @@ -0,0 +1,426 @@ +delete=削除する +rename=名前を変更する +properties=プロパティ +usedDate=中古$DATE$ +openDir=オープンディレクトリ +sortLastUsed=最終使用日でソートする +sortAlphabetical=アルファベット順に並べる +restart=XPipeを再起動する +restartDescription=再起動はしばしば迅速な解決策となる +reportIssue=問題を報告する +reportIssueDescription=統合issueレポーターを開く +usefulActions=便利なアクション +stored=保存された +troubleshootingOptions=トラブルシューティングツール +troubleshoot=トラブルシューティング +remote=リモートファイル +addShellStore=シェルを追加する +addShellTitle=シェル接続を追加する +savedConnections=保存されたコネクション +save=保存する +clean=きれいにする +refresh=リフレッシュする +moveTo=移動する +addDatabase=データベース ... +browseInternalStorage=内部ストレージをブラウズする +addTunnel=トンネル ... +addScript=スクリプト ... +addHost=リモートホスト ... +addShell=シェル環境 ... +addCommand=カスタムコマンド ... +addAutomatically=自動的に検索する +addOther=その他を追加する +addConnection=接続を追加する +skip=スキップする +addConnections=新しい +selectType=タイプを選択する +selectTypeDescription=接続タイプを選択する +selectShellType=シェルタイプ +selectShellTypeDescription=シェル接続のタイプを選択する +name=名称 +storeIntroTitle=接続ハブ +storeIntroDescription=ここでは、ローカルとリモートのシェル接続をすべて一箇所で管理できる。まず始めに、利用可能な接続を自動的に素早く検出し、追加する接続を選択できる。 +detectConnections=接続を検索する +configuration=構成 +dragAndDropFilesHere=または、ここにファイルをドラッグ&ドロップする +confirmDsCreationAbortTitle=中止を確認する +confirmDsCreationAbortHeader=データ・ソースの作成を中止するか? +confirmDsCreationAbortContent=データソース作成の進行状況はすべて失われる。 +confirmInvalidStoreTitle=接続に失敗した +confirmInvalidStoreHeader=接続検証をスキップするか? +confirmInvalidStoreContent=接続が検証できなくても、この接続を追加し、後で接続の問題を修正することができる。 +none=なし +expand=拡大する +accessSubConnections=アクセスサブ接続 +common=一般的な +color=カラー +alwaysConfirmElevation=許可昇格を常に確認する +alwaysConfirmElevationDescription=sudoなど、システム上でコマンドを実行するために昇格パーミッションが必要な場合の処理方法を制御する。\n\nデフォルトでは、sudo認証情報はセッション中にキャッシュされ、必要なときに自動的に提供される。このオプションを有効にすると、毎回昇格アクセスの確認を求められる。 +allow=許可する +ask=尋ねる +deny=拒否する +share=gitリポジトリに追加する +unshare=gitリポジトリから削除する +remove=削除する +newCategory=新しいサブカテゴリー +passwordManager=パスワードマネージャー +prompt=プロンプト +customCommand=カスタムコマンド +other=その他 +setLock=ロックを設定する +selectConnection=接続を選択する +changeLock=パスフレーズを変更する +test=テスト +lockCreationAlertTitle=パスフレーズを設定する +lockCreationAlertHeader=新しいマスターパスフレーズを設定する +finish=終了する +error=エラーが発生した +downloadStageDescription=ファイルをローカルマシンにダウンロードし、ネイティブのデスクトップ環境にドラッグ&ドロップできるようにする。 +ok=OK +search=検索 +newFile=新規ファイル +newDirectory=新しいディレクトリ +passphrase=パスフレーズ +repeatPassphrase=パスフレーズを繰り返す +password=パスワード +unlockAlertTitle=ワークスペースのロックを解除する +unlockAlertHeader=保管庫のパスフレーズを入力して続行する +enterLockPassword=ロックパスワードを入力する +repeatPassword=リピートパスワード +askpassAlertTitle=アスクパス +unsupportedOperation=サポートされていない操作:$MSG$ +fileConflictAlertTitle=衝突を解決する +fileConflictAlertHeader=コンフリクトが発生した。どうする? +fileConflictAlertContent=ファイル$FILE$ はターゲット・システムに既に存在する。 +fileConflictAlertContentMultiple=ファイル$FILE$ はすでに存在する。すべてに適用されるオプションを選択することで、自動的に解決できる競合がもっとあるかもしれない。 +moveAlertTitle=動きを確認する +moveAlertHeader=($COUNT$) で選択した要素を$TARGET$ に移動させたいか? +deleteAlertTitle=削除を確認する +deleteAlertHeader=選択した ($COUNT$) 要素を削除するか? +selectedElements=選択された要素: +mustNotBeEmpty=$VALUE$ は空であってはならない +valueMustNotBeEmpty=値は空であってはならない +transferDescription=ファイルをドロップして転送する +dragFiles=ブラウザ内でファイルをドラッグする +dragLocalFiles=ここからローカルファイルをドラッグする +null=$VALUE$ はnullであってはならない。 +roots=ルーツ +scripts=スクリプト +searchFilter=検索 ... +recent=最近の +shortcut=ショートカット +browserWelcomeEmpty=ここで、前回の続きを見ることができる。 +browserWelcomeSystems=あなたは最近、以下のシステムに接続した: +hostFeatureUnsupported=$FEATURE$ がホストにインストールされていない +missingStore=$NAME$ は存在しない +connectionName=接続名 +connectionNameDescription=この接続にカスタム名を付ける +openFileTitle=ファイルを開く +unknown=不明 +scanAlertTitle=接続を追加する +scanAlertChoiceHeader=ターゲット +scanAlertChoiceHeaderDescription=接続を検索する場所を選択する。これは、利用可能なすべての接続を最初に検索する。 +scanAlertHeader=接続タイプ +scanAlertHeaderDescription=システムに自動的に追加する接続のタイプを選択する。 +noInformationAvailable=情報がない +localMachine=ローカルマシン +yes=はい +no=いいえ +errorOccured=エラーが発生した +terminalErrorOccured=端末エラーが発生した +errorTypeOccured=$TYPE$ 型の例外が発生した。 +permissionsAlertTitle=必要なパーミッション +permissionsAlertHeader=この操作を行うには、追加のパーミッションが必要である。 +permissionsAlertContent=ポップアップに従い、XPipeの設定メニューで必要な権限を与える。 +errorDetails=詳細を表示する +updateReadyAlertTitle=更新準備完了 +updateReadyAlertHeader=バージョン$VERSION$ へのアップデートをインストールする準備ができた。 +updateReadyAlertContent=これで新しいバージョンがインストールされ、インストールが終了したらXPipeを再起動する。 +errorNoDetail=エラーの詳細がわからない +updateAvailableTitle=更新可能 +updateAvailableHeader=XPipeのバージョン$VERSION$ へのアップデートがインストール可能である。 +updateAvailableContent=XPipeが起動できなくても、更新プログラムをインストールすることで、問題を解決できる可能性がある。 +clipboardActionDetectedTitle=クリップボードアクションが検出された +clipboardActionDetectedHeader=クリップボードの内容をインポートしたい? +clipboardActionDetectedContent=XPipeがクリップボードのコンテンツを検出した。今すぐ開く? +install=インストールする +ignore=無視する +possibleActions=可能なアクション +reportError=エラーを報告する +reportOnGithub=GitHubで課題レポートを作成する +reportOnGithubDescription=GitHub リポジトリに新しい課題を投稿する +reportErrorDescription=任意のユーザーフィードバックと診断情報を含むエラーレポートを送信する +ignoreError=エラーを無視する +ignoreErrorDescription=このエラーを無視して、何事もなかったかのように続ける +provideEmail=連絡方法(任意、修正に関する通知を希望する場合のみ) +additionalErrorInfo=追加情報(オプション) +additionalErrorAttachments=添付ファイルを選択する(オプション) +dataHandlingPolicies=プライバシーポリシー +sendReport=レポートを送信する +errorHandler=エラーハンドラ +events=イベント +method=方法 +validate=検証する +stackTrace=スタックトレース +previousStep=< 前へ +nextStep=次のページ +finishStep=完了する +edit=編集する +browseInternal=内部をブラウズする +checkOutUpdate=更新をチェックする +open=開く +quit=終了する +noTerminalSet=端末アプリケーションが自動的に設定されていない。設定メニューで手動で設定できる。 +connections=接続 +settings=設定 +explorePlans=ライセンス +help=ヘルプ +about=について +developer=開発者 +browseFileTitle=ファイルをブラウズする +browse=閲覧する +browser=ブラウザ +selectFileFromComputer=このコンピューターからファイルを選択する +links=便利なリンク +website=ウェブサイト +documentation=ドキュメンテーション +discordDescription=Discordサーバーに参加する +security=セキュリティ +securityPolicy=セキュリティ情報 +securityPolicyDescription=詳細なセキュリティポリシーを読む +privacy=プライバシーポリシー +privacyDescription=XPipeアプリケーションのプライバシーポリシーを読む +slackDescription=Slackワークスペースに参加する +support=サポート +githubDescription=GitHubリポジトリをチェックする +openSourceNotices=オープンソースのお知らせ +xPipeClient=XPipeデスクトップ +checkForUpdates=アップデートを確認する +checkForUpdatesDescription=アップデートがあればダウンロードする +lastChecked=最終チェック +version=バージョン +build=ビルドバージョン +runtimeVersion=ランタイムバージョン +virtualMachine=仮想マシン +updateReady=アップデートをインストールする +updateReadyPortable=更新をチェックする +updateReadyDescription=アップデートがダウンロードされ、インストールする準備ができた。 +updateReadyDescriptionPortable=アップデートがダウンロードできる +updateRestart=再起動して更新する +never=決して +updateAvailableTooltip=更新可能 +visitGithubRepository=GitHub リポジトリを見る +updateAvailable=アップデート可能:$VERSION$ +downloadUpdate=ダウンロード更新 +legalAccept=エンドユーザーライセンス契約に同意する +confirm=確認する +print=印刷する +whatsNew=バージョン$VERSION$ ($DATE$) の新機能 +antivirusNoticeTitle=アンチウイルスプログラムについて +updateChangelogAlertTitle=変更履歴 +greetingsAlertTitle=XPipeへようこそ +gotIt=理解した +eula=エンドユーザー使用許諾契約書 +news=ニュース +introduction=はじめに +privacyPolicy=プライバシーポリシー +agree=同意する +disagree=同意しない +directories=ディレクトリ +logFile=ログファイル +logFiles=ログファイル +logFilesAttachment=ログファイル +issueReporter=問題レポーター +openCurrentLogFile=ログファイル +openCurrentLogFileDescription=現在のセッションのログファイルを開く +openLogsDirectory=ログディレクトリを開く +installationFiles=インストールファイル +openInstallationDirectory=インストールファイル +openInstallationDirectoryDescription=XPipeのインストールディレクトリを開く +launchDebugMode=デバッグモード +launchDebugModeDescription=XPipeをデバッグモードで再起動する +extensionInstallTitle=ダウンロード +extensionInstallDescription=このアクションには、XPipeが配布していない追加のサードパーティライブラリが必要である。ここで自動的にインストールできる。コンポーネントはベンダーのウェブサイトからダウンロードする: +extensionInstallLicenseNote=ダウンロードおよび自動インストールを実行することにより、サードパーティライセンスの条項に同意するものとする: +license=ライセンス +installRequired=インストールが必要 +restore=リストア +restoreAllSessions=すべてのセッションを復元する +connectionTimeout=接続開始タイムアウト +connectionTimeoutDescription=接続がタイムアウトしたと判断する前に、応答を待つ時間を秒単位で指定する。接続に時間がかかるリモート・システムがある場合は、この値を増やしてみるとよい。 +useBundledTools=バンドルされているOpenSSHツールを使う +useBundledToolsDescription=ローカルにインストールされているものではなく、バンドルされているバージョンのopensshクライアントを使用する。\n\nこのバージョンは通常、システムに同梱されているものよりも最新で、追加機能をサポートしているかもしれない。また、これらのツールを最初にインストールする必要もなくなる。\n\n適用には再起動が必要である。 +appearance=外観 +integrations=統合 +uiOptions=UIオプション +theme=テーマ +rdp=リモートデスクトップ +rdpConfiguration=リモートデスクトップの設定 +rdpClient=RDPクライアント +rdpClientDescription=RDP接続を開始するときに呼び出すRDPクライアントプログラム。\n\n様々なクライアントの能力や統合の程度が異なることに注意。クライアントの中には、パスワードの自動受け渡しに対応していないものもあるので、起動時にパスワードを入力する必要がある。 +localShell=ローカルシェル +themeDescription=お好みの表示テーマ +dontAutomaticallyStartVmSshServer=必要なときにVM用のSSHサーバーを自動的に起動しない +dontAutomaticallyStartVmSshServerDescription=ハイパーバイザーで稼働しているVMへのシェル接続は、SSHを介して行われる。XPipeは、必要に応じてインストールされたSSHサーバを自動的に起動することができる。セキュリティ上の理由でこれを望まない場合は、このオプションでこの動作を無効にすることができる。 +confirmGitShareTitle=git共有を確認する +confirmGitShareHeader=これでファイルが git vault にコピーされ、変更がコミットされる。続行する? +gitShareFileTooltip=git vaultのデータディレクトリにファイルを追加し、自動的に同期されるようにする。\n\nこのアクションは、設定で git vault が有効になっている場合にのみ使用できる。 +performanceMode=パフォーマンスモード +performanceModeDescription=アプリケーションのパフォーマンスを向上させるために不要な視覚効果をすべて無効にする。 +dontAcceptNewHostKeys=新しいSSHホスト鍵を自動的に受け取らない +dontAcceptNewHostKeysDescription=XPipeは、SSHクライアントに既知のホスト鍵が保存されていない場合、デフォルトで自動的にホスト鍵を受け付ける。しかし、既知のホスト鍵が変更されている場合は、新しいものを受け入れない限り接続を拒否する。\n\nこの動作を無効にすると、最初は競合していなくても、すべてのホスト鍵をチェックできるようになる。 +uiScale=UIスケール +uiScaleDescription=システム全体の表示スケールとは別に設定できるカスタムスケーリング値。値の単位はパーセントで、例えば150を指定するとUIのスケールは150%になる。\n\n適用には再起動が必要。 +editorProgram=エディタプログラム +editorProgramDescription=あらゆる種類のテキストデータを編集する際に使用するデフォルトのテキストエディタ。 +windowOpacity=ウィンドウの不透明度 +windowOpacityDescription=ウィンドウの不透明度を変更し、バックグラウンドで起こっていることを追跡する。 +useSystemFont=システムフォントを使用する +openDataDir=保管庫データディレクトリ +openDataDirButton=オープンデータディレクトリ +openDataDirDescription=SSH キーなどの追加ファイルを git リポジトリとシステム間で同期させたい場合は、storage data ディレクトリに置くことができる。そこで参照されるファイルは、同期されたシステムで自動的にファイルパスが適応される。 +updates=更新情報 +passwordKey=パスワードキー +selectAll=すべて選択する +command=コマンド +advanced=高度な +thirdParty=オープンソース通知 +eulaDescription=XPipeアプリケーションのエンドユーザーライセンス契約を読む +thirdPartyDescription=サードパーティライブラリのオープンソースライセンスを見る +workspaceLock=マスターパスフレーズ +enableGitStorage=git同期を有効にする +sharing=共有 +sync=同期 +enableGitStorageDescription=有効にすると、XPipeは接続データ保存用のgitリポジトリを初期化し、変更があればコミットする。これにはgitがインストールされている必要があり、読み込みや保存の動作が遅くなる可能性があることに注意。\n\n同期するカテゴリーは、明示的に共有として指定する必要がある。\n\n適用には再起動が必要である。 +storageGitRemote=GitリモートURL +storageGitRemoteDescription=設定すると、XPipeは読み込み時に変更点を自動的にプルし、保存時に変更点をリモートリポジトリにプッシュする。\n\nこれにより、複数のXPipeインストール間で設定データを共有することができる。HTTPとSSH URLの両方がサポートされている。読み込みと保存の動作が遅くなる可能性があることに注意。\n\n適用には再起動が必要。 +vault=金庫 +workspaceLockDescription=XPipeに保存されている機密情報を暗号化するためのカスタムパスワードを設定する。\n\nこれにより、保存された機密情報の暗号化レイヤーが追加され、セキュリティが向上する。XPipe起動時にパスワードの入力を求められる。 +useSystemFontDescription=システムフォントを使用するか、XPipeにバンドルされているRobotoフォントを使用するかを制御する。 +tooltipDelay=ツールチップの遅延 +tooltipDelayDescription=ツールチップが表示されるまでの待ち時間(ミリ秒)。 +fontSize=フォントサイズ +windowOptions=ウィンドウオプション +saveWindowLocation=ウィンドウの保存場所 +saveWindowLocationDescription=ウィンドウ座標を保存し、再起動時に復元するかどうかを制御する。 +startupShutdown=スタートアップ/シャットダウン +showChildCategoriesInParentCategory=親カテゴリーに子カテゴリーを表示する +showChildCategoriesInParentCategoryDescription=特定の親カテゴリが選択されたときに、サブカテゴリにあるすべての接続を含めるかどうか。\n\nこれを無効にすると、カテゴリはサブフォルダを含めずに直接の内容だけを表示する古典的なフォルダのように動作する。 +condenseConnectionDisplay=接続表示を凝縮する +condenseConnectionDisplayDescription=すべてのトップレベル接続の縦のスペースを少なくして、接続リストをより凝縮できるようにする。 +enforceWindowModality=ウィンドウのモダリティを強制する +enforceWindowModalityDescription=接続作成ダイアログなどのセカンダリウィンドウが開いている間、メインウィンドウへの入力をすべてブロックするようにする。これは、時々ミスクリックする場合に便利である。 +openConnectionSearchWindowOnConnectionCreation=接続作成時に接続検索ウィンドウを開く +openConnectionSearchWindowOnConnectionCreationDescription=新しいシェル接続を追加するときに、利用可能なサブ接続を検索するウィンドウを自動的に開くかどうか。 +workflow=ワークフロー +system=システム +application=アプリケーション +storage=ストレージ +runOnStartup=起動時に実行する +closeBehaviour=閉じる動作 +closeBehaviourDescription=XPipeのメインウィンドウを閉じたときの処理を制御する。 +language=言語 +languageDescription=使用する表示言語。\n\nこれらは自動翻訳をベースにしており、貢献者によって手作業で修正・改善されていることに注意してほしい。また、GitHubで翻訳の修正を投稿することで、翻訳作業を手伝うこともできる。 +lightTheme=ライトテーマ +darkTheme=ダークテーマ +exit=XPipeを終了する +continueInBackground=バックグラウンドで続ける +minimizeToTray=トレイに最小化する +closeBehaviourAlertTitle=閉じる動作を設定する +closeBehaviourAlertTitleHeader=ウィンドウを閉じるときの動作を選択する。アプリケーションがシャットダウンされると、アクティブな接続はすべて閉じられる。 +startupBehaviour=起動時の動作 +startupBehaviourDescription=XPipe起動時のデスクトップアプリケーションのデフォルト動作を制御する。 +clearCachesAlertTitle=クリーンキャッシュ +clearCachesAlertTitleHeader=XPipeのキャッシュをすべて削除する? +clearCachesAlertTitleContent=ユーザーエクスペリエンスを向上させるために保存されているすべてのデータが削除されることに注意すること。 +startGui=GUIを起動する +startInTray=トレイで起動する +startInBackground=バックグラウンドで起動する +clearCaches=キャッシュをクリアする +clearCachesDescription=すべてのキャッシュデータを削除する +apply=適用する +cancel=キャンセルする +notAnAbsolutePath=絶対パスではない +notADirectory=ディレクトリではない +notAnEmptyDirectory=空のディレクトリではない +automaticallyUpdate=アップデートを確認する +automaticallyUpdateDescription=有効にすると、XPipeの実行中に新しいリリース情報が自動的に取得される。アップデータはバックグラウンドで実行されず、アップデートのインストールを明示的に確認する必要がある。 +sendAnonymousErrorReports=匿名でエラーレポートを送信する +sendUsageStatistics=匿名で利用統計を送信する +storageDirectory=ストレージディレクトリ +storageDirectoryDescription=XPipeがすべての接続情報を保存する場所。この設定は次回再起動時にのみ適用される。この設定を変更すると、古いディレクトリのデータは新しいディレクトリにコピーされない。 +logLevel=ログレベル +appBehaviour=アプリケーションの動作 +logLevelDescription=ログファイルを書くときに使用するログレベル。 +developerMode=開発者モード +developerModeDescription=有効にすると、開発に役立つさまざまな追加オプションにアクセスできるようになる。再起動後にのみ有効になる。 +editor=エディター +custom=カスタム +passwordManagerCommand=パスワードマネージャーコマンド +passwordManagerCommandDescription=パスワードを取得するために実行するコマンド。プレースホルダ文字列$KEYは、呼び出されたときに引用符で囲まれたパスワードキーに置き換えられる。これは、パスワードを標準出力に出力するために、パスワードマネージャCLIを呼び出す必要がある。\n\nパスワードを必要とする接続をセットアップするときはいつでも、このキーを取得するように設定できる。 +passwordManagerCommandTest=テストパスワードマネージャー +passwordManagerCommandTestDescription=パスワード・マネージャー・コマンドをセットアップした場合、出力が正しく見えるかどうかをここでテストできる。コマンドはパスワードそのものを標準出力に出力するだけで、他の書式は出力に含まれないはずである。 +preferEditorTabs=新しいタブを開きたい +preferEditorTabsDescription=XPipeが新しいウィンドウではなく、選択したエディタで新しいタブを開こうとするかどうかを制御する。\n\nすべてのエディタが対応しているわけではないことに注意。 +customRdpClientCommand=カスタムコマンド +customRdpClientCommandDescription=カスタムRDPクライアントを起動するために実行するコマンド。\n\nプレースホルダ文字列$FILEは、呼び出されたときに引用符で囲まれた絶対.rdpファイル名に置き換えられる。実行パスにスペースが含まれている場合は、引用符で囲むことを忘れないこと。 +customEditorCommand=カスタムエディタコマンド +customEditorCommandDescription=カスタムエディタを起動するために実行するコマンド。\n\nプレースホルダー文字列$FILEは、呼び出されると引用符で囲まれた絶対ファイル名に置き換えられる。エディタの実行パスにスペースが含まれている場合は、引用符で囲むことを忘れないこと。 +editorReloadTimeout=エディタのリロードタイムアウト +editorReloadTimeoutDescription=ファイルが更新された後、そのファイルを読み込む前に待つミリ秒数。これは、エディターがファイルロックの書き込みや解放に時間がかかる場合の問題を回避する。 +encryptAllVaultData=すべての保管庫データを暗号化する +encryptAllVaultDataDescription=この機能を有効にすると、データ保管庫の接続データのあらゆる部分が暗号化される。これは、ユーザ名やホスト名など、デフォルトでは暗号化されていないデータ保管庫の他のパラメータに対して、セキュリティの別のレイヤーを追加するものである。\n\nこのオプションを指定すると、git vault の履歴と diff が無意味になり、元の変更を見ることができなくなる。 +vaultSecurity=金庫のセキュリティ +developerDisableUpdateVersionCheck=アップデートのバージョンチェックを無効にする +developerDisableUpdateVersionCheckDescription=アップデートチェッカーがアップデートを探すときにバージョン番号を無視するかどうかを制御する。 +developerDisableGuiRestrictions=GUIの制限を無効にする +developerDisableGuiRestrictionsDescription=無効にしたアクションをユーザーインターフェースから実行できるかどうかを制御する。 +developerShowHiddenEntries=隠しエントリーを表示する +developerShowHiddenEntriesDescription=有効にすると、非表示の内部データソースが表示される。 +developerShowHiddenProviders=非表示のプロバイダーを表示する +developerShowHiddenProvidersDescription=非表示の内部接続プロバイダとデータソースプロバイダを作成ダイアログに表示するかどうかを制御する。 +developerDisableConnectorInstallationVersionCheck=コネクタのバージョンチェックを無効にする +developerDisableConnectorInstallationVersionCheckDescription=リモートマシンにインストールされたXPipeコネクタのバージョンを検査するときに、アップデートチェッカがバージョン番号を無視するかどうかを制御する。 +shellCommandTest=シェルコマンドテスト +shellCommandTestDescription=XPipeが内部的に使用するシェルセッションでコマンドを実行する。 +terminal=ターミナル +terminalEmulator=ターミナルエミュレータ +terminalConfiguration=端末設定 +editorConfiguration=エディタ構成 +defaultApplication=デフォルトのアプリケーション +terminalEmulatorDescription=あらゆる種類のシェル接続を開くときに使用するデフォルトの端末。このアプリケーションは表示目的でのみ使用され、起動されるシェルプログラムはシェル接続そのものに依存する。\n\n端末によってサポートされる機能のレベルが異なるため、推奨または非推奨のマークが付けられている。非推奨端末はすべてXPipeで動作するが、タブ、タイトルカラー、シェルサポートなどの機能が欠けている可能性がある。推奨端末を使用することで、最高のユーザーエクスペリエンスが得られるだろう。 +program=プログラム +customTerminalCommand=カスタム端末コマンド +customTerminalCommandDescription=指定されたコマンドでカスタムターミナルを開くために実行するコマンド。\n\nXPipeは、端末が実行するための一時的なランチャー・シェル・スクリプトを作成する。指定したコマンドのプレースホルダ文字列$CMDは、呼び出されたときに実際のランチャー・スクリプトに置き換えられる。ターミナルの実行パスにスペースが含まれている場合は、引用符で囲むことを忘れないこと。 +clearTerminalOnInit=開始時にターミナルをクリアする +clearTerminalOnInitDescription=有効にすると、XPipeは新しいターミナル・セッションが起動したときにクリア・コマンドを実行し、不要な出力を削除する。 +enableFastTerminalStartup=端末の高速起動を有効にする +enableFastTerminalStartupDescription=有効にすると、端末セッションは可能な限り早く開始されるようになる。\n\nこれにより、いくつかの起動チェックがスキップされ、表示されるシステム情報は更新されない。接続エラーはターミナルにのみ表示される。 +dontCachePasswords=プロンプトのパスワードをキャッシュしない +dontCachePasswordsDescription=現在のセッションで再度入力する必要がないように、照会されたパスワードをXPipeが内部的にキャッシュするかどうかを制御する。\n\nこの動作を無効にすると、システムから要求されるたびに、プロンプトされた認証情報を再入力する必要がある。 +denyTempScriptCreation=一時的なスクリプトの作成を拒否する +denyTempScriptCreationDescription=XPipeは、その機能の一部を実現するために、ターゲットシステム上に一時的なシェルスクリプトを作成し、簡単なコマンドを簡単に実行できるようにすることがある。これらには機密情報は含まれておらず、単に実装のために作成される。\n\nこの動作を無効にすると、XPipeはリモートシステム上に一時ファイルを作成しない。このオプションは、ファイルシステムの変更がすべて監視されるようなセキュリティの高い状況で有用である。このオプションを無効にすると、シェル環境やスクリプトなど、一部の機能が意図したとおりに動作しなくなる。 +disableCertutilUse=Windowsでcertutilの使用を無効にする +useLocalFallbackShell=ローカルのフォールバックシェルを使う +useLocalFallbackShellDescription=ローカル操作を処理するために、別のローカルシェルを使うように切り替える。WindowsではPowerShell、その他のシステムではボーンシェルがこれにあたる。\n\nこのオプションは、通常のローカル・デフォルト・シェルが無効になっているか、ある程度壊れている場合に使用できる。このオプションが有効になっている場合、一部の機能は期待通りに動作しないかもしれない。\n\n適用には再起動が必要である。 +disableCertutilUseDescription=cmd.exeにはいくつかの欠点やバグがあるため、cmd.exeが非ASCII入力で壊れるように、certutilを使って一時的なシェルスクリプトを作成し、base64入力をデコードする。XPipeはPowerShellを使用することもできるが、その場合は動作が遅くなる。\n\nこれにより、Windowsシステムでcertutilを使用して一部の機能を実現することができなくなり、代わりにPowerShellにフォールバックする。AVの中にはcertutilの使用をブロックするものもあるので、これは喜ぶかもしれない。 +disableTerminalRemotePasswordPreparation=端末のリモートパスワードの準備を無効にする +disableTerminalRemotePasswordPreparationDescription=複数の中間システムを経由するリモートシェル接続をターミナルで確立する必要がある状況では、プロンプトを自動的に埋めることができるように、中間システムの1つに必要なパスワードを準備する必要があるかもしれない。\n\n中間システムにパスワードを転送したくない場合は、この動作を無効にすることができる。中間システムで必要なパスワードは、ターミナルを開いたときに照会される。 +more=詳細 +translate=翻訳 +allConnections=すべての接続 +allScripts=すべてのスクリプト +predefined=定義済み +default=デフォルト +goodMorning=おはよう +goodAfternoon=こんにちは +goodEvening=こんばんは +addVisual=ビジュアル ... +ssh=SSH +sshConfiguration=SSHの設定 +size=サイズ +attributes=属性 +modified=変更された +isOnlySupported=プロフェッショナルライセンスでのみサポートされる +areOnlySupported=プロフェッショナルライセンスでのみサポートされる +updateReadyTitle=$VERSION$ に更新 diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties new file mode 100644 index 000000000..5543c107b --- /dev/null +++ b/lang/app/strings/translations_nl.properties @@ -0,0 +1,426 @@ +delete=Verwijderen +rename=Hernoemen +properties=Eigenschappen +usedDate=Gebruikt $DATE$ +openDir=Open Directory +sortLastUsed=Sorteren op laatst gebruikte datum +sortAlphabetical=Sorteer alfabetisch op naam +restart=XPipe opnieuw opstarten +restartDescription=Een herstart kan vaak een snelle oplossing zijn +reportIssue=Een probleem melden +reportIssueDescription=Open de geïntegreerde issue reporter +usefulActions=Nuttige acties +stored=Opgeslagen +troubleshootingOptions=Hulpmiddelen voor probleemoplossing +troubleshoot=Problemen oplossen +remote=Afgelegen bestand +addShellStore=Shell toevoegen ... +addShellTitle=Shell-verbinding toevoegen +savedConnections=Opgeslagen verbindingen +save=Opslaan +clean=Maak schoon +refresh=Vernieuwen +moveTo=Naar ... +addDatabase=Databank ... +browseInternalStorage=Bladeren door interne opslag +addTunnel=Tunnel ... +addScript=Script ... +addHost=Externe host ... +addShell=Shell-omgeving ... +addCommand=Aangepaste opdracht ... +addAutomatically=Automatisch zoeken ... +addOther=Andere toevoegen ... +addConnection=Verbinding toevoegen +skip=Overslaan +addConnections=Nieuw +selectType=Selecteer type +selectTypeDescription=Verbindingstype kiezen +selectShellType=Type omhulsel +selectShellTypeDescription=Selecteer het type van de Shell-verbinding +name=Naam +storeIntroTitle=Verbindingshub +storeIntroDescription=Hier kun je al je lokale en externe shellverbindingen op één plek beheren. Om te beginnen kun je snel beschikbare verbindingen automatisch detecteren en kiezen welke je wilt toevoegen. +detectConnections=Zoeken naar verbindingen +configuration=Configuratie +dragAndDropFilesHere=Of sleep gewoon een bestand hierheen +confirmDsCreationAbortTitle=Afbreken bevestigen +confirmDsCreationAbortHeader=Wil je het maken van de gegevensbron afbreken? +confirmDsCreationAbortContent=Alle vorderingen bij het maken van gegevensbronnen gaan verloren. +confirmInvalidStoreTitle=Mislukte verbinding +confirmInvalidStoreHeader=Wil je verbindingsvalidatie overslaan? +confirmInvalidStoreContent=Je kunt deze verbinding toevoegen, zelfs als deze niet gevalideerd kon worden, en de verbindingsproblemen later oplossen. +none=Geen +expand=Uitvouwen +accessSubConnections=Toegang tot subverbindingen +common=Gewoon +color=Kleur +alwaysConfirmElevation=Toestemmingsverhoging altijd bevestigen +alwaysConfirmElevationDescription=Regelt hoe om te gaan met gevallen waarin verhoogde rechten nodig zijn om een commando op een systeem uit te voeren, bijvoorbeeld met sudo.\n\nStandaard worden alle sudo referenties in de cache geplaatst tijdens een sessie en automatisch verstrekt als ze nodig zijn. Als deze optie is ingeschakeld, wordt je elke keer gevraagd om de verhoogde toegang te bevestigen. +allow=Toestaan +ask=Vraag +deny=Weigeren +share=Toevoegen aan git repository +unshare=Verwijderen uit git repository +remove=Verwijderen +newCategory=Nieuwe subcategorie +passwordManager=Wachtwoord manager +prompt=Prompt +customCommand=Aangepaste opdracht +other=Andere +setLock=Slot instellen +selectConnection=Verbinding selecteren +changeLock=Wachtwoordzin wijzigen +test=Test +lockCreationAlertTitle=Passphrase instellen +lockCreationAlertHeader=Stel je nieuwe hoofdwachtzin in +finish=Beëindigen +error=Er is een fout opgetreden +downloadStageDescription=Downloadt bestanden naar je lokale computer, zodat je ze naar je eigen desktopomgeving kunt slepen. +ok=Ok +search=Zoeken +newFile=Nieuw bestand +newDirectory=Nieuwe map +passphrase=Passphrase +repeatPassphrase=Herhaal wachtwoordzin +password=Wachtwoord +unlockAlertTitle=Werkruimte ontgrendelen +unlockAlertHeader=Voer je wachtwoordzin voor de kluis in om verder te gaan +enterLockPassword=Wachtwoord voor slot invoeren +repeatPassword=Wachtwoord herhalen +askpassAlertTitle=Askpass +unsupportedOperation=Niet-ondersteunde bewerking: $MSG$ +fileConflictAlertTitle=Conflict oplossen +fileConflictAlertHeader=Er is een conflict opgetreden. Hoe wilt u verdergaan? +fileConflictAlertContent=Het bestand $FILE$ bestaat al op het doelsysteem. +fileConflictAlertContentMultiple=Het bestand $FILE$ bestaat al. Er kunnen meer conflicten zijn die je automatisch kunt oplossen door een optie te kiezen die voor iedereen geldt. +moveAlertTitle=Zet bevestigen +moveAlertHeader=Wil je de ($COUNT$) geselecteerde elementen verplaatsen naar $TARGET$? +deleteAlertTitle=Verwijdering bevestigen +deleteAlertHeader=Wil je de ($COUNT$) geselecteerde elementen verwijderen? +selectedElements=Geselecteerde elementen: +mustNotBeEmpty=$VALUE$ mag niet leeg zijn +valueMustNotBeEmpty=Waarde mag niet leeg zijn +transferDescription=Bestanden laten vallen om over te dragen +dragFiles=Bestanden slepen binnen browser +dragLocalFiles=Lokale bestanden van hier slepen +null=$VALUE$ moet not null zijn +roots=Wortels +scripts=Scripts +searchFilter=Zoeken ... +recent=Recent +shortcut=Snelkoppeling +browserWelcomeEmpty=Hier kun je zien waar je de vorige keer gebleven was. +browserWelcomeSystems=Je was onlangs verbonden met de volgende systemen: +hostFeatureUnsupported=$FEATURE$ is niet geïnstalleerd op de host +missingStore=$NAME$ bestaat niet +connectionName=Naam verbinding +connectionNameDescription=Geef deze verbinding een aangepaste naam +openFileTitle=Bestand openen +unknown=Onbekend +scanAlertTitle=Verbindingen toevoegen +scanAlertChoiceHeader=Doel +scanAlertChoiceHeaderDescription=Kies waar je wilt zoeken naar verbindingen. Hiermee worden eerst alle beschikbare verbindingen gezocht. +scanAlertHeader=Typen verbindingen +scanAlertHeaderDescription=Selecteer types verbindingen die je automatisch wilt toevoegen voor het systeem. +noInformationAvailable=Geen informatie beschikbaar +localMachine=Lokale machine +yes=Ja +no=Geen +errorOccured=Er is een fout opgetreden +terminalErrorOccured=Er is een terminalfout opgetreden +errorTypeOccured=Er is een uitzondering van het type $TYPE$ gegooid +permissionsAlertTitle=Vereiste machtigingen +permissionsAlertHeader=Er zijn extra rechten nodig om deze bewerking uit te voeren. +permissionsAlertContent=Volg de pop-up om XPipe de vereiste rechten te geven in het instellingenmenu. +errorDetails=Details tonen +updateReadyAlertTitle=Gereed voor bijwerken +updateReadyAlertHeader=Een update naar versie $VERSION$ is klaar om geïnstalleerd te worden +updateReadyAlertContent=Hiermee wordt de nieuwe versie geïnstalleerd en wordt XPipe opnieuw opgestart zodra de installatie is voltooid. +errorNoDetail=Er zijn geen foutgegevens beschikbaar +updateAvailableTitle=Update beschikbaar +updateAvailableHeader=Er is een XPipe-update naar versie $VERSION$ beschikbaar om te installeren +updateAvailableContent=Hoewel XPipe niet kon worden gestart, kun je proberen de update te installeren om het probleem mogelijk op te lossen. +clipboardActionDetectedTitle=Klembord actie gedetecteerd +clipboardActionDetectedHeader=Wil je de inhoud van je klembord importeren? +clipboardActionDetectedContent=XPipe heeft inhoud op je klembord gedetecteerd die geopend kan worden. Wil je het nu openen? +install=Installeren ... +ignore=Negeren +possibleActions=Mogelijke acties +reportError=Fout rapporteren +reportOnGithub=Een probleemrapport maken op GitHub +reportOnGithubDescription=Open een nieuw probleem in de GitHub repository +reportErrorDescription=Een foutenrapport verzenden met optionele feedback van de gebruiker en diagnose-info +ignoreError=Fout negeren +ignoreErrorDescription=Negeer deze foutmelding en ga verder alsof er niets is gebeurd +provideEmail=Hoe kunnen we contact met je opnemen (optioneel, alleen als je op de hoogte wilt worden gesteld van fixes)? +additionalErrorInfo=Aanvullende informatie geven (optioneel) +additionalErrorAttachments=Selecteer bijlagen (optioneel) +dataHandlingPolicies=Privacybeleid +sendReport=Rapport verzenden +errorHandler=Foutbehandelaar +events=Gebeurtenissen +method=Methode +validate=Valideren +stackTrace=Stacktrack +previousStep=< Vorig +nextStep=Volgende > +finishStep=Afmaken +edit=Bewerken +browseInternal=Intern bladeren +checkOutUpdate=Uitchecken update +open=Open +quit=Afsluiten +noTerminalSet=Er is geen computertoepassing automatisch ingesteld. Je kunt dit handmatig doen in het instellingenmenu. +connections=Verbindingen +settings=Instellingen +explorePlans=Licentie +help=Help +about=Over +developer=Ontwikkelaar +browseFileTitle=Bestand doorbladeren +browse=Bladeren door +browser=Browser +selectFileFromComputer=Selecteer een bestand van deze computer +links=Nuttige koppelingen +website=Website +documentation=Documentatie +discordDescription=Word lid van de Discord server +security=Beveiliging +securityPolicy=Beveiligingsinformatie +securityPolicyDescription=Het gedetailleerde beveiligingsbeleid lezen +privacy=Privacybeleid +privacyDescription=Lees het privacybeleid voor de XPipe-toepassing +slackDescription=Word lid van de Slack-werkruimte +support=Ondersteuning +githubDescription=Bekijk de GitHub opslagplaats +openSourceNotices=Open Bron Mededelingen +xPipeClient=XPipe Desktop +checkForUpdates=Controleren op updates +checkForUpdatesDescription=Download een update als die er is +lastChecked=Laatst gecontroleerd +version=Versie +build=Versie bouwen +runtimeVersion=Runtime versie +virtualMachine=Virtuele machine +updateReady=Update installeren +updateReadyPortable=Uitchecken update +updateReadyDescription=Een update is gedownload en kan worden geïnstalleerd +updateReadyDescriptionPortable=Een update is beschikbaar om te downloaden +updateRestart=Opnieuw opstarten om bij te werken +never=Nooit +updateAvailableTooltip=Beschikbare update +visitGithubRepository=Bezoek GitHub archief +updateAvailable=Update beschikbaar: $VERSION$ +downloadUpdate=Update downloaden +legalAccept=Ik accepteer de licentieovereenkomst voor eindgebruikers +confirm=Bevestigen +print=Afdrukken +whatsNew=Wat is er nieuw in versie $VERSION$ ($DATE$) +antivirusNoticeTitle=Een opmerking over antivirusprogramma's +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Welkom bij XPipe +gotIt=Gekregen +eula=Licentieovereenkomst voor eindgebruikers +news=Nieuws +introduction=Inleiding +privacyPolicy=Privacybeleid +agree=Akkoord +disagree=Oneens +directories=Directories +logFile=Logbestand +logFiles=Logbestanden +logFilesAttachment=Logbestanden +issueReporter=Probleemrapporteur +openCurrentLogFile=Logbestanden +openCurrentLogFileDescription=Open het logbestand van de huidige sessie +openLogsDirectory=Open logs directory +installationFiles=Installatiebestanden +openInstallationDirectory=Installatiebestanden +openInstallationDirectoryDescription=Open XPipe installatiemap +launchDebugMode=Debugmodus +launchDebugModeDescription=XPipe herstarten in debugmodus +extensionInstallTitle=Downloaden +extensionInstallDescription=Deze actie vereist aanvullende bibliotheken van derden die niet door XPipe worden gedistribueerd. Je kunt ze hier automatisch installeren. De componenten worden dan gedownload van de website van de leverancier: +extensionInstallLicenseNote=Door de download en automatische installatie uit te voeren ga je akkoord met de voorwaarden van de licenties van derden: +license=Licentie +installRequired=Installatie vereist +restore=Herstellen +restoreAllSessions=Alle sessies herstellen +connectionTimeout=Time-out start verbinding +connectionTimeoutDescription=De tijd in seconden om te wachten op een antwoord voordat een verbinding als getimed wordt beschouwd. Als sommige van je systemen op afstand er lang over doen om verbinding te maken, kun je proberen deze waarde te verhogen. +useBundledTools=Gebundelde OpenSSH-gereedschappen gebruiken +useBundledToolsDescription=Gebruik liever de gebundelde versie van de openssh client in plaats van je lokaal geïnstalleerde versie.\n\nDeze versie is meestal actueler dan degene die op je systeem staat en ondersteunt mogelijk extra mogelijkheden. Hierdoor is het ook niet meer nodig om deze tools überhaupt geïnstalleerd te hebben.\n\nVereist opnieuw opstarten om toe te passen. +appearance=Uiterlijk +integrations=Integraties +uiOptions=UI-opties +theme=Thema +rdp=Bureaublad op afstand +rdpConfiguration=Configuratie van bureaublad op afstand +rdpClient=RDP-client +rdpClientDescription=Het RDP-clientprogramma dat wordt aangeroepen bij het starten van RDP-verbindingen.\n\nMerk op dat verschillende clients verschillende niveaus van mogelijkheden en integraties hebben. Sommige clients ondersteunen het automatisch doorgeven van wachtwoorden niet, dus je moet ze nog steeds invullen bij het starten. +localShell=Lokale shell +themeDescription=Het weergavethema van je voorkeur +dontAutomaticallyStartVmSshServer=SSH-server voor VM's niet automatisch starten wanneer nodig +dontAutomaticallyStartVmSshServerDescription=Elke shellverbinding met een VM die draait in een hypervisor wordt gemaakt via SSH. XPipe kan automatisch de geïnstalleerde SSH-server starten wanneer dat nodig is. Als je dit om veiligheidsredenen niet wilt, dan kun je dit gedrag gewoon uitschakelen met deze optie. +confirmGitShareTitle=Git delen bevestigen +confirmGitShareHeader=Dit kopieert het bestand naar je git vault en commit je wijzigingen. Wil je doorgaan? +gitShareFileTooltip=Voeg een bestand toe aan de git vault datamap zodat het automatisch gesynchroniseerd wordt.\n\nDeze actie kan alleen worden gebruikt als de git vault is ingeschakeld in de instellingen. +performanceMode=Prestatiemodus +performanceModeDescription=Schakelt alle visuele effecten uit die niet nodig zijn om de prestaties van de toepassing te verbeteren. +dontAcceptNewHostKeys=Nieuwe SSH-hostsleutels niet automatisch accepteren +dontAcceptNewHostKeysDescription=XPipe accepteert standaard automatisch hostsleutels van systemen waar je SSH-client nog geen bekende hostsleutel heeft opgeslagen. Als een bekende hostsleutel echter is gewijzigd, zal het weigeren om verbinding te maken tenzij je de nieuwe accepteert.\n\nDoor dit gedrag uit te schakelen kun je alle hostsleutels controleren, zelfs als er in eerste instantie geen conflict is. +uiScale=UI Schaal +uiScaleDescription=Een aangepaste schaalwaarde die onafhankelijk van de systeembrede schermschaal kan worden ingesteld. Waarden zijn in procenten, dus bijvoorbeeld een waarde van 150 resulteert in een UI-schaal van 150%.\n\nVereist een herstart om toe te passen. +editorProgram=Bewerkingsprogramma +editorProgramDescription=De standaard teksteditor om te gebruiken bij het bewerken van tekstgegevens. +windowOpacity=Venster ondoorzichtigheid +windowOpacityDescription=Verandert de ondoorzichtigheid van het venster om bij te houden wat er op de achtergrond gebeurt. +useSystemFont=Lettertype van het systeem gebruiken +openDataDir=Kluisgegevensmap +openDataDirButton=Open gegevensmap +openDataDirDescription=Als je aanvullende bestanden, zoals SSH sleutels, wilt synchroniseren tussen systemen met je git repository, dan kun je ze in de storage data directory zetten. Van alle bestanden waarnaar daar verwezen wordt, worden de bestandspaden automatisch aangepast op elk gesynchroniseerd systeem. +updates=Updates +passwordKey=Wachtwoord sleutel +selectAll=Alles selecteren +command=Opdracht +advanced=Geavanceerd +thirdParty=Open bron berichten +eulaDescription=Lees de licentieovereenkomst voor de eindgebruiker voor de XPipe-toepassing +thirdPartyDescription=De open source licenties van bibliotheken van derden bekijken +workspaceLock=Hoofdwachtzin +enableGitStorage=Git synchronisatie inschakelen +sharing=Delen +sync=Synchronisatie +enableGitStorageDescription=Als dit is ingeschakeld zal XPipe een git repository initialiseren voor de opslag van de verbindingsgegevens en alle wijzigingen daarop vastleggen. Merk op dat hiervoor git geïnstalleerd moet zijn en dat dit het laden en opslaan kan vertragen.\n\nAlle categorieën die gesynchroniseerd moeten worden, moeten expliciet als gedeeld worden aangemerkt.\n\nVereist een herstart om toe te passen. +storageGitRemote=Git URL op afstand +storageGitRemoteDescription=Als dit is ingesteld, haalt XPipe automatisch wijzigingen op bij het laden en pusht wijzigingen naar het externe archief bij het opslaan.\n\nHierdoor kun je configuratiegegevens delen tussen meerdere XPipe installaties. Zowel HTTP als SSH URL's worden ondersteund. Merk op dat dit het laden en opslaan kan vertragen.\n\nVereist een herstart om toe te passen. +vault=Kluis +workspaceLockDescription=Stelt een aangepast wachtwoord in om gevoelige informatie die is opgeslagen in XPipe te versleutelen.\n\nDit resulteert in een verhoogde beveiliging omdat het een extra coderingslaag biedt voor je opgeslagen gevoelige informatie. Je wordt dan gevraagd om het wachtwoord in te voeren wanneer XPipe start. +useSystemFontDescription=Bepaalt of je het systeemlettertype gebruikt of het Roboto-lettertype dat met XPipe wordt meegeleverd. +tooltipDelay=Tooltip vertraging +tooltipDelayDescription=Het aantal milliseconden dat moet worden gewacht tot een tooltip wordt weergegeven. +fontSize=Lettergrootte +windowOptions=Venster Opties +saveWindowLocation=Vensterlocatie opslaan +saveWindowLocationDescription=Regelt of de coördinaten van het venster moeten worden opgeslagen en hersteld bij opnieuw opstarten. +startupShutdown=Opstarten / Afsluiten +showChildCategoriesInParentCategory=Toon kindcategorieën in bovenliggende categorie +showChildCategoriesInParentCategoryDescription=Het al dan niet opnemen van alle verbindingen in subcategorieën wanneer een bepaalde bovenliggende categorie is geselecteerd.\n\nAls dit is uitgeschakeld, gedragen de categorieën zich meer als klassieke mappen die alleen hun directe inhoud tonen zonder submappen op te nemen. +condenseConnectionDisplay=Verbindingsweergave samenvatten +condenseConnectionDisplayDescription=Laat elke verbinding op het hoogste niveau minder verticale ruimte innemen om een meer beknopte verbindingslijst mogelijk te maken. +enforceWindowModality=Venstermodaliteit afdwingen +enforceWindowModalityDescription=Zorgt ervoor dat secundaire vensters, zoals het dialoogvenster voor het maken van een verbinding, alle invoer voor het hoofdvenster blokkeren terwijl ze geopend zijn. Dit is handig als je soms verkeerd klikt. +openConnectionSearchWindowOnConnectionCreation=Verbindingszoekvenster openen bij het maken van een verbinding +openConnectionSearchWindowOnConnectionCreationDescription=Het al dan niet automatisch openen van het venster om te zoeken naar beschikbare subverbindingen bij het toevoegen van een nieuwe shellverbinding. +workflow=Werkstroom +system=Systeem +application=Toepassing +storage=Opslag +runOnStartup=Uitvoeren bij opstarten +closeBehaviour=Gedrag sluiten +closeBehaviourDescription=Regelt hoe XPipe verder moet gaan na het sluiten van het hoofdvenster. +language=Taal +languageDescription=De te gebruiken weergavetaal.\n\nMerk op dat deze automatische vertalingen als basis gebruiken en handmatig worden gerepareerd en verbeterd door bijdragers. Je kunt ook helpen met vertalen door vertaalcorrecties in te sturen op GitHub. +lightTheme=Licht thema +darkTheme=Donker thema +exit=XPipe afsluiten +continueInBackground=Doorgaan op de achtergrond +minimizeToTray=Minimaliseren naar lade +closeBehaviourAlertTitle=Sluitgedrag instellen +closeBehaviourAlertTitleHeader=Selecteer wat er moet gebeuren bij het sluiten van het venster. Alle actieve verbindingen worden gesloten wanneer de toepassing wordt afgesloten. +startupBehaviour=Opstartgedrag +startupBehaviourDescription=Regelt het standaardgedrag van de bureaubladtoepassing wanneer XPipe wordt gestart. +clearCachesAlertTitle=Cache opschonen +clearCachesAlertTitleHeader=Wil je alle XPipe caches opschonen? +clearCachesAlertTitleContent=Merk op dat hierdoor alle gegevens worden verwijderd die zijn opgeslagen om de gebruikerservaring te verbeteren. +startGui=GUI starten +startInTray=Starten in de lade +startInBackground=Op achtergrond starten +clearCaches=Caches wissen ... +clearCachesDescription=Alle cachegegevens verwijderen +apply=Toepassen +cancel=Annuleren +notAnAbsolutePath=Geen absoluut pad +notADirectory=Geen directory +notAnEmptyDirectory=Geen lege map +automaticallyUpdate=Controleren op updates +automaticallyUpdateDescription=Als deze optie is ingeschakeld, wordt nieuwe release-informatie automatisch opgehaald terwijl XPipe actief is. Er wordt geen updateprogramma op de achtergrond uitgevoerd en je moet de installatie van een update nog steeds expliciet bevestigen. +sendAnonymousErrorReports=Anoniem foutrapporten versturen +sendUsageStatistics=Anonieme gebruiksstatistieken verzenden +storageDirectory=Opslagmap +storageDirectoryDescription=De locatie waar XPipe alle verbindingsinformatie moet opslaan. Deze instelling wordt pas toegepast bij de volgende herstart. Als je dit verandert, worden de gegevens in de oude map niet gekopieerd naar de nieuwe. +logLevel=Logniveau +appBehaviour=Gedrag van de toepassing +logLevelDescription=Het logniveau dat gebruikt moet worden bij het schrijven van logbestanden. +developerMode=Ontwikkelaar modus +developerModeDescription=Als deze optie is ingeschakeld, heb je toegang tot een aantal extra opties die handig zijn voor ontwikkeling. Alleen actief na opnieuw opstarten. +editor=Bewerker +custom=Aangepaste +passwordManagerCommand=Opdracht voor wachtwoordbeheer +passwordManagerCommandDescription=Het commando dat moet worden uitgevoerd om wachtwoorden op te halen. De tekenreeks $KEY wordt bij het aanroepen vervangen door de geciteerde wachtwoordsleutel. Dit moet je wachtwoordmanager CLI aanroepen om het wachtwoord naar stdout af te drukken, bijvoorbeeld mypassmgr get $KEY.\n\nJe kunt dan instellen dat de sleutel wordt opgehaald wanneer je een verbinding opzet waarvoor een wachtwoord nodig is. +passwordManagerCommandTest=Wachtwoordmanager testen +passwordManagerCommandTestDescription=Je kunt hier testen of de uitvoer er correct uitziet als je een wachtwoordmanager-commando hebt ingesteld. Het commando moet alleen het wachtwoord zelf uitvoeren naar stdout, er mag geen andere opmaak in de uitvoer worden opgenomen. +preferEditorTabs=Open liever nieuwe tabbladen +preferEditorTabsDescription=Bepaalt of XPipe zal proberen nieuwe tabbladen te openen in de door jou gekozen editor in plaats van nieuwe vensters.\n\nMerk op dat niet elke editor dit ondersteunt. +customRdpClientCommand=Aangepaste opdracht +customRdpClientCommandDescription=Het commando dat moet worden uitgevoerd om de aangepaste RDP-client te starten.\n\nDe tekenreeks $FILE wordt vervangen door de absolute .rdp bestandsnaam wanneer deze wordt aangeroepen. Vergeet niet het uitvoerbare pad aan te halen als het spaties bevat. +customEditorCommand=Aangepaste editor opdracht +customEditorCommandDescription=Het commando dat moet worden uitgevoerd om de aangepaste editor te starten.\n\nDe tekenreeks $FILE wordt vervangen door de absolute bestandsnaam als deze wordt aangeroepen. Vergeet niet om het uitvoerbare pad van je editor te citeren als het spaties bevat. +editorReloadTimeout=Editor herlaad timeout +editorReloadTimeoutDescription=Het aantal milliseconden dat moet worden gewacht voordat een bestand wordt gelezen nadat het is bijgewerkt. Dit voorkomt problemen in gevallen waarin je editor traag is met het schrijven of vrijgeven van bestandsloten. +encryptAllVaultData=Alle kluisgegevens versleutelen +encryptAllVaultDataDescription=Als deze optie is ingeschakeld, wordt elk deel van de verbindingsgegevens van de vault versleuteld in plaats van alleen de geheimen binnen die gegevens. Dit voegt een extra beveiligingslaag toe voor andere parameters zoals gebruikersnamen, hostnamen, etc., die standaard niet versleuteld zijn in de vault.\n\nDeze optie maakt je git vault geschiedenis en diffs nutteloos, omdat je de originele wijzigingen niet meer kunt zien, alleen de binaire wijzigingen. +vaultSecurity=Kluisbeveiliging +developerDisableUpdateVersionCheck=Updateversiecontrole uitschakelen +developerDisableUpdateVersionCheckDescription=Bepaalt of de updatechecker het versienummer negeert bij het zoeken naar een update. +developerDisableGuiRestrictions=GUI-beperkingen uitschakelen +developerDisableGuiRestrictionsDescription=Regelt of sommige uitgeschakelde acties nog steeds kunnen worden uitgevoerd vanuit de gebruikersinterface. +developerShowHiddenEntries=Verborgen items tonen +developerShowHiddenEntriesDescription=Als deze optie is ingeschakeld, worden verborgen en interne gegevensbronnen getoond. +developerShowHiddenProviders=Verborgen aanbieders tonen +developerShowHiddenProvidersDescription=Bepaalt of verborgen en interne verbindings- en gegevensbronproviders worden getoond in het aanmaakvenster. +developerDisableConnectorInstallationVersionCheck=Connector versiecontrole uitschakelen +developerDisableConnectorInstallationVersionCheckDescription=Bepaalt of de updatechecker het versienummer negeert bij het inspecteren van de versie van een XPipe-connector die op een externe machine is geïnstalleerd. +shellCommandTest=Shell commando test +shellCommandTestDescription=Een commando uitvoeren in de shellsessie die intern door XPipe wordt gebruikt. +terminal=Terminal +terminalEmulator=Terminal emulator +terminalConfiguration=Terminal configuratie +editorConfiguration=Configuratie van een editor +defaultApplication=Standaard toepassing +terminalEmulatorDescription=De standaard terminal die wordt gebruikt bij het openen van een shellverbinding. Deze toepassing wordt alleen gebruikt voor weergave, het opgestarte shell-programma hangt af van de shell-verbinding zelf.\n\nDe mate van ondersteuning verschilt per terminal, daarom is elke terminal gemarkeerd als aanbevolen of niet aanbevolen. Alle niet-aanbevolen terminals werken met XPipe, maar missen mogelijk functies als tabbladen, titelkleuren, shell-ondersteuning en meer. Je gebruikerservaring is het beste als je een aanbevolen terminal gebruikt. +program=Programma +customTerminalCommand=Aangepast terminalcommando +customTerminalCommandDescription=Het commando dat moet worden uitgevoerd om de aangepaste terminal te openen met een gegeven commando.\n\nXPipe maakt een tijdelijk launcher-shell script aan om je terminal uit te voeren. De placeholder string $CMD in het commando dat je opgeeft zal worden vervangen door het eigenlijke launcher script wanneer het wordt aangeroepen. Vergeet niet het uitvoerbare pad van je terminal te citeren als het spaties bevat. +clearTerminalOnInit=Terminal wissen bij init +clearTerminalOnInitDescription=Indien ingeschakeld zal XPipe een clear commando uitvoeren wanneer een nieuwe terminal sessie wordt gestart om onnodige uitvoer te verwijderen. +enableFastTerminalStartup=Snel opstarten van terminal inschakelen +enableFastTerminalStartupDescription=Als deze optie is ingeschakeld, wordt geprobeerd terminalsessies zo mogelijk sneller te starten.\n\nHierdoor worden verschillende opstartcontroles overgeslagen en wordt weergegeven systeeminformatie niet bijgewerkt. Eventuele verbindingsfouten worden alleen in de terminal getoond. +dontCachePasswords=Gevraagde wachtwoorden niet in de cache opslaan +dontCachePasswordsDescription=Bepaalt of opgevraagde wachtwoorden intern door XPipe in de cache moeten worden opgeslagen, zodat je ze niet opnieuw hoeft in te voeren in de huidige sessie.\n\nAls dit gedrag is uitgeschakeld, moet je alle opgevraagde wachtwoorden opnieuw invoeren elke keer dat het systeem ze nodig heeft. +denyTempScriptCreation=Het maken van een tijdelijk script weigeren +denyTempScriptCreationDescription=Om sommige functionaliteiten te realiseren, maakt XPipe soms tijdelijke shell scripts aan op een doelsysteem om eenvoudige commando's eenvoudig uit te kunnen voeren. Deze bevatten geen gevoelige informatie en worden alleen gemaakt voor implementatiedoeleinden.\n\nAls dit gedrag is uitgeschakeld, maakt XPipe geen tijdelijke bestanden aan op een systeem op afstand. Deze optie is handig in omgevingen met een hoge beveiligingsgraad waar elke wijziging aan het bestandssysteem wordt gecontroleerd. Als dit is uitgeschakeld, zullen sommige functionaliteiten, zoals shell omgevingen en scripts, niet werken zoals bedoeld. +disableCertutilUse=Het gebruik van certutil onder Windows uitschakelen +useLocalFallbackShell=Lokale fallback-shell gebruiken +useLocalFallbackShellDescription=Schakel over op het gebruik van een andere lokale shell om lokale bewerkingen uit te voeren. Dit is PowerShell op Windows en bourne shell op andere systemen.\n\nDeze optie kan worden gebruikt als de normale lokale standaard shell is uitgeschakeld of tot op zekere hoogte kapot is. Sommige functies kunnen echter niet werken zoals verwacht wanneer deze optie is ingeschakeld.\n\nVereist een herstart om toe te passen. +disableCertutilUseDescription=Vanwege verschillende tekortkomingen en bugs in cmd.exe worden tijdelijke shellscripts gemaakt met certutil door het te gebruiken om base64 invoer te decoderen, omdat cmd.exe breekt op niet-ASCII invoer. XPipe kan hiervoor ook PowerShell gebruiken, maar dit is langzamer.\n\nDit schakelt elk gebruik van certutil op Windows systemen uit om bepaalde functionaliteit te realiseren en in plaats daarvan terug te vallen op PowerShell. Dit zou sommige AV's kunnen plezieren, omdat sommige AV's het gebruik van certutil blokkeren. +disableTerminalRemotePasswordPreparation=Voorbereiding voor wachtwoord op afstand van terminal uitschakelen +disableTerminalRemotePasswordPreparationDescription=In situaties waar een remote shell verbinding die via meerdere intermediaire systemen loopt in de terminal tot stand moet worden gebracht, kan het nodig zijn om alle vereiste wachtwoorden op een van de intermediaire systemen voor te bereiden, zodat eventuele prompts automatisch kunnen worden ingevuld.\n\nAls je niet wilt dat de wachtwoorden ooit worden verzonden naar een tussenliggend systeem, dan kun je dit gedrag uitschakelen. Elk vereist tussenliggend wachtwoord zal dan worden opgevraagd in de terminal zelf wanneer deze wordt geopend. +more=Meer +translate=Vertalingen +allConnections=Alle verbindingen +allScripts=Alle scripts +predefined=Voorgedefinieerd +default=Standaard +goodMorning=Goedemorgen +goodAfternoon=Goedemiddag +goodEvening=Goedenavond +addVisual=Visuele ... +ssh=SSH +sshConfiguration=SSH-configuratie +size=Grootte +attributes=Attributen +modified=Gewijzigd +isOnlySupported=wordt alleen ondersteund met een professionele licentie +areOnlySupported=worden alleen ondersteund met een professionele licentie +updateReadyTitle=Bijwerken naar $VERSION$ klaar diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties new file mode 100644 index 000000000..3a3d9fffc --- /dev/null +++ b/lang/app/strings/translations_pt.properties @@ -0,0 +1,426 @@ +delete=Elimina +rename=Renomeia +properties=Propriedades +usedDate=Usado $DATE$ +openDir=Abrir diretório +sortLastUsed=Ordena por data da última utilização +sortAlphabetical=Ordena alfabeticamente por nome +restart=Reinicia o XPipe +restartDescription=Um reinício pode muitas vezes ser uma solução rápida +reportIssue=Relata um problema +reportIssueDescription=Abre o relatório de problemas integrado +usefulActions=Acções úteis +stored=Guardado +troubleshootingOptions=Ferramentas de resolução de problemas +troubleshoot=Resolve problemas +remote=Ficheiro remoto +addShellStore=Adiciona o Shell ... +addShellTitle=Adiciona uma ligação Shell +savedConnections=Ligações guardadas +save=Guarda +clean=Limpar +refresh=Actualiza +moveTo=Move-te para ... +addDatabase=Base de dados ... +browseInternalStorage=Navega no armazenamento interno +addTunnel=Túnel ... +addScript=Script ... +addHost=Anfitrião remoto ... +addShell=Ambiente Shell ... +addCommand=Comando personalizado ... +addAutomatically=Pesquisa automaticamente ... +addOther=Adiciona outro ... +addConnection=Adicionar ligação +skip=Salta +addConnections=Novo +selectType=Selecciona o tipo +selectTypeDescription=Selecciona o tipo de ligação +selectShellType=Tipo de Shell +selectShellTypeDescription=Selecciona o tipo de ligação Shell +name=Nome +storeIntroTitle=Hub de ligação +storeIntroDescription=Aqui podes gerir todas as tuas ligações shell locais e remotas num único local. Para começar, podes detetar rapidamente as ligações disponíveis automaticamente e escolher as que queres adicionar. +detectConnections=Procura ligações +configuration=Configuração +dragAndDropFilesHere=Ou simplesmente arrasta e larga um ficheiro aqui +confirmDsCreationAbortTitle=Confirmação de abortar +confirmDsCreationAbortHeader=Queres anular a criação da fonte de dados? +confirmDsCreationAbortContent=Perde todo o progresso da criação da fonte de dados. +confirmInvalidStoreTitle=Falha na ligação +confirmInvalidStoreHeader=Queres saltar a validação da ligação? +confirmInvalidStoreContent=Podes adicionar esta ligação mesmo que não possa ser validada e corrigir os problemas de ligação mais tarde. +none=Não tens +expand=Expande +accessSubConnections=Acede às subconexões +common=Comum +color=Cor +alwaysConfirmElevation=Confirma sempre a elevação da permissão +alwaysConfirmElevationDescription=Controla a forma de lidar com casos em que são necessárias permissões elevadas para executar um comando num sistema, por exemplo, com sudo.\n\nPor predefinição, quaisquer credenciais sudo são armazenadas em cache durante uma sessão e fornecidas automaticamente quando necessário. Se esta opção estiver activada, pede-te para confirmares sempre o acesso de elevação. +allow=Permite +ask=Pergunta +deny=Recusar +share=Adiciona ao repositório git +unshare=Remove do repositório git +remove=Remove +newCategory=Nova subcategoria +passwordManager=Gestor de palavras-passe +prompt=Prompt +customCommand=Comando personalizado +other=Outro +setLock=Definir bloqueio +selectConnection=Selecionar ligação +changeLock=Altera a frase-chave +test=Testa +lockCreationAlertTitle=Define a frase-chave +lockCreationAlertHeader=Define a tua nova frase-chave principal +finish=Termina +error=Ocorreu um erro +downloadStageDescription=Descarrega ficheiros para a sua máquina local, para que possa arrastá-los e largá-los no seu ambiente de trabalho nativo. +ok=Ok +search=Procura +newFile=Novo ficheiro +newDirectory=Novo diretório +passphrase=Frase-chave +repeatPassphrase=Repete a frase-chave +password=Palavra-passe +unlockAlertTitle=Desbloqueia o espaço de trabalho +unlockAlertHeader=Introduz a tua frase-chave do cofre para continuar +enterLockPassword=Introduzir a palavra-passe do cadeado +repeatPassword=Repete a palavra-passe +askpassAlertTitle=Askpass +unsupportedOperation=Operação não suportada: $MSG$ +fileConflictAlertTitle=Resolve o conflito +fileConflictAlertHeader=Encontraste um conflito. Como queres proceder? +fileConflictAlertContent=O ficheiro $FILE$ já existe no sistema de destino. +fileConflictAlertContentMultiple=O ficheiro $FILE$ já existe. Poderão existir mais conflitos que podes resolver automaticamente escolhendo uma opção que se aplique a todos. +moveAlertTitle=Confirmação de movimento +moveAlertHeader=Queres mover os elementos seleccionados ($COUNT$) para $TARGET$? +deleteAlertTitle=Confirma a eliminação +deleteAlertHeader=Queres apagar os ($COUNT$) elementos seleccionados? +selectedElements=Elementos seleccionados: +mustNotBeEmpty=$VALUE$ não pode estar vazio +valueMustNotBeEmpty=O valor não pode estar vazio +transferDescription=Larga ficheiros para transferir +dragFiles=Arrasta ficheiros no browser +dragLocalFiles=Arrasta ficheiros locais a partir daqui +null=$VALUE$ não pode ser nulo +roots=Raízes +scripts=Scripts +searchFilter=Pesquisa ... +recent=Recente +shortcut=Atalho +browserWelcomeEmpty=Aqui poderás ver onde paraste da última vez. +browserWelcomeSystems=Estiveste recentemente ligado aos seguintes sistemas: +hostFeatureUnsupported=$FEATURE$ não está instalado no anfitrião +missingStore=$NAME$ não existe +connectionName=Nome da ligação +connectionNameDescription=Dá um nome personalizado a esta ligação +openFileTitle=Abre um ficheiro +unknown=Desconhecido +scanAlertTitle=Adiciona ligações +scanAlertChoiceHeader=Destino +scanAlertChoiceHeaderDescription=Escolhe onde procurar as ligações. Procura primeiro todas as ligações disponíveis. +scanAlertHeader=Tipos de ligação +scanAlertHeaderDescription=Selecciona os tipos de ligações que pretendes adicionar automaticamente ao sistema. +noInformationAvailable=Não há informações disponíveis +localMachine=Máquina local +yes=Sim +no=Não +errorOccured=Ocorreu um erro +terminalErrorOccured=Ocorreu um erro no terminal +errorTypeOccured=Foi lançada uma exceção do tipo $TYPE$ +permissionsAlertTitle=Permissões necessárias +permissionsAlertHeader=São necessárias permissões adicionais para efetuar esta operação. +permissionsAlertContent=Segue a janela pop-up para dar ao XPipe as permissões necessárias no menu de definições. +errorDetails=Mostra os detalhes +updateReadyAlertTitle=Atualizar pronto +updateReadyAlertHeader=Uma atualização para a versão $VERSION$ está pronta para ser instalada +updateReadyAlertContent=Instala a nova versão e reinicia o XPipe quando a instalação estiver concluída. +errorNoDetail=Não há detalhes de erro disponíveis +updateAvailableTitle=Atualização disponível +updateAvailableHeader=Está disponível para instalação uma atualização do XPipe para a versão $VERSION$ +updateAvailableContent=Apesar de não ter sido possível iniciar o XPipe, podes tentar instalar a atualização para potencialmente corrigir o problema. +clipboardActionDetectedTitle=Ação da área de transferência detectada +clipboardActionDetectedHeader=Queres importar o conteúdo da tua área de transferência? +clipboardActionDetectedContent=XPipe detectou conteúdo na tua área de transferência que pode ser aberto. Queres abri-lo agora? +install=Instala ... +ignore=Ignora +possibleActions=Acções possíveis +reportError=Relata um erro +reportOnGithub=Criar um relatório de problemas no GitHub +reportOnGithubDescription=Abre um novo problema no repositório do GitHub +reportErrorDescription=Envia um relatório de erro com feedback opcional do utilizador e informações de diagnóstico +ignoreError=Ignora o erro +ignoreErrorDescription=Ignora este erro e continua como se nada tivesse acontecido +provideEmail=Como te contactar (opcional, apenas se quiseres ser notificado sobre correcções) +additionalErrorInfo=Fornece informações adicionais (opcional) +additionalErrorAttachments=Selecionar anexos (opcional) +dataHandlingPolicies=Política de privacidade +sendReport=Envia um relatório +errorHandler=Gestor de erros +events=Eventos +method=Método +validate=Valida +stackTrace=Rastreio de pilha +previousStep=< Anterior +nextStep=Seguinte > +finishStep=Terminar +edit=Edita +browseInternal=Navega internamente +checkOutUpdate=Verifica a atualização +open=Abre-te +quit=Desiste +noTerminalSet=Não definiste automaticamente nenhuma aplicação de terminal. Podes fazê-lo manualmente no menu de definições. +connections=Ligações +settings=Definições +explorePlans=Licença +help=Ajuda-te +about=Acerca de +developer=Programador +browseFileTitle=Procurar ficheiro +browse=Procura +browser=Navegador +selectFileFromComputer=Selecciona um ficheiro deste computador +links=Ligações úteis +website=Sítio Web +documentation=Documentação +discordDescription=Junta-te ao servidor Discord +security=Segurança +securityPolicy=Informações de segurança +securityPolicyDescription=Lê a política de segurança detalhada +privacy=Política de privacidade +privacyDescription=Lê a política de privacidade da aplicação XPipe +slackDescription=Junta-te ao espaço de trabalho do Slack +support=Apoia +githubDescription=Consulta o repositório do GitHub +openSourceNotices=Avisos de código aberto +xPipeClient=XPipe Desktop +checkForUpdates=Verifica se há actualizações +checkForUpdatesDescription=Descarrega uma atualização, se houver uma +lastChecked=Verificado pela última vez +version=Versão +build=Constrói uma versão +runtimeVersion=Versão em tempo de execução +virtualMachine=Máquina virtual +updateReady=Instalar a atualização +updateReadyPortable=Verifica a atualização +updateReadyDescription=Uma atualização foi descarregada e está pronta para ser instalada +updateReadyDescriptionPortable=Uma atualização está disponível para transferência +updateRestart=Reinicia para atualizar +never=Nunca mais +updateAvailableTooltip=Atualização disponível +visitGithubRepository=Visita o repositório GitHub +updateAvailable=Atualização disponível: $VERSION$ +downloadUpdate=Descarregar atualização +legalAccept=Aceito o Contrato de Licença de Utilizador Final +confirm=Confirmar +print=Imprimir +whatsNew=O que há de novo na versão $VERSION$ ($DATE$) +antivirusNoticeTitle=Uma nota sobre programas antivírus +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Bem-vindo ao XPipe +gotIt=Percebeste +eula=Contrato de licença de utilizador final +news=Novidades +introduction=Introdução +privacyPolicy=Política de privacidade +agree=Concorda +disagree=Não concordas +directories=Directórios +logFile=Ficheiro de registo +logFiles=Ficheiros de registo +logFilesAttachment=Ficheiros de registo +issueReporter=Relator de problemas +openCurrentLogFile=Ficheiros de registo +openCurrentLogFileDescription=Abre o ficheiro de registo da sessão atual +openLogsDirectory=Abre o diretório de registos +installationFiles=Ficheiros de instalação +openInstallationDirectory=Ficheiros de instalação +openInstallationDirectoryDescription=Abre o diretório de instalação do XPipe +launchDebugMode=Modo de depuração +launchDebugModeDescription=Reinicia o XPipe no modo de depuração +extensionInstallTitle=Descarrega +extensionInstallDescription=Esta ação requer bibliotecas adicionais de terceiros que não são distribuídas pelo XPipe. Podes instalá-las automaticamente aqui. Os componentes são descarregados do sítio Web do fornecedor: +extensionInstallLicenseNote=Ao efetuar a transferência e a instalação automática, concordas com os termos das licenças de terceiros: +license=Licença +installRequired=Instalação necessária +restore=Restaurar +restoreAllSessions=Repõe todas as sessões +connectionTimeout=Tempo limite de início da ligação +connectionTimeoutDescription=O tempo, em segundos, de espera por uma resposta antes de considerares que a ligação expirou. Se alguns dos teus sistemas remotos demorarem muito tempo a estabelecer ligação, podes tentar aumentar este valor. +useBundledTools=Usa as ferramentas OpenSSH incluídas no pacote +useBundledToolsDescription=Prefere usar a versão empacotada do cliente openssh em vez da versão instalada localmente.\n\nEsta versão é normalmente mais actualizada do que as fornecidas com o teu sistema e pode suportar funcionalidades adicionais. Isso também elimina a necessidade de ter essas ferramentas instaladas em primeiro lugar.\n\nRequer reiniciar para aplicar. +appearance=Aparece +integrations=Integrações +uiOptions=Opções da IU +theme=Tema +rdp=Ambiente de trabalho remoto +rdpConfiguration=Configuração do ambiente de trabalho remoto +rdpClient=Cliente RDP +rdpClientDescription=Chama o programa cliente RDP ao iniciar ligações RDP.\n\nNota que vários clientes têm diferentes graus de capacidades e integrações. Alguns clientes não suportam a passagem de palavras-passe automaticamente, pelo que tens de as preencher no lançamento. +localShell=Shell local +themeDescription=O teu tema de visualização preferido +dontAutomaticallyStartVmSshServer=Não inicia automaticamente o servidor SSH para VMs quando necessário +dontAutomaticallyStartVmSshServerDescription=Qualquer ligação shell a uma VM em execução num hipervisor é feita através de SSH. O XPipe pode iniciar automaticamente o servidor SSH instalado quando necessário. Se não quiseres isto por razões de segurança, então podes simplesmente desativar este comportamento com esta opção. +confirmGitShareTitle=Confirma a partilha do git +confirmGitShareHeader=Isto irá copiar o ficheiro para o teu cofre git e confirmar as tuas alterações. Queres continuar? +gitShareFileTooltip=Adiciona o ficheiro ao diretório de dados do git vault para que seja sincronizado automaticamente.\n\nEsta ação só pode ser utilizada quando o git vault está ativado nas definições. +performanceMode=Modo de desempenho +performanceModeDescription=Desactiva todos os efeitos visuais que não são necessários para melhorar o desempenho da aplicação. +dontAcceptNewHostKeys=Não aceita automaticamente novas chaves de anfitrião SSH +dontAcceptNewHostKeysDescription=O XPipe aceitará automaticamente chaves de anfitrião por defeito de sistemas onde o teu cliente SSH não tem nenhuma chave de anfitrião conhecida já guardada. No entanto, se alguma chave de anfitrião conhecida tiver sido alterada, recusará a ligação a menos que aceites a nova chave.\n\nDesativar este comportamento permite-te verificar todas as chaves de anfitrião, mesmo que não haja conflito inicialmente. +uiScale=Escala UI +uiScaleDescription=Um valor de escala personalizado que pode ser definido independentemente da escala de exibição de todo o sistema. Os valores estão em percentagem, por isso, por exemplo, o valor de 150 resultará numa escala da IU de 150%.\n\nRequer uma reinicialização para ser aplicado. +editorProgram=Programa editor +editorProgramDescription=O editor de texto predefinido a utilizar quando edita qualquer tipo de dados de texto. +windowOpacity=Opacidade de uma janela +windowOpacityDescription=Altera a opacidade da janela para acompanhar o que está a acontecer em segundo plano. +useSystemFont=Utiliza o tipo de letra do sistema +openDataDir=Diretório de dados da abóbada +openDataDirButton=Abre o diretório de dados +openDataDirDescription=Se quiseres sincronizar ficheiros adicionais, como chaves SSH, entre sistemas com o teu repositório git, podes colocá-los no diretório de dados de armazenamento. Quaisquer ficheiros aí referenciados terão os seus caminhos de ficheiro automaticamente adaptados em qualquer sistema sincronizado. +updates=Actualiza +passwordKey=Chave de palavra-passe +selectAll=Selecciona tudo +command=Comanda +advanced=Avançado +thirdParty=Avisos de fonte aberta +eulaDescription=Lê o Contrato de Licença de Utilizador Final da aplicação XPipe +thirdPartyDescription=Vê as licenças de fonte aberta de bibliotecas de terceiros +workspaceLock=Palavra-passe principal +enableGitStorage=Ativar a sincronização do git +sharing=Partilha +sync=Sincronização +enableGitStorageDescription=Quando ativado, o XPipe inicializa um repositório git para o armazenamento de dados de conexão e confirma quaisquer alterações nele. Tem em atenção que isto requer que o git esteja instalado e pode tornar as operações de carregamento e gravação mais lentas.\n\nTodas as categorias que devem ser sincronizadas têm de ser explicitamente designadas como partilhadas.\n\nRequer uma reinicialização para ser aplicado. +storageGitRemote=URL remoto do Git +storageGitRemoteDescription=Quando definido, o XPipe extrai automaticamente quaisquer alterações ao carregar e empurra quaisquer alterações para o repositório remoto ao guardar.\n\nIsto permite-te partilhar os teus dados de configuração entre várias instalações XPipe. São suportados URLs HTTP e SSH. Tem em atenção que isto pode tornar as operações de carregamento e gravação mais lentas.\n\nRequer uma reinicialização para ser aplicado. +vault=Cofre +workspaceLockDescription=Define uma palavra-passe personalizada para encriptar qualquer informação sensível armazenada no XPipe.\n\nIsto resulta numa maior segurança, uma vez que fornece uma camada adicional de encriptação para as informações sensíveis armazenadas. Ser-te-á pedido que introduzas a palavra-passe quando o XPipe for iniciado. +useSystemFontDescription=Controla se deve ser utilizado o tipo de letra do sistema ou o tipo de letra Roboto que é fornecido com o XPipe. +tooltipDelay=Atraso na dica de ferramenta +tooltipDelayDescription=A quantidade de milissegundos a aguardar até que uma dica de ferramenta seja apresentada. +fontSize=Tamanho de letra +windowOptions=Opções de janela +saveWindowLocation=Guarda a localização da janela +saveWindowLocationDescription=Controla se as coordenadas da janela devem ser guardadas e restauradas ao reiniciar. +startupShutdown=Arranque / Encerramento +showChildCategoriesInParentCategory=Mostra as categorias secundárias na categoria principal +showChildCategoriesInParentCategoryDescription=Incluir ou não todas as ligações localizadas em subcategorias quando se selecciona uma determinada categoria principal.\n\nSe esta opção estiver desactivada, as categorias comportam-se mais como pastas clássicas que apenas mostram o seu conteúdo direto sem incluir as subpastas. +condenseConnectionDisplay=Condensa a visualização da ligação +condenseConnectionDisplayDescription=Faz com que cada ligação de nível superior ocupe menos espaço vertical para permitir uma lista de ligações mais condensada. +enforceWindowModality=Aplica a modalidade de janela +enforceWindowModalityDescription=Faz com que as janelas secundárias, como a caixa de diálogo de criação de ligação, bloqueiem todas as entradas para a janela principal enquanto estiverem abertas. Isto é útil se, por vezes, te enganares a clicar. +openConnectionSearchWindowOnConnectionCreation=Abre a janela de pesquisa de ligação na criação da ligação +openConnectionSearchWindowOnConnectionCreationDescription=Se abre ou não automaticamente a janela para procurar subligações disponíveis ao adicionar uma nova ligação shell. +workflow=Fluxo de trabalho +system=O sistema +application=Aplicação +storage=Armazenamento +runOnStartup=Executa no arranque +closeBehaviour=Fecha o comportamento +closeBehaviourDescription=Controla a forma como o XPipe deve proceder ao fechar a sua janela principal. +language=Língua +languageDescription=A linguagem de visualização a utilizar.\n\nNota que estas usam traduções automáticas como base e são corrigidas e melhoradas manualmente pelos colaboradores. Também podes ajudar o esforço de tradução submetendo correcções de tradução no GitHub. +lightTheme=Tema de luz +darkTheme=Tema escuro +exit=Sai do XPipe +continueInBackground=Continua em segundo plano +minimizeToTray=Minimiza para o tabuleiro +closeBehaviourAlertTitle=Define o comportamento de fecho +closeBehaviourAlertTitleHeader=Selecciona o que deve acontecer ao fechar a janela. Todas as ligações activas serão fechadas quando a aplicação for encerrada. +startupBehaviour=Comportamento de arranque +startupBehaviourDescription=Controla o comportamento predefinido da aplicação de ambiente de trabalho quando o XPipe é iniciado. +clearCachesAlertTitle=Limpa a cache +clearCachesAlertTitleHeader=Queres limpar todas as caches do XPipe? +clearCachesAlertTitleContent=Tem em atenção que isto irá eliminar todos os dados armazenados para melhorar a experiência do utilizador. +startGui=Inicia a GUI +startInTray=Inicia no tabuleiro +startInBackground=Inicia em segundo plano +clearCaches=Limpa as caches ... +clearCachesDescription=Elimina todos os dados da cache +apply=Aplica-te +cancel=Cancela +notAnAbsolutePath=Não é um caminho absoluto +notADirectory=Não é um diretório +notAnEmptyDirectory=Não é um diretório vazio +automaticallyUpdate=Verifica se há actualizações +automaticallyUpdateDescription=Quando ativado, as informações de novas versões são obtidas automaticamente enquanto o XPipe está em execução. Nenhum atualizador é executado em segundo plano e tens de confirmar explicitamente a instalação de qualquer atualização. +sendAnonymousErrorReports=Envia relatórios de erro anónimos +sendUsageStatistics=Envia estatísticas de utilização anónimas +storageDirectory=Diretório de armazenamento +storageDirectoryDescription=A localização onde o XPipe deve armazenar todas as informações de ligação. Esta definição só será aplicada na próxima reinicialização. Quando alteras isto, os dados no antigo diretório não são copiados para o novo. +logLevel=Nível de registo +appBehaviour=Comportamento da aplicação +logLevelDescription=O nível de registo que deve ser utilizado quando escreves ficheiros de registo. +developerMode=Modo de desenvolvimento +developerModeDescription=Quando ativado, terás acesso a uma variedade de opções adicionais que são úteis para o desenvolvimento. Só fica ativo depois de reiniciar. +editor=Editor +custom=Personaliza +passwordManagerCommand=Comando do gestor de senhas +passwordManagerCommandDescription=O comando a executar para ir buscar as palavras-passe. A string de espaço reservado $KEY será substituída pela chave de senha citada quando chamada. Isto deve chamar o teu gestor de senhas CLI para imprimir a senha para stdout, por exemplo, mypassmgr get $KEY.\n\nPodes então definir a chave para ser recuperada sempre que configurares uma ligação que requeira uma palavra-passe. +passwordManagerCommandTest=Testa o gestor de palavras-passe +passwordManagerCommandTestDescription=Podes testar aqui se a saída parece correcta se tiveres configurado um comando de gestão de palavras-passe. O comando só deve enviar a própria palavra-passe para stdout, não devendo ser incluída qualquer outra formatação na saída. +preferEditorTabs=Prefere abrir novos separadores +preferEditorTabsDescription=Controla se o XPipe tentará abrir novos separadores no editor escolhido em vez de novas janelas.\n\nNota que nem todos os editores suportam isto. +customRdpClientCommand=Comando personalizado +customRdpClientCommandDescription=O comando a ser executado para iniciar o cliente RDP personalizado.\n\nA cadeia de caracteres de espaço $FILE será substituída pelo nome do arquivo .rdp absoluto entre aspas quando chamado. Lembra-te de colocar entre aspas o teu caminho executável se este contiver espaços. +customEditorCommand=Comando do editor personalizado +customEditorCommandDescription=O comando a executar para iniciar o editor personalizado.\n\nA string de espaço reservado $FILE será substituída pelo nome absoluto do ficheiro entre aspas quando chamado. Lembra-te de citar o caminho executável do teu editor se este contiver espaços. +editorReloadTimeout=Tempo limite de recarga do editor +editorReloadTimeoutDescription=A quantidade de milissegundos a esperar antes de ler um ficheiro depois de este ter sido atualizado. Isto evita problemas nos casos em que o teu editor é lento a escrever ou a libertar bloqueios de ficheiros. +encryptAllVaultData=Encripta todos os dados do cofre +encryptAllVaultDataDescription=Quando ativado, todas as partes dos dados de ligação do vault serão encriptadas, em vez de apenas os segredos contidos nesses dados. Isto adiciona outra camada de segurança para outros parâmetros, como nomes de utilizador, nomes de anfitrião, etc., que não são encriptados por predefinição no vault.\n\nEsta opção tornará o histórico e os diffs do seu git vault inúteis, pois você não poderá mais ver as alterações originais, apenas as alterações binárias. +vaultSecurity=Segurança do cofre +developerDisableUpdateVersionCheck=Desativar a verificação da versão de atualização +developerDisableUpdateVersionCheckDescription=Controla se o verificador de actualizações ignora o número da versão quando procura uma atualização. +developerDisableGuiRestrictions=Desativar restrições GUI +developerDisableGuiRestrictionsDescription=Controla se algumas acções desactivadas ainda podem ser executadas a partir da interface do utilizador. +developerShowHiddenEntries=Mostra entradas ocultas +developerShowHiddenEntriesDescription=Quando ativado, as fontes de dados ocultas e internas serão mostradas. +developerShowHiddenProviders=Mostra fornecedores ocultos +developerShowHiddenProvidersDescription=Controla se os provedores de conexão e fonte de dados ocultos e internos serão mostrados no diálogo de criação. +developerDisableConnectorInstallationVersionCheck=Desativar a verificação da versão do conetor +developerDisableConnectorInstallationVersionCheckDescription=Controla se o verificador de actualizações ignora o número da versão ao inspecionar a versão de um conetor XPipe instalado numa máquina remota. +shellCommandTest=Teste de Comando Shell +shellCommandTestDescription=Executa um comando na sessão shell utilizada internamente pelo XPipe. +terminal=Terminal +terminalEmulator=Emulador de terminal +terminalConfiguration=Configuração do terminal +editorConfiguration=Configuração do editor +defaultApplication=Aplicação por defeito +terminalEmulatorDescription=O terminal predefinido a utilizar quando abre qualquer tipo de ligação shell. Esta aplicação é apenas utilizada para fins de visualização, o programa shell iniciado depende da própria ligação shell.\n\nO nível de suporte de funcionalidades varia consoante o terminal, é por isso que cada um está marcado como recomendado ou não recomendado. Todos os terminais não recomendados funcionam com o XPipe, mas podem não ter funcionalidades como separadores, cores de título, suporte de shell e muito mais. A tua experiência de utilizador será melhor se utilizares um terminal recomendado. +program=Programa +customTerminalCommand=Comando de terminal personalizado +customTerminalCommandDescription=O comando a executar para abrir o terminal personalizado com um determinado comando.\n\nO XPipe criará um script de shell de lançamento temporário para o teu terminal executar. A string de espaço reservado $CMD no comando que forneces será substituída pelo script de lançamento real quando chamado. Lembra-te de colocar entre aspas o caminho do executável do teu terminal se este contiver espaços. +clearTerminalOnInit=Limpa o terminal no início +clearTerminalOnInitDescription=Quando ativado, o XPipe executa um comando de limpeza quando é iniciada uma nova sessão de terminal para remover qualquer saída desnecessária. +enableFastTerminalStartup=Ativar o arranque rápido do terminal +enableFastTerminalStartupDescription=Quando ativado, tenta iniciar as sessões de terminal mais rapidamente, sempre que possível.\n\nIsto saltará várias verificações de arranque e não actualizará qualquer informação de sistema apresentada. Quaisquer erros de ligação só serão mostrados no terminal. +dontCachePasswords=Não guardar em cache as palavras-passe solicitadas +dontCachePasswordsDescription=Controla se as palavras-passe consultadas devem ser colocadas em cache internamente pelo XPipe para que não tenhas de as introduzir novamente na sessão atual.\n\nSe este comportamento estiver desativado, terás de voltar a introduzir quaisquer credenciais solicitadas sempre que estas forem requeridas pelo sistema. +denyTempScriptCreation=Recusa a criação de scripts temporários +denyTempScriptCreationDescription=Para realizar algumas das suas funcionalidades, o XPipe cria por vezes scripts de shell temporários num sistema de destino para permitir uma execução fácil de comandos simples. Estes não contêm qualquer informação sensível e são criados apenas para efeitos de implementação.\n\nSe este comportamento for desativado, o XPipe não criará quaisquer ficheiros temporários num sistema remoto. Esta opção é útil em contextos de alta segurança onde cada mudança no sistema de arquivos é monitorada. Se esta opção for desactivada, algumas funcionalidades, por exemplo, ambientes shell e scripts, não funcionarão como pretendido. +disableCertutilUse=Desativar a utilização do certutil no Windows +useLocalFallbackShell=Utiliza a shell de recurso local +useLocalFallbackShellDescription=Passa a usar outro shell local para lidar com operações locais. Seria o PowerShell no Windows e o bourne shell noutros sistemas.\n\nEsta opção pode ser usada no caso de o shell local padrão normal estar desativado ou quebrado em algum grau. No entanto, alguns recursos podem não funcionar como esperado quando esta opção está ativada.\n\nRequer uma reinicialização para ser aplicada. +disableCertutilUseDescription=Devido a várias falhas e bugs no cmd.exe, são criados scripts de shell temporários com o certutil, utilizando-o para descodificar a entrada base64, uma vez que o cmd.exe quebra em entradas não ASCII. O XPipe também pode usar o PowerShell para isso, mas será mais lento.\n\nIsso desabilita qualquer uso do certutil em sistemas Windows para realizar alguma funcionalidade e volta para o PowerShell. Isso pode agradar alguns AVs, pois alguns deles bloqueiam o uso do certutil. +disableTerminalRemotePasswordPreparation=Desativar a preparação da palavra-passe remota do terminal +disableTerminalRemotePasswordPreparationDescription=Em situações em que uma ligação shell remota que passa por vários sistemas intermédios deva ser estabelecida no terminal, pode ser necessário preparar quaisquer palavras-passe necessárias num dos sistemas intermédios para permitir o preenchimento automático de quaisquer prompts.\n\nSe não pretender que as palavras-passe sejam transferidas para qualquer sistema intermédio, pode desativar este comportamento. Qualquer senha intermediária necessária será então consultada no próprio terminal quando aberto. +more=Mais +translate=Tradução +allConnections=Todas as ligações +allScripts=Todos os scripts +predefined=Predefinido +default=Por defeito +goodMorning=Bom dia +goodAfternoon=Boa tarde +goodEvening=Boa noite +addVisual=Visual ... +ssh=SSH +sshConfiguration=Configuração SSH +size=Tamanho +attributes=Atribui +modified=Modificado +isOnlySupported=só é suportado com uma licença profissional +areOnlySupported=só são suportados com uma licença profissional +updateReadyTitle=Actualiza para $VERSION$ ready diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties new file mode 100644 index 000000000..fb17a6169 --- /dev/null +++ b/lang/app/strings/translations_ru.properties @@ -0,0 +1,426 @@ +delete=Удалить +rename=Переименовать +properties=Свойства +usedDate=Используется $DATE$ +openDir=Открытый каталог +sortLastUsed=Сортировка по дате последнего использования +sortAlphabetical=Сортировка по алфавиту по имени +restart=Перезапустить XPipe +restartDescription=Перезапуск часто может быть быстрым решением проблемы +reportIssue=Сообщить о проблеме +reportIssueDescription=Откройте интегрированный отчет о проблемах +usefulActions=Полезные действия +stored=Сохраненный +troubleshootingOptions=Инструменты для устранения неполадок +troubleshoot=Устранение неполадок +remote=Удаленный файл +addShellStore=Добавить оболочку ... +addShellTitle=Добавить подключение к оболочке +savedConnections=Сохраненные соединения +save=Сохранить +clean=Очистить +refresh=Обновить +moveTo=Перейти к ... +addDatabase=База данных ... +browseInternalStorage=Просмотр внутреннего хранилища +addTunnel=Туннель ... +addScript=Скрипт ... +addHost=Удаленный хост ... +addShell=Shell Environment ... +addCommand=Пользовательская команда ... +addAutomatically=Поиск в автоматическом режиме ... +addOther=Add Other ... +addConnection=Добавить соединение +skip=Пропустить +addConnections=Новый +selectType=Выберите тип +selectTypeDescription=Выберите тип соединения +selectShellType=Тип оболочки +selectShellTypeDescription=Выберите тип соединения с оболочкой +name=Имя +storeIntroTitle=Концентратор соединений +storeIntroDescription=Здесь ты можешь управлять всеми своими локальными и удаленными shell-соединениями в одном месте. Для начала ты можешь быстро обнаружить доступные соединения в автоматическом режиме и выбрать, какие из них добавить. +detectConnections=Поиск соединений +configuration=Конфигурация +dragAndDropFilesHere=Или просто перетащи сюда файл +confirmDsCreationAbortTitle=Подтверждение прерывания +confirmDsCreationAbortHeader=Хочешь прервать создание источника данных? +confirmDsCreationAbortContent=Весь прогресс создания источника данных будет потерян. +confirmInvalidStoreTitle=Неудачное соединение +confirmInvalidStoreHeader=Хочешь пропустить проверку соединения? +confirmInvalidStoreContent=Ты можешь добавить это соединение, даже если его не удалось подтвердить, и исправить проблемы с подключением позже. +none=Нет +expand=Развернуть +accessSubConnections=Подключения доступа +common=Common +color=Цвет +alwaysConfirmElevation=Всегда подтверждай повышение разрешения +alwaysConfirmElevationDescription=Управляет тем, как обрабатывать случаи, когда для запуска команды в системе требуются повышенные права, например, с помощью sudo.\n\nПо умолчанию любые учетные данные sudo кэшируются во время сессии и автоматически предоставляются при необходимости. Если эта опция включена, то каждый раз будет запрашиваться подтверждение повышенного доступа. +allow=Разрешить +ask=Спроси +deny=Запретить +share=Добавить в git-репозиторий +unshare=Удалить из git-репозитория +remove=Удалить +newCategory=Новая подкатегория +passwordManager=Менеджер паролей +prompt=Подсказка +customCommand=Пользовательская команда +other=Другие +setLock=Установить замок +selectConnection=Выберите соединение +changeLock=Изменить парольную фразу +test=Тест +lockCreationAlertTitle=Установите парольную фразу +lockCreationAlertHeader=Установите новую главную кодовую фразу +finish=Закончи +error=Произошла ошибка +downloadStageDescription=Загрузи файлы на локальную машину, чтобы ты мог перетащить их в родное окружение рабочего стола. +ok=Ок +search=Поиск +newFile=Новый файл +newDirectory=Новый каталог +passphrase=Пассфраза +repeatPassphrase=Повторная парольная фраза +password=Пароль +unlockAlertTitle=Разблокировать рабочую область +unlockAlertHeader=Введите парольную фразу своего хранилища, чтобы продолжить +enterLockPassword=Введите пароль от замка +repeatPassword=Повторять пароль +askpassAlertTitle=Askpass +unsupportedOperation=Неподдерживаемая операция: $MSG$ +fileConflictAlertTitle=Разрешить конфликт +fileConflictAlertHeader=Возник конфликт. Как бы ты хотел продолжить? +fileConflictAlertContent=Файл $FILE$ уже существует в целевой системе. +fileConflictAlertContentMultiple=Файл $FILE$ уже существует. Возможно, есть и другие конфликты, которые ты можешь автоматически разрешить, выбрав опцию, применимую ко всем. +moveAlertTitle=Подтвердить перемещение +moveAlertHeader=Ты хочешь переместить ($COUNT$) выбранные элементы в $TARGET$? +deleteAlertTitle=Подтверждение удаления +deleteAlertHeader=Хочешь удалить ($COUNT$) выбранные элементы? +selectedElements=Выбранные элементы: +mustNotBeEmpty=$VALUE$ не должен быть пустым +valueMustNotBeEmpty=Значение не должно быть пустым +transferDescription=Сбрасывать файлы для передачи +dragFiles=Перетаскивание файлов в браузере +dragLocalFiles=Перетащите локальные файлы отсюда +null=$VALUE$ должен быть не нулевым +roots=Корни +scripts=Скрипты +searchFilter=Поиск ... +recent=Последние +shortcut=Ярлык +browserWelcomeEmpty=Здесь ты сможешь увидеть, на чем ты остановился в прошлый раз. +browserWelcomeSystems=Недавно ты был подключен к следующим системам: +hostFeatureUnsupported=$FEATURE$ не установлен на хосте +missingStore=$NAME$ не существует +connectionName=Имя соединения +connectionNameDescription=Дайте этому соединению пользовательское имя +openFileTitle=Открытый файл +unknown=Неизвестный +scanAlertTitle=Добавить соединения +scanAlertChoiceHeader=Цель +scanAlertChoiceHeaderDescription=Выбери, где искать соединения. Сначала будут искаться все доступные соединения. +scanAlertHeader=Типы соединений +scanAlertHeaderDescription=Выбери типы соединений, которые ты хочешь автоматически добавлять для системы. +noInformationAvailable=Нет информации +localMachine=Локальная машина +yes=Да +no=Нет +errorOccured=Произошла ошибка +terminalErrorOccured=Произошла ошибка терминала +errorTypeOccured=Возникло исключение типа $TYPE$ +permissionsAlertTitle=Необходимые разрешения +permissionsAlertHeader=Для выполнения этой операции необходимы дополнительные разрешения. +permissionsAlertContent=Проследи за всплывающим окном, чтобы дать XPipe необходимые разрешения в меню настроек. +errorDetails=Показать подробности +updateReadyAlertTitle=Готовность к обновлению +updateReadyAlertHeader=Обновление до версии $VERSION$ готово к установке +updateReadyAlertContent=Это позволит установить новую версию и перезапустить XPipe после завершения установки. +errorNoDetail=Никаких подробностей об ошибке нет +updateAvailableTitle=Обновление доступно +updateAvailableHeader=Обновление XPipe до версии $VERSION$ доступно для установки +updateAvailableContent=Даже если XPipe не удалось запустить, ты можешь попытаться установить обновление, чтобы потенциально исправить проблему. +clipboardActionDetectedTitle=Обнаружено действие буфера обмена +clipboardActionDetectedHeader=Хочешь импортировать содержимое своего буфера обмена? +clipboardActionDetectedContent=XPipe обнаружила в твоем буфере обмена содержимое, которое можно открыть. Хочешь открыть его прямо сейчас? +install=Установи ... +ignore=Игнорируй +possibleActions=Возможные действия +reportError=Ошибка в отчете +reportOnGithub=Создайте отчет о проблеме на GitHub +reportOnGithubDescription=Открой новую проблему в репозитории GitHub +reportErrorDescription=Отправь отчет об ошибке с дополнительным отзывом пользователя и информацией о диагностике +ignoreError=Игнорировать ошибку +ignoreErrorDescription=Игнорируй эту ошибку и продолжай как ни в чем не бывало +provideEmail=Как с тобой связаться (необязательно, только если ты хочешь получать уведомления об исправлениях) +additionalErrorInfo=Предоставьте дополнительную информацию (необязательно) +additionalErrorAttachments=Выберите вложения (необязательно) +dataHandlingPolicies=Политика конфиденциальности +sendReport=Отправить отчет +errorHandler=Обработчик ошибок +events=События +method=Метод +validate=Проверь +stackTrace=Трассировка стека +previousStep=< Предыдущий +nextStep=Следующая > +finishStep=Закончи +edit=Редактировать +browseInternal=Обзор внутренних +checkOutUpdate=Проверить обновление +open=Открыть +quit=Выйти из игры +noTerminalSet=Ни одно приложение для терминала не было установлено автоматически. Ты можешь сделать это вручную в меню настроек. +connections=Соединения +settings=Настройки +explorePlans=Лицензия +help=Справка +about=О сайте +developer=Разработчик +browseFileTitle=Просмотр файла +browse=Просматривай +browser=Браузер +selectFileFromComputer=Выберите файл с этого компьютера +links=Полезные ссылки +website=Сайт +documentation=Документация +discordDescription=Присоединяйтесь к серверу Discord +security=Безопасность +securityPolicy=Информация о безопасности +securityPolicyDescription=Прочитай подробную политику безопасности +privacy=Политика конфиденциальности +privacyDescription=Прочитай политику конфиденциальности для приложения XPipe +slackDescription=Присоединяйся к рабочему пространству Slack +support=Поддержите +githubDescription=Загляни в репозиторий GitHub +openSourceNotices=Уведомления об открытом исходном коде +xPipeClient=XPipe Desktop +checkForUpdates=Проверьте наличие обновлений +checkForUpdatesDescription=Загрузите обновление, если оно есть +lastChecked=Последняя проверка +version=Версия +build=Версия сборки +runtimeVersion=Версия для выполнения +virtualMachine=Виртуальная машина +updateReady=Установить обновление +updateReadyPortable=Проверить обновление +updateReadyDescription=Обновление было загружено и готово к установке +updateReadyDescriptionPortable=Обновление доступно для загрузки +updateRestart=Перезапустить, чтобы обновить +never=Никогда +updateAvailableTooltip=Обновление доступно +visitGithubRepository=Посетите репозиторий GitHub +updateAvailable=Доступно обновление: $VERSION$ +downloadUpdate=Скачать обновление +legalAccept=Я принимаю лицензионное соглашение с конечным пользователем +confirm=Подтверди +print=Распечатать +whatsNew=Что нового в версии $VERSION$ ($DATE$) +antivirusNoticeTitle=Заметка об антивирусных программах +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Добро пожаловать в XPipe +gotIt=Понял +eula=Лицензионное соглашение с конечным пользователем +news=Новости +introduction=Введение +privacyPolicy=Политика конфиденциальности +agree=Согласись +disagree=Не соглашайся +directories=Директории +logFile=Лог-файл +logFiles=Лог-файлы +logFilesAttachment=Лог-файлы +issueReporter=Репортер проблем +openCurrentLogFile=Лог-файлы +openCurrentLogFileDescription=Открыть файл журнала текущей сессии +openLogsDirectory=Открыть каталог журналов +installationFiles=Установочные файлы +openInstallationDirectory=Установочные файлы +openInstallationDirectoryDescription=Откройте каталог установки XPipe +launchDebugMode=Режим отладки +launchDebugModeDescription=Перезапуск XPipe в режиме отладки +extensionInstallTitle=Скачать +extensionInstallDescription=Для этого действия требуются дополнительные сторонние библиотеки, которые не распространяются XPipe. Ты можешь автоматически установить их здесь. Затем компоненты загружаются с сайта производителя: +extensionInstallLicenseNote=Выполняя загрузку и автоматическую установку, ты соглашаешься с условиями лицензий третьих лиц: +license=Лицензия +installRequired=Требуется установка +restore=Восстанови +restoreAllSessions=Восстановление всех сессий +connectionTimeout=Таймаут запуска соединения +connectionTimeoutDescription=Время в секундах, в течение которого нужно ждать ответа, прежде чем считать соединение прерванным по таймеру. Если некоторые из твоих удаленных систем долго подключаются, попробуй увеличить это значение. +useBundledTools=Используйте прилагаемые инструменты OpenSSH +useBundledToolsDescription=Предпочитай использовать поставляемую в комплекте версию клиента openssh вместо локально установленного.\n\nЭта версия обычно более актуальна, чем та, что поставляется в твоей системе, и может поддерживать дополнительные возможности. Это также избавляет от необходимости устанавливать эти инструменты в первую очередь.\n\nДля применения требуется перезагрузка. +appearance=Внешний вид +integrations=Интеграции +uiOptions=Параметры пользовательского интерфейса +theme=Тема +rdp=Удаленный рабочий стол +rdpConfiguration=Настройка удаленного рабочего стола +rdpClient=RDP-клиент +rdpClientDescription=Программа-клиент RDP, которую нужно вызывать при запуске RDP-соединений.\n\nУчти, что разные клиенты имеют разную степень возможностей и интеграции. Некоторые клиенты не поддерживают автоматическую передачу паролей, поэтому тебе все равно придется заполнять их при запуске. +localShell=Локальная оболочка +themeDescription=Предпочитаемая тобой тема отображения +dontAutomaticallyStartVmSshServer=Не запускай автоматически SSH-сервер для виртуальных машин, когда это необходимо +dontAutomaticallyStartVmSshServerDescription=Любое shell-подключение к виртуальной машине, запущенной в гипервизоре, осуществляется через SSH. XPipe может автоматически запускать установленный SSH-сервер, когда это необходимо. Если тебе это не нужно по соображениям безопасности, то ты можешь просто отключить такое поведение с помощью этой опции. +confirmGitShareTitle=Подтверждение совместного использования git +confirmGitShareHeader=Это скопирует файл в твое хранилище git и зафиксирует твои изменения. Хочешь продолжить? +gitShareFileTooltip=Добавь файл в каталог данных git vault, чтобы он автоматически синхронизировался.\n\nЭто действие можно использовать, только если в настройках включено git-хранилище. +performanceMode=Режим производительности +performanceModeDescription=Отключи все визуальные эффекты, которые не нужны, чтобы повысить производительность приложения. +dontAcceptNewHostKeys=Не принимай новые ключи хоста SSH автоматически +dontAcceptNewHostKeysDescription=XPipe по умолчанию автоматически принимает хост-ключи от систем, в которых у твоего SSH-клиента нет уже сохраненного известного хост-ключа. Однако если какой-либо известный ключ хоста изменился, он откажется подключаться, пока ты не примешь новый.\n\nОтключение этого поведения позволяет тебе проверять все хост-ключи, даже если изначально конфликта нет. +uiScale=Шкала пользовательского интерфейса +uiScaleDescription=Пользовательское значение масштабирования, которое может быть установлено независимо от общесистемного масштаба отображения. Значения указываются в процентах, поэтому, например, значение 150 приведет к масштабированию пользовательского интерфейса на 150%.\n\nДля применения требуется перезагрузка. +editorProgram=Программа-редактор +editorProgramDescription=Текстовый редактор по умолчанию, который используется при редактировании любого вида текстовых данных. +windowOpacity=Непрозрачность окна +windowOpacityDescription=Изменяет непрозрачность окна, чтобы следить за тем, что происходит на заднем плане. +useSystemFont=Используйте системный шрифт +openDataDir=Каталог данных хранилища +openDataDirButton=Открытый каталог данных +openDataDirDescription=Если ты хочешь синхронизировать дополнительные файлы, например SSH-ключи, между системами с твоим git-репозиторием, ты можешь поместить их в каталог данных хранилища. У любых файлов, на которые там ссылаются, пути к файлам будут автоматически адаптированы на любой синхронизированной системе. +updates=Обновления +passwordKey=Ключ пароля +selectAll=Выберите все +command=Команда +advanced=Продвинутый +thirdParty=Уведомления с открытым исходным кодом +eulaDescription=Прочитай лицензионное соглашение с конечным пользователем для приложения XPipe +thirdPartyDescription=Просмотр лицензий с открытым исходным кодом сторонних библиотек +workspaceLock=Мастер-пароль +enableGitStorage=Включить синхронизацию git +sharing=Обмен +sync=Синхронизация +enableGitStorageDescription=Когда эта функция включена, XPipe инициализирует git-репозиторий для хранения данных о соединении и фиксирует в нем все изменения. Учти, что это требует установки git и может замедлить операции загрузки и сохранения.\n\nВсе категории, которые должны синхронизироваться, должны быть явно обозначены как общие.\n\nТребуется перезапуск для применения. +storageGitRemote=Удаленный URL-адрес Git +storageGitRemoteDescription=Если установить эту настройку, XPipe будет автоматически вытаскивать любые изменения при загрузке и выталкивать их в удаленный репозиторий при сохранении.\n\nЭто позволяет тебе обмениваться конфигурационными данными между несколькими установками XPipe. Поддерживаются как HTTP, так и SSH-адреса. Учти, что это может замедлить операции загрузки и сохранения.\n\nДля применения требуется перезагрузка. +vault=Vault +workspaceLockDescription=Устанавливает пользовательский пароль для шифрования любой конфиденциальной информации, хранящейся в XPipe.\n\nЭто повышает безопасность, так как обеспечивает дополнительный уровень шифрования хранимой тобой конфиденциальной информации. При запуске XPipe тебе будет предложено ввести пароль. +useSystemFontDescription=Контролирует, использовать ли системный шрифт или шрифт Roboto, который поставляется в комплекте с XPipe. +tooltipDelay=Задержка всплывающей подсказки +tooltipDelayDescription=Количество миллисекунд, которое нужно подождать до появления всплывающей подсказки. +fontSize=Размер шрифта +windowOptions=Параметры окна +saveWindowLocation=Сохранить местоположение окна +saveWindowLocationDescription=Контролирует, нужно ли сохранять координаты окна и восстанавливать их при перезагрузке. +startupShutdown=Запуск / выключение +showChildCategoriesInParentCategory=Показывать дочерние категории в родительской категории +showChildCategoriesInParentCategoryDescription=Включать или не включать все соединения, расположенные в подкатегориях, при выборе определенной родительской категории.\n\nЕсли эта опция отключена, то категории будут вести себя скорее как классические папки, в которых отображается только их непосредственное содержимое без включения вложенных папок. +condenseConnectionDisplay=Конденсаторное отображение соединения +condenseConnectionDisplayDescription=Сделай так, чтобы каждое соединение верхнего уровня занимало меньше места по вертикали, чтобы список соединений был более сжатым. +enforceWindowModality=Модальность окна принуждения +enforceWindowModalityDescription=Заставляет второстепенные окна, например диалог создания соединения, блокировать весь ввод для главного окна, пока они открыты. Это полезно, если ты иногда ошибаешься при нажатии. +openConnectionSearchWindowOnConnectionCreation=Открыть окно поиска соединения при его создании +openConnectionSearchWindowOnConnectionCreationDescription=Нужно ли автоматически открывать окно для поиска доступных подсоединений при добавлении нового соединения оболочки. +workflow=Рабочий процесс +system=Система +application=Приложение +storage=Хранилище +runOnStartup=Запуск при запуске +closeBehaviour=Близкое поведение +closeBehaviourDescription=Управляет тем, как XPipe должен действовать после закрытия своего главного окна. +language=Язык +languageDescription=Язык отображения, который нужно использовать.\n\nОбрати внимание, что в качестве основы используются автоматические переводы, которые вручную исправляются и улучшаются соавторами. Ты также можешь помочь усилиям по переводу, отправляя исправления перевода на GitHub. +lightTheme=Легкая тема +darkTheme=Темная тема +exit=Выйти из XPipe +continueInBackground=Продолжение на заднем плане +minimizeToTray=Минимизировать в трей +closeBehaviourAlertTitle=Установить поведение при закрытии +closeBehaviourAlertTitleHeader=Выбери, что должно произойти при закрытии окна. Все активные соединения будут закрыты при завершении работы приложения. +startupBehaviour=Поведение при запуске +startupBehaviourDescription=Управляет поведением настольного приложения по умолчанию при запуске XPipe. +clearCachesAlertTitle=Очистить кэш +clearCachesAlertTitleHeader=Хочешь очистить все кэши XPipe? +clearCachesAlertTitleContent=Учти, что при этом будут удалены все данные, которые хранятся для улучшения пользовательского опыта. +startGui=Запуск графического интерфейса +startInTray=Запуск в трее +startInBackground=Запуск в фоновом режиме +clearCaches=Очистите кэш ... +clearCachesDescription=Удалить все данные из кэша +apply=Применяй +cancel=Отмена +notAnAbsolutePath=Не абсолютный путь +notADirectory=Не каталог +notAnEmptyDirectory=Не пустая директория +automaticallyUpdate=Проверьте наличие обновлений +automaticallyUpdateDescription=Если эта функция включена, то информация о новых релизах автоматически подхватывается во время работы XPipe. Никакой программы обновления не запускается в фоновом режиме, и тебе все равно придется явно подтверждать установку любого обновления. +sendAnonymousErrorReports=Отправлять анонимные сообщения об ошибках +sendUsageStatistics=Отправляйте анонимную статистику использования +storageDirectory=Каталог хранилищ +storageDirectoryDescription=Место, где XPipe должен хранить всю информацию о соединениях. Эта настройка будет применена только при следующем перезапуске. При ее изменении данные из старой директории не копируются в новую. +logLevel=Уровень журнала +appBehaviour=Поведение приложения +logLevelDescription=Уровень журнала, который следует использовать при записи лог-файлов. +developerMode=Режим разработчика +developerModeDescription=Если включить эту функцию, то ты получишь доступ к множеству дополнительных опций, полезных для разработки. Активен только после перезапуска. +editor=Редактор +custom=Пользовательский +passwordManagerCommand=Команда менеджера паролей +passwordManagerCommandDescription=Команда, которую нужно выполнить для получения паролей. Строка-заполнитель $KEY при вызове будет заменена на заключенный в кавычки ключ пароля. Это должно вызвать CLI твоего менеджера паролей для печати пароля в stdout, например, mypassmgr get $KEY.\n\nЗатем ты можешь задать, чтобы ключ извлекался всякий раз, когда ты устанавливаешь соединение, требующее ввода пароля. +passwordManagerCommandTest=Тестовый менеджер паролей +passwordManagerCommandTestDescription=Здесь ты можешь проверить, правильно ли выглядит вывод, если ты настроил команду менеджера паролей. Команда должна выводить в stdout только сам пароль, никакое другое форматирование не должно присутствовать в выводе. +preferEditorTabs=Предпочитает открывать новые вкладки +preferEditorTabsDescription=Контролирует, будет ли XPipe пытаться открывать новые вкладки в выбранном тобой редакторе вместо новых окон.\n\nУчти, что не каждый редактор поддерживает эту функцию. +customRdpClientCommand=Пользовательская команда +customRdpClientCommandDescription=Команда, которую нужно выполнить, чтобы запустить пользовательский RDP-клиент.\n\nСтрока-заполнитель $FILE при вызове будет заменена на заключенное в кавычки абсолютное имя файла .rdp. Не забудь взять в кавычки путь к исполняемому файлу, если он содержит пробелы. +customEditorCommand=Пользовательская команда редактора +customEditorCommandDescription=Команда, которую нужно выполнить, чтобы запустить пользовательский редактор.\n\nСтрока-заполнитель $FILE при вызове будет заменена абсолютным именем файла, взятым в кавычки. Не забудь взять в кавычки путь к исполняемому файлу редактора, если он содержит пробелы. +editorReloadTimeout=Таймаут перезагрузки редактора +editorReloadTimeoutDescription=Количество миллисекунд, которое нужно подождать, прежде чем читать файл после его обновления. Это позволяет избежать проблем в тех случаях, когда твой редактор медленно записывает или снимает блокировки файлов. +encryptAllVaultData=Зашифровать все данные хранилища +encryptAllVaultDataDescription=Если эта функция включена, то каждая часть данных о соединении с хранилищем будет зашифрована, а не только секреты внутри этих данных. Это добавляет еще один уровень безопасности для других параметров, таких как имена пользователей, имена хостов и т.д., которые по умолчанию не шифруются в хранилище.\n\nЭта опция сделает историю git-хранилища и дифы бесполезными, так как ты больше не сможешь увидеть оригинальные изменения, только бинарные. +vaultSecurity=Безопасность хранилища +developerDisableUpdateVersionCheck=Отключить проверку версий обновлений +developerDisableUpdateVersionCheckDescription=Контролирует, будет ли программа проверки обновлений игнорировать номер версии при поиске обновления. +developerDisableGuiRestrictions=Отключить ограничения графического интерфейса +developerDisableGuiRestrictionsDescription=Контролирует, могут ли некоторые отключенные действия по-прежнему выполняться из пользовательского интерфейса. +developerShowHiddenEntries=Показать скрытые записи +developerShowHiddenEntriesDescription=Если включить эту функцию, будут показаны скрытые и внутренние источники данных. +developerShowHiddenProviders=Показать скрытых провайдеров +developerShowHiddenProvidersDescription=Контролирует, будут ли в диалоге создания показываться скрытые и внутренние провайдеры соединений и источников данных. +developerDisableConnectorInstallationVersionCheck=Отключить проверку версии коннектора +developerDisableConnectorInstallationVersionCheckDescription=Контролирует, будет ли программа проверки обновлений игнорировать номер версии при проверке версии коннектора XPipe, установленного на удаленной машине. +shellCommandTest=Тест на знание команд оболочки +shellCommandTestDescription=Выполни команду в сессии оболочки, которая используется внутри XPipe. +terminal=Терминал +terminalEmulator=Эмулятор терминала +terminalConfiguration=Конфигурация терминала +editorConfiguration=Конфигурация редактора +defaultApplication=Приложение по умолчанию +terminalEmulatorDescription=Терминал по умолчанию, который используется при открытии любого типа shell-соединения. Это приложение используется только для отображения, запущенная программа-оболочка зависит от самого shell-соединения.\n\nУровень поддержки функций у разных терминалов разный, поэтому каждый из них помечен как рекомендуемый или нерекомендуемый. Все нерекомендованные терминалы работают с XPipe, но в них могут отсутствовать такие функции, как вкладки, цвета заголовков, поддержка оболочек и многое другое. Твой пользовательский опыт будет наилучшим при использовании рекомендуемого терминала. +program=Программа +customTerminalCommand=Пользовательская команда терминала +customTerminalCommandDescription=Команда, которую нужно выполнить, чтобы открыть пользовательский терминал с заданной командой.\n\nXPipe создаст временный скрипт оболочки запуска для твоего терминала, который будет выполняться. Строка-заполнитель $CMD в команде, которую ты предоставишь, при вызове будет заменена реальным скриптом запуска. Не забудь взять в кавычки путь к исполняемому файлу твоего терминала, если он содержит пробелы. +clearTerminalOnInit=Очистить терминал при инициализации +clearTerminalOnInitDescription=Если включить эту функцию, то при запуске новой терминальной сессии XPipe будет выполнять команду clear, чтобы удалить ненужный вывод. +enableFastTerminalStartup=Включите быстрый запуск терминала +enableFastTerminalStartupDescription=Когда эта функция включена, терминальные сессии стараются запускать быстрее, если это возможно.\n\nПри этом будет пропущено несколько проверок запуска и не будет обновляться отображаемая системная информация. Любые ошибки подключения будут отображаться только в терминале. +dontCachePasswords=Не кэшируй введенные пароли +dontCachePasswordsDescription=Контролирует, нужно ли кэшировать запрашиваемые пароли внутри XPipe, чтобы тебе не пришлось вводить их снова в текущей сессии.\n\nЕсли это поведение отключено, тебе придется заново вводить запрашиваемые учетные данные каждый раз, когда они потребуются системе. +denyTempScriptCreation=Запрет на создание временных скриптов +denyTempScriptCreationDescription=Для реализации некоторых своих функций XPipe иногда создает временные shell-скрипты на целевой системе, чтобы обеспечить легкое выполнение простых команд. Они не содержат никакой конфиденциальной информации и создаются просто в целях реализации.\n\nЕсли отключить это поведение, XPipe не будет создавать никаких временных файлов на удаленной системе. Эта опция полезна в условиях повышенной безопасности, когда отслеживается каждое изменение файловой системы. Если эта опция отключена, некоторые функции, например, окружения оболочки и скрипты, не будут работать так, как задумано. +disableCertutilUse=Отключите использование certutil в Windows +useLocalFallbackShell=Использовать локальную резервную оболочку +useLocalFallbackShellDescription=Переключись на использование другой локальной оболочки для выполнения локальных операций. Это может быть PowerShell в Windows и bourne shell в других системах.\n\nЭту опцию можно использовать в том случае, если обычная локальная оболочка по умолчанию отключена или в какой-то степени сломана. Однако при включении этой опции некоторые функции могут работать не так, как ожидалось.\n\nДля применения требуется перезагрузка. +disableCertutilUseDescription=Из-за ряда недостатков и ошибок в cmd.exe временные shell-скрипты создаются с помощью certutil, используя его для декодирования ввода base64, так как cmd.exe ломается при вводе не ASCII. XPipe также может использовать для этого PowerShell, но это будет медленнее.\n\nТаким образом, на Windows-системах отменяется использование certutil для реализации некоторой функциональности, и вместо него используется PowerShell. Это может порадовать некоторые антивирусы, так как некоторые из них блокируют использование certutil. +disableTerminalRemotePasswordPreparation=Отключить подготовку удаленного пароля терминала +disableTerminalRemotePasswordPreparationDescription=В ситуациях, когда в терминале необходимо установить удаленное shell-соединение, проходящее через несколько промежуточных систем, может возникнуть необходимость подготовить все необходимые пароли на одной из промежуточных систем, чтобы обеспечить автоматическое заполнение любых подсказок.\n\nЕсли ты не хочешь, чтобы пароли когда-либо передавались в какую-либо промежуточную систему, ты можешь отключить это поведение. Тогда любой требуемый промежуточный пароль будет запрашиваться в самом терминале при его открытии. +more=Подробнее +translate=Переводы +allConnections=Все соединения +allScripts=Все скрипты +predefined=Предопределенный +default=По умолчанию +goodMorning=Доброе утро +goodAfternoon=Добрый день +goodEvening=Добрый вечер +addVisual=Visual ... +ssh=SSH +sshConfiguration=Конфигурация SSH +size=Размер +attributes=Атрибуты +modified=Изменено +isOnlySupported=поддерживается только при наличии профессиональной лицензии +areOnlySupported=поддерживаются только с профессиональной лицензией +updateReadyTitle=Обновление на $VERSION$ готово diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties new file mode 100644 index 000000000..f35f7f729 --- /dev/null +++ b/lang/app/strings/translations_tr.properties @@ -0,0 +1,426 @@ +delete=Silme +rename=Yeniden Adlandır +properties=Özellikler +usedDate=Kullanılmış $DATE$ +openDir=Açık Dizin +sortLastUsed=Son kullanım tarihine göre sırala +sortAlphabetical=İsme göre alfabetik sıralama +restart=XPipe'ı yeniden başlatın +restartDescription=Yeniden başlatma genellikle hızlı bir çözüm olabilir +reportIssue=Bir sorun bildirin +reportIssueDescription=Entegre sorun raportörünü açın +usefulActions=Yararlı eylemler +stored=Kurtarıldı +troubleshootingOptions=Sorun giderme araçları +troubleshoot=Sorun Giderme +remote=Uzak Dosya +addShellStore=Kabuk Ekle ... +addShellTitle=Kabuk Bağlantısı Ekleme +savedConnections=Kaydedilen Bağlantılar +save=Kaydet +clean=Temiz +refresh=Yenile +moveTo=Taşınmak ... +addDatabase=Veritabanı ... +browseInternalStorage=Dahili depolama alanına göz atın +addTunnel=Tünel ... +addScript=Senaryo ... +addHost=Uzak Ana Bilgisayar ... +addShell=Shell Çevre ... +addCommand=Özel Komut ... +addAutomatically=Otomatik Olarak Ara ... +addOther=Diğerlerini Ekle ... +addConnection=Bağlantı Ekle +skip=Atla +addConnections=Yeni +selectType=Tip Seçiniz +selectTypeDescription=Bağlantı türünü seçin +selectShellType=Kabuk Tipi +selectShellTypeDescription=Kabuk Bağlantı Türünü Seçin +name=İsim +storeIntroTitle=Bağlantı Merkezi +storeIntroDescription=Burada tüm yerel ve uzak kabuk bağlantılarınızı tek bir yerden yönetebilirsiniz. Başlangıç olarak, mevcut bağlantıları otomatik olarak hızlı bir şekilde algılayabilir ve hangilerinin ekleneceğini seçebilirsiniz. +detectConnections=Bağlantıları arayın +configuration=Konfigürasyon +dragAndDropFilesHere=Ya da bir dosyayı buraya sürükleyip bırakın +confirmDsCreationAbortTitle=İptal işlemini onayla +confirmDsCreationAbortHeader=Veri kaynağı oluşturma işlemini iptal etmek istiyor musunuz? +confirmDsCreationAbortContent=Tüm veri kaynağı oluşturma ilerlemeleri kaybolacaktır. +confirmInvalidStoreTitle=Başarısız bağlantı +confirmInvalidStoreHeader=Bağlantı doğrulamasını atlamak mı istiyorsunuz? +confirmInvalidStoreContent=Doğrulanamamış olsa bile bu bağlantıyı ekleyebilir ve bağlantı sorunlarını daha sonra düzeltebilirsiniz. +none=Hiçbiri +expand=Genişlet +accessSubConnections=Alt bağlantılara erişim +common=Ortak +color=Renk +alwaysConfirmElevation=Her zaman izin yükseltmesini onaylayın +alwaysConfirmElevationDescription=Sistemde bir komut çalıştırmak için sudo gibi yüksek izinlerin gerektiği durumların nasıl ele alınacağını kontrol eder.\n\nVarsayılan olarak, tüm sudo kimlik bilgileri bir oturum sırasında önbelleğe alınır ve gerektiğinde otomatik olarak sağlanır. Bu seçenek etkinleştirilirse, her seferinde yükseltme erişimini onaylamanızı isteyecektir. +allow=İzin ver +ask=Sor +deny=Reddet +share=Git deposuna ekle +unshare=Git deposundan kaldır +remove=Kaldırmak +newCategory=Yeni alt kategori +passwordManager=Parola yöneticisi +prompt=İstem +customCommand=Özel komut +other=Diğer +setLock=Kilidi ayarla +selectConnection=Bağlantı seçin +changeLock=Parolayı değiştir +test=Test +lockCreationAlertTitle=Parolayı ayarla +lockCreationAlertHeader=Yeni ana parolanızı ayarlayın +finish=Bitirmek +error=Bir hata oluştu +downloadStageDescription=Dosyaları yerel makinenize indirir, böylece bunları yerel masaüstü ortamınıza sürükleyip bırakabilirsiniz. +ok=Tamam +search=Arama +newFile=Yeni dosya +newDirectory=Yeni dizin +passphrase=Parola +repeatPassphrase=Parolayı tekrarla +password=Şifre +unlockAlertTitle=Çalışma alanının kilidini aç +unlockAlertHeader=Devam etmek için kasa parolanızı girin +enterLockPassword=Kilit şifresini girin +repeatPassword=Şifreyi tekrarla +askpassAlertTitle=Askpass +unsupportedOperation=Desteklenmeyen işlem: $MSG$ +fileConflictAlertTitle=Çatışma çözme +fileConflictAlertHeader=Bir çakışma ile karşılaşıldı. Nasıl devam etmek istersiniz? +fileConflictAlertContent=$FILE$ dosyası hedef sistemde zaten var. +fileConflictAlertContentMultiple=$FILE$ dosyası zaten var. Tümü için geçerli olan bir seçeneği seçerek otomatik olarak çözebileceğiniz daha fazla çakışma olabilir. +moveAlertTitle=Hareketi onayla +moveAlertHeader=($COUNT$) seçili öğeleri $TARGET$ adresine taşımak istiyor musunuz? +deleteAlertTitle=Silme işlemini onayla +deleteAlertHeader=($COUNT$) seçili öğeleri silmek istiyor musunuz? +selectedElements=Seçilen unsurlar: +mustNotBeEmpty=$VALUE$ boş olmamalıdır +valueMustNotBeEmpty=Değer boş olmamalıdır +transferDescription=Aktarılacak dosyaları bırakın +dragFiles=Dosyaları tarayıcı içinde sürükleyin +dragLocalFiles=Yerel dosyaları buradan sürükleyin +null=$VALUE$ null olmamalıdır +roots=Kökler +scripts=Senaryolar +searchFilter=Arama ... +recent=Yakın zamanda +shortcut=Kısayol +browserWelcomeEmpty=Burada en son nerede kaldığınızı görebileceksiniz. +browserWelcomeSystems=Yakın zamanda aşağıdaki sistemlere bağlandınız: +hostFeatureUnsupported=$FEATURE$ ana bilgisayarda yüklü değil +missingStore=$NAME$ mevcut değil +connectionName=Bağlantı adı +connectionNameDescription=Bu bağlantıya özel bir ad verin +openFileTitle=Dosya aç +unknown=Bilinmiyor +scanAlertTitle=Bağlantı ekleme +scanAlertChoiceHeader=Hedef +scanAlertChoiceHeaderDescription=Bağlantıların nerede aranacağını seçin. Bu, önce mevcut tüm bağlantıları arayacaktır. +scanAlertHeader=Bağlantı türleri +scanAlertHeaderDescription=Sistem için otomatik olarak eklemek istediğiniz bağlantı türlerini seçin. +noInformationAvailable=Bilgi mevcut değil +localMachine=Yerel Makine +yes=Evet +no=Hayır +errorOccured=Bir hata oluştu +terminalErrorOccured=Bir terminal hatası oluştu +errorTypeOccured=$TYPE$ türünde bir istisna fırlatıldı +permissionsAlertTitle=Gerekli izinler +permissionsAlertHeader=Bu işlemi gerçekleştirmek için ek izinler gereklidir. +permissionsAlertContent=XPipe'a ayarlar menüsünde gerekli izinleri vermek için lütfen açılır pencereyi izleyin. +errorDetails=Detayları göster +updateReadyAlertTitle=Güncelleme Hazır +updateReadyAlertHeader=$VERSION$ sürümüne bir güncelleme yüklenmeye hazırdır +updateReadyAlertContent=Bu işlem yeni sürümü yükleyecek ve yükleme tamamlandığında XPipe'ı yeniden başlatacaktır. +errorNoDetail=Hata ayrıntıları mevcut değil +updateAvailableTitle=Güncelleme Mevcut +updateAvailableHeader=$VERSION$ sürümüne yönelik bir XPipe güncellemesi yüklenebilir +updateAvailableContent=XPipe başlatılamamış olsa da, sorunu çözmek için güncellemeyi yüklemeyi deneyebilirsiniz. +clipboardActionDetectedTitle=Pano Eylemi algılandı +clipboardActionDetectedHeader=Pano içeriğinizi içe aktarmak mı istiyorsunuz? +clipboardActionDetectedContent=XPipe panonuzda açılabilecek bir içerik algıladı. Şimdi açmak istiyor musunuz? +install=Yükle ... +ignore=Görmezden gel +possibleActions=Olası eylemler +reportError=Hata bildir +reportOnGithub=GitHub'da bir sorun raporu oluşturun +reportOnGithubDescription=GitHub deposunda yeni bir sorun açın +reportErrorDescription=İsteğe bağlı kullanıcı geri bildirimi ve tanılama bilgileri içeren bir hata raporu gönderin +ignoreError=Hatayı yoksay +ignoreErrorDescription=Bu hatayı görmezden gelin ve hiçbir şey olmamış gibi devam edin +provideEmail=Sizinle nasıl iletişime geçebiliriz (isteğe bağlı, yalnızca düzeltmeler hakkında bilgilendirilmek istiyorsanız) +additionalErrorInfo=Ek bilgi sağlayın (isteğe bağlı) +additionalErrorAttachments=Ekleri seçin (isteğe bağlı) +dataHandlingPolicies=Gizlilik Politikası +sendReport=Rapor gönder +errorHandler=Hata işleyici +events=Etkinlikler +method=Yöntem +validate=Doğrulama +stackTrace=Yığın izi +previousStep=< Önceki +nextStep=Sonraki > +finishStep=Bitirmek +edit=Düzenle +browseInternal=Dahili Gözat +checkOutUpdate=Güncellemeye göz atın +open=Açık +quit=Bırak +noTerminalSet=Hiçbir terminal uygulaması otomatik olarak ayarlanmamıştır. Bunu ayarlar menüsünden manuel olarak yapabilirsiniz. +connections=Bağlantılar +settings=Ayarlar +explorePlans=Lisans +help=Yardım +about=Hakkında +developer=Geliştirici +browseFileTitle=Dosyaya göz at +browse=Gözat +browser=Tarayıcı +selectFileFromComputer=Bu bilgisayardan bir dosya seçin +links=Faydalı bağlantılar +website=Web sitesi +documentation=Dokümantasyon +discordDescription=Discord sunucusuna katılın +security=Güvenlik +securityPolicy=Güvenlik bilgileri +securityPolicyDescription=Ayrıntılı güvenlik politikasını okuyun +privacy=Gizlilik Politikası +privacyDescription=XPipe uygulaması için gizlilik politikasını okuyun +slackDescription=Slack çalışma alanına katılın +support=Destek +githubDescription=GitHub deposuna göz atın +openSourceNotices=Açık Kaynak Bildirimleri +xPipeClient=XPipe Masaüstü +checkForUpdates=Güncellemeleri kontrol edin +checkForUpdatesDescription=Varsa bir güncelleme indirin +lastChecked=Son kontrol +version=Versiyon +build=Sürüm oluştur +runtimeVersion=Çalışma zamanı sürümü +virtualMachine=Sanal makine +updateReady=Güncellemeyi yükleyin +updateReadyPortable=Güncellemeye göz atın +updateReadyDescription=Bir güncelleme indirildi ve yüklenmeye hazır +updateReadyDescriptionPortable=Bir güncelleme indirilebilir +updateRestart=Güncellemek için yeniden başlatın +never=Asla +updateAvailableTooltip=Güncelleme mevcut +visitGithubRepository=GitHub deposunu ziyaret edin +updateAvailable=Güncelleme mevcut: $VERSION$ +downloadUpdate=Güncellemeyi indirin +legalAccept=Son Kullanıcı Lisans Sözleşmesini kabul ediyorum +confirm=Onaylayın +print=Yazdır +whatsNew=$VERSION$ sürümündeki yenilikler ($DATE$) +antivirusNoticeTitle=Antivirüs programları hakkında bir not +updateChangelogAlertTitle=Değişiklik Günlüğü +greetingsAlertTitle=XPipe'a Hoş Geldiniz +gotIt=Anladım +eula=Son Kullanıcı Lisans Sözleşmesi +news=Haberler +introduction=Giriş +privacyPolicy=Gizlilik Politikası +agree=Katılıyorum +disagree=Katılmıyorum +directories=Dizinler +logFile=Günlük Dosyası +logFiles=Günlük Dosyaları +logFilesAttachment=Günlük Dosyaları +issueReporter=Sayı Muhabiri +openCurrentLogFile=Günlük dosyaları +openCurrentLogFileDescription=Geçerli oturumun günlük dosyasını açın +openLogsDirectory=Günlükler dizinini açın +installationFiles=Kurulum Dosyaları +openInstallationDirectory=Kurulum dosyaları +openInstallationDirectoryDescription=XPipe kurulum dizinini açın +launchDebugMode=Hata ayıklama modu +launchDebugModeDescription=XPipe'ı hata ayıklama modunda yeniden başlatın +extensionInstallTitle=İndir +extensionInstallDescription=Bu eylem XPipe tarafından dağıtılmayan ek üçüncü taraf kütüphaneleri gerektirir. Bunları buradan otomatik olarak yükleyebilirsiniz. Bileşenler daha sonra satıcının web sitesinden indirilir: +extensionInstallLicenseNote=İndirme ve otomatik yükleme işlemini gerçekleştirerek üçüncü taraf lisanslarının koşullarını kabul etmiş olursunuz: +license=Lisans +installRequired=Kurulum Gerekli +restore=Geri Yükleme +restoreAllSessions=Tüm oturumları geri yükle +connectionTimeout=Bağlantı başlatma zaman aşımı +connectionTimeoutDescription=Bir bağlantının zaman aşımına uğradığını düşünmeden önce yanıt için beklenecek saniye cinsinden süre. Uzak sistemlerinizden bazılarının bağlanması uzun sürüyorsa, bu değeri artırmayı deneyebilirsiniz. +useBundledTools=Birlikte verilen OpenSSH araçlarını kullanma +useBundledToolsDescription=Yerel olarak yüklediğiniz openssh istemcisi yerine paketlenmiş sürümünü kullanmayı tercih edin.\n\nBu sürüm genellikle sisteminizde yüklü olandan daha günceldir ve ek özellikleri destekleyebilir. Bu aynı zamanda bu araçların ilk etapta yüklü olması gerekliliğini de ortadan kaldırır.\n\nUygulamak için yeniden başlatma gerekir. +appearance=Görünüş +integrations=Entegrasyonlar +uiOptions=Kullanıcı Arayüzü Seçenekleri +theme=Tema +rdp=Uzak masaüstü +rdpConfiguration=Uzak masaüstü yapılandırması +rdpClient=RDP istemcisi +rdpClientDescription=RDP bağlantıları başlatılırken çağrılacak RDP istemci programı.\n\nÇeşitli istemcilerin farklı derecelerde yeteneklere ve entegrasyonlara sahip olduğunu unutmayın. Bazı istemciler parolaların otomatik olarak aktarılmasını desteklemez, bu nedenle bunları başlatırken doldurmanız gerekir. +localShell=Yerel kabuk +themeDescription=Tercih ettiğiniz ekran teması +dontAutomaticallyStartVmSshServer=Gerektiğinde VM'ler için SSH sunucusunu otomatik olarak başlatma +dontAutomaticallyStartVmSshServerDescription=Bir hipervizörde çalışan bir sanal makineye herhangi bir kabuk bağlantısı SSH aracılığıyla yapılır. XPipe gerektiğinde kurulu SSH sunucusunu otomatik olarak başlatabilir. Güvenlik nedeniyle bunu istemiyorsanız, bu seçenekle bu davranışı devre dışı bırakabilirsiniz. +confirmGitShareTitle=Git paylaşımını onayla +confirmGitShareHeader=Bu, dosyayı git kasanıza kopyalayacak ve değişikliklerinizi işleyecektir. Devam etmek istiyor musunuz? +gitShareFileTooltip=Dosyayı git vault veri dizinine ekleyin, böylece otomatik olarak senkronize edilir.\n\nBu eylem yalnızca ayarlarda git vault etkinleştirildiğinde kullanılabilir. +performanceMode=Performans modu +performanceModeDescription=Uygulama performansını artırmak için gerekli olmayan tüm görsel efektleri devre dışı bırakır. +dontAcceptNewHostKeys=Yeni SSH ana bilgisayar anahtarlarını otomatik olarak kabul etme +dontAcceptNewHostKeysDescription=XPipe, SSH istemcinizin bilinen bir ana bilgisayar anahtarı kaydetmediği sistemlerden ana bilgisayar anahtarlarını varsayılan olarak otomatik olarak kabul edecektir. Ancak bilinen herhangi bir ana bilgisayar anahtarı değişmişse, yenisini kabul etmediğiniz sürece bağlanmayı reddedecektir.\n\nBu davranışın devre dışı bırakılması, başlangıçta herhangi bir çakışma olmasa bile tüm ana bilgisayar anahtarlarını kontrol etmenizi sağlar. +uiScale=UI Ölçeği +uiScaleDescription=Sistem genelindeki ekran ölçeğinizden bağımsız olarak ayarlanabilen özel bir ölçeklendirme değeri. Değerler yüzde cinsindendir, bu nedenle örneğin 150 değeri %150'lik bir UI ölçeği ile sonuçlanacaktır.\n\nUygulamak için yeniden başlatma gerekir. +editorProgram=Editör Programı +editorProgramDescription=Her türlü metin verisini düzenlerken kullanılacak varsayılan metin düzenleyicisi. +windowOpacity=Pencere opaklığı +windowOpacityDescription=Arka planda neler olduğunu takip etmek için pencere opaklığını değiştirir. +useSystemFont=Sistem yazı tipini kullan +openDataDir=Kasa veri dizini +openDataDirButton=Açık veri dizini +openDataDirDescription=SSH anahtarları gibi ek dosyaları git deponuzla sistemler arasında senkronize etmek istiyorsanız, bunları depolama veri dizinine koyabilirsiniz. Burada referans verilen tüm dosyaların dosya yolları, senkronize edilen herhangi bir sistemde otomatik olarak uyarlanacaktır. +updates=Güncellemeler +passwordKey=Şifre anahtarı +selectAll=Tümünü seçin +command=Komuta +advanced=Gelişmiş +thirdParty=Açık kaynak bildirimleri +eulaDescription=XPipe uygulaması için Son Kullanıcı Lisans Sözleşmesini okuyun +thirdPartyDescription=Üçüncü taraf kütüphanelerin açık kaynak lisanslarını görüntüleyin +workspaceLock=Ana parola +enableGitStorage=Git senkronizasyonunu etkinleştir +sharing=Paylaşım +sync=Senkronizasyon +enableGitStorageDescription=Etkinleştirildiğinde, XPipe bağlantı veri deposu için bir git deposu başlatır ve değişiklikleri bu depoya işler. Bunun için git'in yüklü olması gerektiğini ve yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın.\n\nSenkronize edilmesi gereken tüm kategoriler açıkça paylaşılan olarak belirlenmelidir.\n\nUygulamak için yeniden başlatma gerekir. +storageGitRemote=Git uzak URL'si +storageGitRemoteDescription=Ayarlandığında, XPipe yükleme sırasında tüm değişiklikleri otomatik olarak çekecek ve kaydetme sırasında tüm değişiklikleri uzak depoya itecektir.\n\nBu, yapılandırma verilerinizi birden fazla XPipe kurulumu arasında paylaşmanıza olanak tanır. Hem HTTP hem de SSH URL'leri desteklenir. Bunun yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın.\n\nUygulamak için yeniden başlatma gerekir. +vault=Kasa +workspaceLockDescription=XPipe'da saklanan hassas bilgileri şifrelemek için özel bir parola belirler.\n\nBu, depolanan hassas bilgileriniz için ek bir şifreleme katmanı sağladığından daha fazla güvenlikle sonuçlanır. Daha sonra XPipe başlatıldığında şifreyi girmeniz istenecektir. +useSystemFontDescription=Sistem fontunuzun mu yoksa XPipe ile birlikte gelen Roboto fontunun mu kullanılacağını kontrol eder. +tooltipDelay=Araç ipucu gecikmesi +tooltipDelayDescription=Bir araç ipucu görüntülenene kadar beklenecek milisaniye miktarı. +fontSize=Yazı tipi boyutu +windowOptions=Pencere Seçenekleri +saveWindowLocation=Pencere konumunu kaydet +saveWindowLocationDescription=Pencere koordinatlarının kaydedilip kaydedilmeyeceğini ve yeniden başlatmalarda geri yüklenip yüklenmeyeceğini kontrol eder. +startupShutdown=Başlatma / Kapatma +showChildCategoriesInParentCategory=Üst kategoride alt kategorileri göster +showChildCategoriesInParentCategoryDescription=Belirli bir üst kategori seçildiğinde alt kategorilerde bulunan tüm bağlantıların dahil edilip edilmeyeceği.\n\nBu devre dışı bırakılırsa kategoriler, alt klasörleri dahil etmeden yalnızca doğrudan içeriklerini gösteren klasik klasörler gibi davranır. +condenseConnectionDisplay=Yoğunlaştırılmış bağlantı ekranı +condenseConnectionDisplayDescription=Daha yoğun bir bağlantı listesi elde etmek için her üst düzey bağlantının daha az dikey alan kaplamasını sağlayın. +enforceWindowModality=Pencere modalitesini uygulayın +enforceWindowModalityDescription=Bağlantı oluşturma iletişim kutusu gibi ikincil pencerelerin açıkken ana pencere için tüm girdileri engellemesini sağlar. Bu, bazen yanlış tıkladığınızda kullanışlıdır. +openConnectionSearchWindowOnConnectionCreation=Bağlantı oluşturma sırasında bağlantı arama penceresini açma +openConnectionSearchWindowOnConnectionCreationDescription=Yeni bir kabuk bağlantısı eklendiğinde mevcut alt bağlantıları aramak için pencerenin otomatik olarak açılıp açılmayacağı. +workflow=İş akışı +system=Sistem +application=Uygulama +storage=Depolama +runOnStartup=Başlangıçta çalıştır +closeBehaviour=Yakın davranış +closeBehaviourDescription=XPipe'ın ana penceresini kapattıktan sonra nasıl devam edeceğini kontrol eder. +language=Dil +languageDescription=Kullanılacak ekran dili.\n\nBunların temel olarak otomatik çevirileri kullandığını ve katkıda bulunanlar tarafından manuel olarak düzeltildiğini ve geliştirildiğini unutmayın. Ayrıca GitHub'da çeviri düzeltmeleri göndererek çeviri çabalarına yardımcı olabilirsiniz. +lightTheme=Işık Teması +darkTheme=Koyu Tema +exit=XPipe'tan çıkın +continueInBackground=Arka planda devam et +minimizeToTray=Tepsiye küçült +closeBehaviourAlertTitle=Kapanış davranışını ayarlama +closeBehaviourAlertTitleHeader=Pencere kapatılırken ne olması gerektiğini seçin. Uygulama kapatıldığında tüm etkin bağlantılar kapatılacaktır. +startupBehaviour=Başlangıç davranışı +startupBehaviourDescription=XPipe başlatıldığında masaüstü uygulamasının varsayılan davranışını kontrol eder. +clearCachesAlertTitle=Önbelleği Temizle +clearCachesAlertTitleHeader=Tüm XPipe önbelleklerini temizlemek istiyor musunuz? +clearCachesAlertTitleContent=Bunun, kullanıcı deneyimini iyileştirmek için depolanan tüm verileri sileceğini unutmayın. +startGui=GUI'yi Başlat +startInTray=Tepside başlat +startInBackground=Arka planda başlat +clearCaches=Önbellekleri temizle ... +clearCachesDescription=Tüm önbellek verilerini sil +apply=Başvurmak +cancel=İptal +notAnAbsolutePath=Mutlak bir yol değil +notADirectory=Dizin değil +notAnEmptyDirectory=Boş bir dizin değil +automaticallyUpdate=Güncellemeleri kontrol edin +automaticallyUpdateDescription=Etkinleştirildiğinde, XPipe çalışırken yeni sürüm bilgileri otomatik olarak alınır. Arka planda hiçbir güncelleyici çalışmaz ve yine de herhangi bir güncelleme yüklemesini açıkça onaylamanız gerekir. +sendAnonymousErrorReports=Anonim hata raporları gönderin +sendUsageStatistics=Anonim kullanım istatistikleri gönderin +storageDirectory=Depolama dizini +storageDirectoryDescription=XPipe'ın tüm bağlantı bilgilerini saklaması gereken konum. Bu ayar yalnızca bir sonraki yeniden başlatmada uygulanacaktır. Bunu değiştirirken, eski dizindeki veriler yenisine kopyalanmaz. +logLevel=Günlük seviyesi +appBehaviour=Uygulama davranışı +logLevelDescription=Günlük dosyaları yazılırken kullanılması gereken günlük düzeyi. +developerMode=Geliştirici modu +developerModeDescription=Etkinleştirildiğinde, geliştirme için yararlı olan çeşitli ek seçeneklere erişebilirsiniz. Yalnızca yeniden başlatmadan sonra etkindir. +editor=Editör +custom=Özel +passwordManagerCommand=Parola yöneticisi komutu +passwordManagerCommandDescription=Parolaları almak için çalıştırılacak komut. Yer tutucu dize $KEY, çağrıldığında alıntılanan parola anahtarıyla değiştirilecektir. Bu, parolayı stdout'a yazdırmak için parola yöneticinizin CLI'sini çağırmalıdır, örneğin mypassmgr get $KEY.\n\nDaha sonra anahtarı, parola gerektiren bir bağlantı kurduğunuzda alınacak şekilde ayarlayabilirsiniz. +passwordManagerCommandTest=Parola yöneticisini test edin +passwordManagerCommandTestDescription=Bir parola yöneticisi komutu kurduysanız çıktının doğru görünüp görünmediğini burada test edebilirsiniz. Komut yalnızca parolanın kendisini stdout'a çıktılamalıdır, çıktıya başka hiçbir biçimlendirme dahil edilmemelidir. +preferEditorTabs=Yeni sekmeler açmayı tercih edin +preferEditorTabsDescription=XPipe'ın yeni pencereler yerine seçtiğiniz düzenleyicide yeni sekmeler açmayı deneyip denemeyeceğini kontrol eder.\n\nHer düzenleyicinin bunu desteklemediğini unutmayın. +customRdpClientCommand=Özel komut +customRdpClientCommandDescription=Özel RDP istemcisini başlatmak için yürütülecek komut.\n\nYer tutucu dize $FILE, çağrıldığında tırnak içine alınmış mutlak .rdp dosya adıyla değiştirilecektir. Boşluk içeriyorsa çalıştırılabilir yolunuzu tırnak içine almayı unutmayın. +customEditorCommand=Özel düzenleyici komutu +customEditorCommandDescription=Özel düzenleyiciyi başlatmak için yürütülecek komut.\n\nYer tutucu dize $FILE, çağrıldığında alıntılanan mutlak dosya adıyla değiştirilecektir. Boşluk içeriyorsa düzenleyicinizin çalıştırılabilir yolunu tırnak içine almayı unutmayın. +editorReloadTimeout=Editör yeniden yükleme zaman aşımı +editorReloadTimeoutDescription=Güncellendikten sonra bir dosyayı okumadan önce beklenecek milisaniye miktarı. Bu, düzenleyicinizin dosya kilitlerini yazma veya serbest bırakma konusunda yavaş olduğu durumlarda sorunları önler. +encryptAllVaultData=Tüm kasa verilerini şifreleyin +encryptAllVaultDataDescription=Etkinleştirildiğinde, kasa bağlantı verilerinin her parçası, yalnızca bu verilerdeki gizli bilgilerin aksine şifrelenecektir. Bu, kasada varsayılan olarak şifrelenmeyen kullanıcı adları, ana bilgisayar adları vb. gibi diğer parametreler için başka bir güvenlik katmanı ekler.\n\nBu seçenek git vault geçmişinizi ve farklarınızı işe yaramaz hale getirecektir çünkü artık orijinal değişiklikleri göremezsiniz, sadece ikili değişiklikleri görebilirsiniz. +vaultSecurity=Kasa güvenliği +developerDisableUpdateVersionCheck=Güncelleme Sürüm Denetimini Devre Dışı Bırak +developerDisableUpdateVersionCheckDescription=Güncelleme denetleyicisinin bir güncelleme ararken sürüm numarasını göz ardı edip etmeyeceğini denetler. +developerDisableGuiRestrictions=GUI kısıtlamalarını devre dışı bırakma +developerDisableGuiRestrictionsDescription=Devre dışı bırakılan bazı eylemlerin kullanıcı arayüzünden yürütülmeye devam edip edemeyeceğini kontrol eder. +developerShowHiddenEntries=Gizli girişleri göster +developerShowHiddenEntriesDescription=Etkinleştirildiğinde, gizli ve dahili veri kaynakları gösterilecektir. +developerShowHiddenProviders=Gizli sağlayıcıları göster +developerShowHiddenProvidersDescription=Gizli ve dahili bağlantı ve veri kaynağı sağlayıcılarının oluşturma diyalog penceresinde gösterilip gösterilmeyeceğini kontrol eder. +developerDisableConnectorInstallationVersionCheck=Konektör Sürüm Kontrolünü Devre Dışı Bırak +developerDisableConnectorInstallationVersionCheckDescription=Güncelleme denetleyicisinin uzak makinede yüklü bir XPipe bağlayıcısının sürümünü incelerken sürüm numarasını göz ardı edip etmeyeceğini kontrol eder. +shellCommandTest=Kabuk Komut Testi +shellCommandTestDescription=XPipe tarafından dahili olarak kullanılan kabuk oturumunda bir komut çalıştırın. +terminal=Terminal +terminalEmulator=Terminal emülatörü +terminalConfiguration=Terminal yapılandırması +editorConfiguration=Editör yapılandırması +defaultApplication=Varsayılan uygulama +terminalEmulatorDescription=Herhangi bir kabuk bağlantısı açarken kullanılacak varsayılan terminal. Bu uygulama sadece görüntüleme amacıyla kullanılır, başlatılan kabuk programı kabuk bağlantısının kendisine bağlıdır.\n\nÖzellik desteğinin seviyesi terminale göre değişir, bu yüzden her biri önerilen veya önerilmeyen olarak işaretlenmiştir. Tüm önerilmeyen terminaller XPipe ile çalışır ancak sekmeler, başlık renkleri, kabuk desteği ve daha fazlası gibi özelliklerden yoksun olabilir. Önerilen bir terminal kullandığınızda kullanıcı deneyiminiz en iyi olacaktır. +program=Program +customTerminalCommand=Özel terminal komutu +customTerminalCommandDescription=Özel terminali belirli bir komutla açmak için çalıştırılacak komut.\n\nXPipe, terminalinizin çalıştırması için geçici bir başlatıcı kabuk betiği oluşturacaktır. Verdiğiniz komuttaki $CMD yer tutucu dizesi, çağrıldığında gerçek başlatıcı betiği ile değiştirilecektir. Terminal çalıştırılabilir yolunuz boşluk içeriyorsa alıntı yapmayı unutmayın. +clearTerminalOnInit=Başlangıçta terminali temizle +clearTerminalOnInitDescription=Etkinleştirildiğinde, XPipe gereksiz çıktıları kaldırmak için yeni bir terminal oturumu başlatıldığında bir clear komutu çalıştırır. +enableFastTerminalStartup=Hızlı terminal başlatmayı etkinleştirme +enableFastTerminalStartupDescription=Etkinleştirildiğinde, terminal oturumları mümkün olduğunda daha hızlı başlatılmaya çalışılır.\n\nBu, birkaç başlangıç kontrolünü atlayacak ve görüntülenen sistem bilgilerini güncellemeyecektir. Herhangi bir bağlantı hatası sadece terminalde gösterilecektir. +dontCachePasswords=İstenen parolaları önbelleğe almayın +dontCachePasswordsDescription=Sorgulanan parolaların XPipe tarafından dahili olarak önbelleğe alınıp alınmayacağını kontrol eder, böylece geçerli oturumda bunları tekrar girmeniz gerekmez.\n\nBu davranış devre dışı bırakılırsa, sistem tarafından her istendiğinde istenen kimlik bilgilerini yeniden girmeniz gerekir. +denyTempScriptCreation=Geçici komut dosyası oluşturmayı reddetme +denyTempScriptCreationDescription=XPipe, bazı işlevlerini gerçekleştirmek için bazen basit komutların kolayca yürütülmesini sağlamak üzere hedef sistemde geçici kabuk komut dosyaları oluşturur. Bunlar herhangi bir hassas bilgi içermez ve sadece uygulama amacıyla oluşturulur.\n\nBu davranış devre dışı bırakılırsa, XPipe uzak bir sistemde herhangi bir geçici dosya oluşturmaz. Bu seçenek, her dosya sistemi değişikliğinin izlendiği yüksek güvenlikli bağlamlarda kullanışlıdır. Bu devre dışı bırakılırsa, kabuk ortamları ve komut dosyaları gibi bazı işlevler amaçlandığı gibi çalışmayacaktır. +disableCertutilUse=Windows'ta certutil kullanımını devre dışı bırakma +useLocalFallbackShell=Yerel yedek kabuk kullan +useLocalFallbackShellDescription=Yerel işlemleri gerçekleştirmek için başka bir yerel kabuk kullanmaya geçin. Bu, Windows'ta PowerShell ve diğer sistemlerde bourne shell olabilir.\n\nBu seçenek, normal yerel varsayılan kabuğun devre dışı bırakılması veya bir dereceye kadar bozulması durumunda kullanılabilir. Bu seçenek etkinleştirildiğinde bazı özellikler beklendiği gibi çalışmayabilir.\n\nUygulamak için yeniden başlatma gerekir. +disableCertutilUseDescription=Cmd.exe'deki çeşitli eksiklikler ve hatalar nedeniyle, geçici kabuk betikleri certutil ile oluşturulur ve cmd.exe ASCII olmayan girdilerde bozulduğu için base64 girdisinin kodunu çözmek için kullanılır. XPipe bunun için PowerShell de kullanabilir ancak bu daha yavaş olacaktır.\n\nBu, bazı işlevleri gerçekleştirmek ve bunun yerine PowerShell'e geri dönmek için Windows sistemlerinde herhangi bir certutil kullanımını devre dışı bırakır. Bu, bazıları certutil kullanımını engellediği için bazı AV'leri memnun edebilir. +disableTerminalRemotePasswordPreparation=Terminal uzaktan parola hazırlamayı devre dışı bırakma +disableTerminalRemotePasswordPreparationDescription=Terminalde birden fazla ara sistemden geçen bir uzak kabuk bağlantısının kurulması gereken durumlarda, herhangi bir sorgunun otomatik olarak doldurulmasına izin vermek için ara sistemlerden birinde gerekli parolaların hazırlanması gerekebilir.\n\nParolaların herhangi bir ara sisteme aktarılmasını istemiyorsanız, bu davranışı devre dışı bırakabilirsiniz. Gerekli herhangi bir ara parola daha sonra açıldığında terminalin kendisinde sorgulanacaktır. +more=Daha fazla +translate=Çeviriler +allConnections=Tüm bağlantılar +allScripts=Tüm senaryolar +predefined=Önceden tanımlı +default=Varsayılan +goodMorning=Günaydın +goodAfternoon=İyi günler +goodEvening=İyi akşamlar +addVisual=Görsel ... +ssh=SSH +sshConfiguration=SSH Yapılandırması +size=Boyut +attributes=Nitelikler +modified=Değiştirilmiş +isOnlySupported=yalnızca profesyonel lisans ile desteklenir +areOnlySupported=yalnızca profesyonel lisans ile desteklenir +updateReadyTitle=$VERSION$ için güncelleme hazır diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties new file mode 100644 index 000000000..23075f2cd --- /dev/null +++ b/lang/app/strings/translations_zh.properties @@ -0,0 +1,426 @@ +delete=删除 +rename=重命名 +properties=属性 +usedDate=已使用$DATE$ +openDir=开放目录 +sortLastUsed=按最后使用日期排序 +sortAlphabetical=按名称字母排序 +restart=重新启动 XPipe +restartDescription=重新启动通常可以快速解决问题 +reportIssue=报告问题 +reportIssueDescription=打开综合问题报告程序 +usefulActions=实用操作 +stored=保存 +troubleshootingOptions=故障排除工具 +troubleshoot=故障排除 +remote=远程文件 +addShellStore=添加外壳 ... +addShellTitle=添加外壳连接 +savedConnections=保存的连接 +save=保存 +clean=清洁 +refresh=刷新 +moveTo=移动到 ... +addDatabase=数据库 ... +browseInternalStorage=浏览内部存储 +addTunnel=隧道 ... +addScript=脚本 ... +addHost=远程主机 ... +addShell=外壳环境 ... +addCommand=自定义命令 ... +addAutomatically=自动搜索 ... +addOther=添加其他 ... +addConnection=添加连接 +skip=跳过 +addConnections=新 +selectType=选择类型 +selectTypeDescription=选择连接类型 +selectShellType=外壳类型 +selectShellTypeDescription=选择外壳连接类型 +name=名称 +storeIntroTitle=连接枢纽 +storeIntroDescription=您可以在这里集中管理所有本地和远程 shell 连接。开始时,您可以快速自动检测可用连接,并选择要添加的连接。 +detectConnections=搜索连接 +configuration=配置 +dragAndDropFilesHere=或直接将文件拖放到此处 +confirmDsCreationAbortTitle=确认中止 +confirmDsCreationAbortHeader=您想放弃创建数据源吗? +confirmDsCreationAbortContent=任何数据源创建进度都将丢失。 +confirmInvalidStoreTitle=连接失败 +confirmInvalidStoreHeader=您想跳过连接验证吗? +confirmInvalidStoreContent=即使无法验证,也可以添加此连接,稍后再修复连接问题。 +none=无 +expand=展开 +accessSubConnections=访问子连接 +common=常见 +color=颜色 +alwaysConfirmElevation=始终确认权限提升 +alwaysConfirmElevationDescription=控制如何处理在系统上运行命令(如使用 sudo)需要提升权限的情况。\n\n默认情况下,任何 sudo 凭证都会在会话期间缓存,并在需要时自动提供。如果启用此选项,则每次都会要求您确认提升权限。 +allow=允许 +ask=询问 +deny=拒绝 +share=添加到 git 仓库 +unshare=从 git 仓库删除 +remove=删除 +newCategory=新子类别 +passwordManager=密码管理器 +prompt=提示 +customCommand=自定义命令 +other=其他 +setLock=设置锁定 +selectConnection=选择连接 +changeLock=更改密码 +test=测试 +lockCreationAlertTitle=设置口令 +lockCreationAlertHeader=设置新的主密码 +finish=完成 +error=发生错误 +downloadStageDescription=将文件下载到本地计算机,以便拖放到本地桌面环境中。 +ok=好的 +search=搜索 +newFile=新文件 +newDirectory=新目录 +passphrase=密码 +repeatPassphrase=重复口令 +password=密码 +unlockAlertTitle=解锁工作区 +unlockAlertHeader=输入保险库密码以继续 +enterLockPassword=输入锁密码 +repeatPassword=重复密码 +askpassAlertTitle=询问密码 +unsupportedOperation=不支持的操作:$MSG$ +fileConflictAlertTitle=解决冲突 +fileConflictAlertHeader=遇到冲突。您想如何继续? +fileConflictAlertContent=目标系统中已存在文件$FILE$ 。 +fileConflictAlertContentMultiple=文件$FILE$ 已经存在。可能还有更多冲突,您可以选择一个适用于所有冲突的选项来自动解决。 +moveAlertTitle=确认移动 +moveAlertHeader=您想将 ($COUNT$) 选定的元素移动到$TARGET$ 吗? +deleteAlertTitle=确认删除 +deleteAlertHeader=您想删除 ($COUNT$) 选定的元素吗? +selectedElements=选定要素: +mustNotBeEmpty=$VALUE$ 不得为空 +valueMustNotBeEmpty=值不得为空 +transferDescription=下拉传输文件 +dragFiles=在浏览器中拖动文件 +dragLocalFiles=从此处拖动本地文件 +null=$VALUE$ 必须为非空 +roots=根 +scripts=脚本 +searchFilter=搜索 ... +recent=最近使用 +shortcut=快捷方式 +browserWelcomeEmpty=在这里,您可以看到上次离开的位置。 +browserWelcomeSystems=您最近连接了以下系统: +hostFeatureUnsupported=$FEATURE$ 主机上未安装 +missingStore=$NAME$ 不存在 +connectionName=连接名称 +connectionNameDescription=为该连接自定义名称 +openFileTitle=打开文件 +unknown=未知 +scanAlertTitle=添加连接 +scanAlertChoiceHeader=目标 +scanAlertChoiceHeaderDescription=选择搜索连接的位置。这将首先查找所有可用的连接。 +scanAlertHeader=连接类型 +scanAlertHeaderDescription=选择要为系统自动添加的连接类型。 +noInformationAvailable=无可用信息 +localMachine=本地机器 +yes=是 +no=无 +errorOccured=发生错误 +terminalErrorOccured=出现终端错误 +errorTypeOccured=抛出了$TYPE$ 类型的异常 +permissionsAlertTitle=所需权限 +permissionsAlertHeader=执行此操作需要额外权限。 +permissionsAlertContent=请根据弹出窗口在设置菜单中为 XPipe 赋予所需的权限。 +errorDetails=显示详细信息 +updateReadyAlertTitle=更新就绪 +updateReadyAlertHeader=$VERSION$ 版本的更新已准备就绪,可以安装 +updateReadyAlertContent=这将安装新版本,并在安装完成后重新启动 XPipe。 +errorNoDetail=无错误详细信息 +updateAvailableTitle=可更新 +updateAvailableHeader=可安装 XPipe 更新至$VERSION$ 版本 +updateAvailableContent=即使 XPipe 无法启动,您也可以尝试安装更新来修复该问题。 +clipboardActionDetectedTitle=检测到剪贴板操作 +clipboardActionDetectedHeader=您想导入剪贴板内容吗? +clipboardActionDetectedContent=XPipe 在剪贴板中检测到可打开的内容。现在要打开吗? +install=安装 ... +ignore=忽略 +possibleActions=可能的操作 +reportError=报告错误 +reportOnGithub=在 GitHub 上创建问题报告 +reportOnGithubDescription=在 GitHub 仓库中打开一个新问题 +reportErrorDescription=发送包含可选用户反馈和诊断信息的错误报告 +ignoreError=忽略错误 +ignoreErrorDescription=忽略此错误,若无其事地继续运行 +provideEmail=如何与您联系(非必填项,仅在您希望收到修复通知时使用) +additionalErrorInfo=提供补充信息(可选) +additionalErrorAttachments=选择附件(可选) +dataHandlingPolicies=隐私政策 +sendReport=发送报告 +errorHandler=错误处理程序 +events=活动 +method=方法 +validate=验证 +stackTrace=堆栈跟踪 +previousStep=< 上一页 +nextStep=下一页 > +finishStep=完成 +edit=编辑 +browseInternal=内部浏览 +checkOutUpdate=签出更新 +open=打开 +quit=退出 +noTerminalSet=没有自动设置终端应用程序。您可以在设置菜单中手动设置。 +connections=连接 +settings=设置 +explorePlans=许可证 +help=帮助 +about=关于 +developer=开发人员 +browseFileTitle=浏览文件 +browse=浏览 +browser=浏览器 +selectFileFromComputer=从本计算机中选择文件 +links=实用链接 +website=网站 +documentation=文档 +discordDescription=加入 Discord 服务器 +security=安全性 +securityPolicy=安全信息 +securityPolicyDescription=阅读详细的安全策略 +privacy=隐私政策 +privacyDescription=阅读 XPipe 应用程序的隐私政策 +slackDescription=加入 Slack 工作区 +support=支持 +githubDescription=查看 GitHub 仓库 +openSourceNotices=开源通知 +xPipeClient=XPipe 桌面 +checkForUpdates=检查更新 +checkForUpdatesDescription=下载更新(如果有的话 +lastChecked=最后检查 +version=版本 +build=构建版本 +runtimeVersion=运行时版本 +virtualMachine=虚拟机 +updateReady=安装更新 +updateReadyPortable=签出更新 +updateReadyDescription=已下载更新并准备安装 +updateReadyDescriptionPortable=可下载更新 +updateRestart=重新启动更新 +never=从不 +updateAvailableTooltip=可更新 +visitGithubRepository=访问 GitHub 仓库 +updateAvailable=可更新:$VERSION$ +downloadUpdate=下载更新 +legalAccept=我接受最终用户许可协议 +confirm=确认 +print=打印 +whatsNew=$VERSION$ ($DATE$) 中的新功能 +antivirusNoticeTitle=关于杀毒软件的说明 +updateChangelogAlertTitle=更新日志 +greetingsAlertTitle=欢迎访问 XPipe +gotIt=明白了 +eula=最终用户许可协议 +news=新闻 +introduction=简介 +privacyPolicy=隐私政策 +agree=同意 +disagree=不同意 +directories=目录 +logFile=日志文件 +logFiles=日志文件 +logFilesAttachment=日志文件 +issueReporter=问题报告器 +openCurrentLogFile=日志文件 +openCurrentLogFileDescription=打开当前会话的日志文件 +openLogsDirectory=打开日志目录 +installationFiles=安装文件 +openInstallationDirectory=安装文件 +openInstallationDirectoryDescription=打开 XPipe 安装目录 +launchDebugMode=调试模式 +launchDebugModeDescription=在调试模式下重新启动 XPipe +extensionInstallTitle=下载 +extensionInstallDescription=该操作需要额外的第三方库,但 XPipe 未分发这些库。您可以在此处自动安装。然后从供应商网站下载组件: +extensionInstallLicenseNote=进行下载和自动安装即表示您同意第三方许可条款: +license=许可证 +installRequired=安装要求 +restore=恢复 +restoreAllSessions=恢复所有会话 +connectionTimeout=连接启动超时 +connectionTimeoutDescription=连接超时前等待响应的时间(秒)。如果某些远程系统的连接时间较长,可以尝试增加此值。 +useBundledTools=使用捆绑的 OpenSSH 工具 +useBundledToolsDescription=优先使用捆绑版本的 openssh 客户端,而不是本地安装的客户端。\n\n该版本通常比系统中安装的版本更新,并可能支持更多功能。这也消除了首先安装这些工具的要求。\n\n需要重新启动才能应用。 +appearance=外观 +integrations=集成 +uiOptions=用户界面选项 +theme=主题 +rdp=远程桌面 +rdpConfiguration=远程桌面配置 +rdpClient=RDP 客户端 +rdpClientDescription=启动 RDP 连接时调用的 RDP 客户端程序。\n\n请注意,各种客户端具有不同程度的能力和集成。有些客户端不支持自动传递密码,因此仍需在启动时填写。 +localShell=本地外壳 +themeDescription=您首选的显示主题 +dontAutomaticallyStartVmSshServer=需要时不自动为虚拟机启动 SSH 服务器 +dontAutomaticallyStartVmSshServerDescription=与在管理程序中运行的虚拟机的任何 shell 连接都是通过 SSH 进行的。XPipe可在需要时自动启动已安装的SSH服务器。如果出于安全原因不希望这样做,则可以通过此选项禁用此行为。 +confirmGitShareTitle=确认 git 共享 +confirmGitShareHeader=这将把文件复制到您的 git 目录,并提交您的修改。要继续吗? +gitShareFileTooltip=将文件添加到 git vault 数据目录,使其自动同步。\n\n此操作只有在设置中启用 git vault 后才能使用。 +performanceMode=性能模式 +performanceModeDescription=禁用所有不需要的视觉效果,以提高应用程序性能。 +dontAcceptNewHostKeys=不自动接受新的 SSH 主机密钥 +dontAcceptNewHostKeysDescription=如果 SSH 客户端没有保存已知主机密钥,XPipe 默认会自动接受来自系统的主机密钥。但是,如果任何已知主机密钥发生变化,除非您接受新密钥,否则它将拒绝连接。\n\n禁用该行为可让您检查所有主机密钥,即使最初没有冲突。 +uiScale=用户界面比例 +uiScaleDescription=自定义缩放值,可独立于系统范围内的显示比例进行设置。数值以百分比为单位,例如,数值为 150 时,用户界面的缩放比例为 150%。\n\n需要重新启动才能应用。 +editorProgram=编辑程序 +editorProgramDescription=编辑任何文本数据时使用的默认文本编辑器。 +windowOpacity=窗口不透明度 +windowOpacityDescription=改变窗口的不透明度,以跟踪后台正在发生的事情。 +useSystemFont=使用系统字体 +openDataDir=保险库数据目录 +openDataDirButton=开放数据目录 +openDataDirDescription=如果你想同步其他文件,比如 SSH 密钥,可以把它们放到存储数据目录中。任何在该目录中引用的文件,其文件路径都会在任何同步的系统上自动调整。 +updates=更新 +passwordKey=密码匙 +selectAll=全部选择 +command=指令 +advanced=高级 +thirdParty=开放源代码通知 +eulaDescription=阅读 XPipe 应用程序的最终用户许可协议 +thirdPartyDescription=查看第三方库的开源许可证 +workspaceLock=主密码 +enableGitStorage=启用 git 同步 +sharing=共享 +sync=同步 +enableGitStorageDescription=启用后,XPipe 将为连接数据存储初始化一个 git 仓库,并将任何更改提交至该仓库。请注意,这需要安装 git,并且可能会降低加载和保存操作的速度。\n\n任何需要同步的类别都必须明确指定为共享类别。\n\n需要重新启动才能应用。 +storageGitRemote=Git 远程 URL +storageGitRemoteDescription=设置后,XPipe 将在加载时自动提取任何更改,并在保存时将任何更改推送到远程资源库。\n\n这样,您就可以在多个 XPipe 安装之间共享配置数据。支持 HTTP 和 SSH URL。请注意,这可能会降低加载和保存操作的速度。\n\n需要重新启动才能应用。 +vault=拱顶 +workspaceLockDescription=设置自定义密码,对存储在 XPipe 中的任何敏感信息进行加密。\n\n这将提高安全性,因为它为您存储的敏感信息提供了额外的加密层。当 XPipe 启动时,系统会提示您输入密码。 +useSystemFontDescription=控制使用系统字体还是 XPipe 附带的 Roboto 字体。 +tooltipDelay=工具提示延迟 +tooltipDelayDescription=等待工具提示显示的毫秒数。 +fontSize=字体大小 +windowOptions=窗口选项 +saveWindowLocation=保存窗口位置 +saveWindowLocationDescription=控制是否保存窗口坐标并在重启时恢复。 +startupShutdown=启动/关闭 +showChildCategoriesInParentCategory=在父类别中显示子类别 +showChildCategoriesInParentCategoryDescription=当选择某个父类别时,是否包括位于子类别中的所有连接。\n\n如果禁用,类别的行为更像传统的文件夹,只显示其直接内容,而不包括子文件夹。 +condenseConnectionDisplay=压缩连接显示 +condenseConnectionDisplayDescription=减少每个顶层连接的垂直空间,使连接列表更简洁。 +enforceWindowModality=执行窗口模式 +enforceWindowModalityDescription=使次窗口(如连接创建对话框)在打开时阻止主窗口的所有输入。如果有时点击错误,这将非常有用。 +openConnectionSearchWindowOnConnectionCreation=创建连接时打开连接搜索窗口 +openConnectionSearchWindowOnConnectionCreationDescription=添加新外壳连接时是否自动打开窗口搜索可用的子连接。 +workflow=工作流程 +system=系统 +application=应用程序 +storage=存储 +runOnStartup=启动时运行 +closeBehaviour=关闭行为 +closeBehaviourDescription=控制 XPipe 关闭主窗口后的运行方式。 +language=语言 +languageDescription=使用的显示语言。\n\n请注意,这些翻译以自动翻译为基础,并由贡献者手动修正和改进。您也可以通过在 GitHub 上提交翻译修正来帮助翻译工作。 +lightTheme=灯光主题 +darkTheme=深色主题 +exit=退出 XPipe +continueInBackground=继续后台 +minimizeToTray=最小化到托盘 +closeBehaviourAlertTitle=设置关闭行为 +closeBehaviourAlertTitleHeader=选择关闭窗口时应发生的情况。关闭程序时,任何活动连接都将被关闭。 +startupBehaviour=启动行为 +startupBehaviourDescription=控制 XPipe 启动时桌面应用程序的默认行为。 +clearCachesAlertTitle=清除缓存 +clearCachesAlertTitleHeader=您想清除所有 XPipe 缓存吗? +clearCachesAlertTitleContent=请注意,这将删除为改善用户体验而存储的所有数据。 +startGui=启动图形用户界面 +startInTray=在托盘中启动 +startInBackground=在后台启动 +clearCaches=清除缓存... +clearCachesDescription=删除所有缓存数据 +apply=应用 +cancel=取消 +notAnAbsolutePath=非绝对路径 +notADirectory=不是目录 +notAnEmptyDirectory=不是空目录 +automaticallyUpdate=检查更新 +automaticallyUpdateDescription=启用后,XPipe 运行时会自动获取新版本信息。没有更新程序在后台运行,您仍需明确确认任何更新安装。 +sendAnonymousErrorReports=发送匿名错误报告 +sendUsageStatistics=发送匿名使用统计数据 +storageDirectory=存储目录 +storageDirectoryDescription=XPipe 存储所有连接信息的位置。该设置只会在下次重启时应用。更改时,旧目录中的数据不会复制到新目录。 +logLevel=日志级别 +appBehaviour=应用程序行为 +logLevelDescription=编写日志文件时应使用的日志级别。 +developerMode=开发人员模式 +developerModeDescription=启用后,您可以访问各种对开发有用的附加选项。仅在重启后激活。 +editor=编辑器 +custom=自定义 +passwordManagerCommand=密码管理器命令 +passwordManagerCommandDescription=为获取密码而执行的命令。在调用时,占位符字符串 $KEY 将被带引号的密码密钥替换。该命令应调用密码管理器 CLI 将密码打印到 stdout,例如:mypassmgr get $KEY。\n\n然后,您就可以设置在建立需要密码的连接时检索密钥。 +passwordManagerCommandTest=测试密码管理器 +passwordManagerCommandTestDescription=如果您设置了密码管理器命令,可以在此测试输出是否正确。该命令只能将密码本身输出到 stdout,输出中不应包含其他格式。 +preferEditorTabs=首选打开新标签页 +preferEditorTabsDescription=控制 XPipe 是否会尝试在您选择的编辑器中打开新标签页,而不是打开新窗口。\n\n请注意,并非每个编辑器都支持这一点。 +customRdpClientCommand=自定义命令 +customRdpClientCommandDescription=启动自定义 RDP 客户端时要执行的命令。\n\n调用时,占位符字符串 $FILE 将被带引号的 .rdp 绝对文件名替换。如果可执行文件路径包含空格,请记住使用引号。 +customEditorCommand=自定义编辑器命令 +customEditorCommandDescription=启动自定义编辑器时要执行的命令。\n\n调用时,占位符字符串 $FILE 将被带引号的绝对文件名替换。如果编辑器的执行路径包含空格,请务必加上引号。 +editorReloadTimeout=编辑器重载超时 +editorReloadTimeoutDescription=文件更新后读取前的等待毫秒数。这样可以避免编辑器在写入或释放文件锁时出现问题。 +encryptAllVaultData=加密所有保险库数据 +encryptAllVaultDataDescription=启用后,保险库连接数据的每个部分都将加密,而不是仅对数据中的秘密进行加密。这为其他参数(如用户名、主机名等)增加了一层安全保护,因为这些参数在保险库中默认情况下是不加密的。\n\n此选项会导致 git 仓库历史记录和差异文件失效,因为您再也看不到原始变更,只能看到二进制变更。 +vaultSecurity=保险库安全 +developerDisableUpdateVersionCheck=禁用更新版本检查 +developerDisableUpdateVersionCheckDescription=控制更新检查程序在查找更新时是否忽略版本号。 +developerDisableGuiRestrictions=禁用图形用户界面限制 +developerDisableGuiRestrictionsDescription=控制某些已禁用的操作是否仍可在用户界面上执行。 +developerShowHiddenEntries=显示隐藏条目 +developerShowHiddenEntriesDescription=启用后,将显示隐藏数据源和内部数据源。 +developerShowHiddenProviders=显示隐藏的提供商 +developerShowHiddenProvidersDescription=控制是否在创建对话框中显示隐藏的内部连接和数据源提供程序。 +developerDisableConnectorInstallationVersionCheck=禁用连接器版本检查 +developerDisableConnectorInstallationVersionCheckDescription=控制更新检查程序在检查远程计算机上安装的 XPipe 连接器的版本时是否忽略版本号。 +shellCommandTest=外壳命令测试 +shellCommandTestDescription=在 XPipe 内部使用的 shell 会话中运行命令。 +terminal=终端 +terminalEmulator=终端仿真器 +terminalConfiguration=终端配置 +editorConfiguration=编辑器配置 +defaultApplication=默认应用程序 +terminalEmulatorDescription=打开任何 shell 连接时使用的默认终端。该程序仅用于显示目的,启动的 shell 程序取决于 shell 连接本身。\n\n不同终端的功能支持程度各不相同,因此每个终端都被标记为推荐或不推荐。所有非推荐终端都能与 XPipe 配合使用,但可能缺乏标签、标题颜色、shell 支持等功能。使用推荐的终端,您将获得最佳的用户体验。 +program=程序 +customTerminalCommand=自定义终端命令 +customTerminalCommandDescription=使用给定命令打开自定义终端时要执行的命令。\n\nXPipe 将创建一个临时启动器 shell 脚本,供您的终端执行。在调用时,您提供的命令中的占位符字符串 $CMD 将被实际的启动器脚本取代。如果您的终端可执行路径包含空格,请务必加上引号。 +clearTerminalOnInit=启动时清除终端 +clearTerminalOnInitDescription=启用后,XPipe 会在启动新的终端会话时运行清除命令,以删除任何不必要的输出。 +enableFastTerminalStartup=启用快速终端启动 +enableFastTerminalStartupDescription=启用后,在可能的情况下,会尝试更快地启动终端会话。\n\n这将跳过几次启动检查,也不会更新任何显示的系统信息。任何连接错误只会显示在终端中。 +dontCachePasswords=不缓存提示密码 +dontCachePasswordsDescription=控制 XPipe 是否应在内部缓存查询到的密码,这样您就不必在当前会话中再次输入密码。\n\n如果禁用此行为,则每次系统需要时,您都必须重新输入任何提示的凭据。 +denyTempScriptCreation=拒绝创建临时脚本 +denyTempScriptCreationDescription=为了实现某些功能,XPipe 有时会在目标系统上创建临时 shell 脚本,以便轻松执行简单命令。这些脚本不包含任何敏感信息,只是为了实现目的而创建的。\n\n如果禁用该行为,XPipe 将不会在远程系统上创建任何临时文件。该选项在高度安全的情况下非常有用,因为在这种情况下,文件系统的每次更改都会受到监控。如果禁用,某些功能(如 shell 环境和脚本)将无法正常工作。 +disableCertutilUse=禁止在 Windows 上使用 certutil +useLocalFallbackShell=使用本地备用 shell +useLocalFallbackShellDescription=改用其他本地 shell 来处理本地操作。在 Windows 系统上是 PowerShell,在其他系统上是 bourne shell。\n\n如果正常的本地默认 shell 在某种程度上被禁用或损坏,则可以使用此选项。启用该选项后,某些功能可能无法正常工作。\n\n需要重新启动才能应用。 +disableCertutilUseDescription=由于 cmd.exe 中存在一些缺陷和错误,因此使用 certutil 创建临时 shell 脚本,用它来解码 base64 输入,因为 cmd.exe 会在非 ASCII 输入时中断。XPipe 也可以使用 PowerShell 来实现这一功能,但速度会慢一些。\n\n这将禁止在 Windows 系统上使用 certutil 来实现某些功能,转而使用 PowerShell。这可能会让一些反病毒软件感到满意,因为有些反病毒软件会阻止使用 certutil。 +disableTerminalRemotePasswordPreparation=禁用终端远程密码准备 +disableTerminalRemotePasswordPreparationDescription=如果要在终端中建立一个经过多个中间系统的远程 shell 连接,可能需要在其中一个中间系统上准备所需的密码,以便自动填写任何提示。\n\n如果不想将密码传送到任何中间系统,可以禁用此行为。任何所需的中间系统密码都将在终端打开时进行查询。 +more=更多信息 +translate=翻译 +allConnections=所有连接 +allScripts=所有脚本 +predefined=预定义 +default=默认值 +goodMorning=早上好 +goodAfternoon=下午好 +goodEvening=晚上好 +addVisual=Visual ... +ssh=SSH +sshConfiguration=SSH 配置 +size=大小 +attributes=属性 +modified=已修改 +isOnlySupported=只有专业许可证才支持 +areOnlySupported=只有专业许可证才支持 +updateReadyTitle=更新至$VERSION$ ready diff --git a/lang/base/strings/translations_de.properties b/lang/base/strings/translations_de.properties new file mode 100644 index 000000000..dd73d93ad --- /dev/null +++ b/lang/base/strings/translations_de.properties @@ -0,0 +1,109 @@ +localMachine=Lokale Maschine +destination=Ziel +configuration=Konfiguration +launch=Starten +start=Start +stop=Stopp +pause=Pause +refresh=Aktualisieren +options=Optionen +newFile=Neue Datei +newLink=Neuer Link +linkName=Link-Name +scanConnections=Verfügbare Verbindungen finden ... +observe=Beobachten beginnen +stopObserve=Beobachten stoppen +createShortcut=Desktop-Verknüpfung erstellen +browseFiles=Dateien durchsuchen +clone=Klonen +targetPath=Zielpfad +newDirectory=Neues Verzeichnis +copyShareLink=Link kopieren +selectStore=Laden auswählen +saveSource=Für später speichern +execute=Führen Sie aus +deleteChildren=Alle Kinder entfernen +descriptionDescription=Gib dieser Gruppe eine optionale Beschreibung +selectSource=Quelle auswählen +commandLineRead=Aktualisieren +commandLineWrite=Schreibe +wslHost=WSL-Host +timeout=Timeout +additionalOptions=Zusätzliche Optionen +type=Typ +input=Eingabe +machine=Maschine +container=Container +host=Host +port=Port +user=Benutzer +password=Passwort +method=Methode +uri=URL +distribution=Vertrieb +username=Benutzername +shellType=Shell-Typ +command=Befehl +browseFile=Datei durchsuchen +openShell=Shell öffnen +editFile=Datei bearbeiten +usage=Verwendung +description=Beschreibung +open=Öffnen +edit=Bearbeiten +scriptContents=Skript-Inhalte +scriptContentsDescription=Die auszuführenden Skriptbefehle +snippets=Skript-Abhängigkeiten +snippetsDescription=Andere Skripte, die zuerst ausgeführt werden sollen +snippetsDependenciesDescription=Alle möglichen Skripte, die ggf. ausgeführt werden sollten +isDefault=Wird in allen kompatiblen Shells auf init ausgeführt +bringToShells=Zu allen kompatiblen Shells bringen +isDefaultGroup=Alle Gruppenskripte auf der Shell init ausführen +executionType=Ausführungsart +executionTypeDescription=Wann dieses Snippet ausgeführt werden soll +minimumShellDialect=Shell-Typ +minimumShellDialectDescription=Der erforderliche Shell-Typ für dieses Skript +dumbOnly=Dumm +terminalOnly=Terminal +both=Beide +shouldElevate=Sollte erheben +shouldElevateDescription=Ob dieses Skript mit erhöhten Rechten ausgeführt werden soll +script.displayName=Skript +script.displayDescription=Ein wiederverwendbares Skript erstellen +scriptGroup.displayName=Skript-Gruppe +scriptGroup.displayDescription=Eine Gruppe für Skripte erstellen +scriptGroup=Gruppe +scriptGroupDescription=Die Gruppe, der dieses Skript zugewiesen werden soll +openInNewTab=In neuer Registerkarte öffnen +executeInBackground=im Hintergrund +executeInTerminal=in $TERM$ +back=Zurückgehen +browseInWindowsExplorer=Blättern im Windows-Explorer +browseInDefaultFileManager=Blättern im Standard-Dateimanager +browseInFinder=Im Finder blättern +chmod=Chmod +#custom +copy=Kopieren +paste=Einfügen +copyLocation=Ort kopieren +absolutePaths=Absolute Pfade +absoluteLinkPaths=Absolute Linkpfade +absolutePathsQuoted=Absolute Pfade in Anführungszeichen +fileNames=Dateinamen +linkFileNames=Link Dateinamen +fileNamesQuoted=Dateinamen (in Anführungszeichen) +deleteFile=Löschen $FILE$ +deleteLink=Link löschen +editWithEditor=Mit $EDITOR$ bearbeiten +followLink=Link folgen +goForward=Vorwärts gehen +showDetails=Details anzeigen +openFileWith=Öffnen mit ... +openWithDefaultApplication=Mit Standardanwendung öffnen +rename=Umbenennen +run=Ausführen +new=Neu +openInTerminal=Im Terminal öffnen +file=Datei +directory=Verzeichnis +symbolicLink=Symbolischer Link diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_en.properties b/lang/base/strings/translations_en.properties similarity index 64% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_en.properties rename to lang/base/strings/translations_en.properties index acac0433c..2ac1eff2e 100644 --- a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/translations_en.properties +++ b/lang/base/strings/translations_en.properties @@ -1,13 +1,6 @@ -anyBinaryFile=Any binary file -dataFile=Data file -binaryFile=Binary file -commandLine=Command Line -java=Java -fileOutput=File Output localMachine=Local Machine destination=Destination configuration=Configuration -selectOutput=Select Output launch=Launch start=Start stop=Stop @@ -37,12 +30,9 @@ commandLineWrite=Write wslHost=WSL Host timeout=Timeout additionalOptions=Additional Options -rawFileOutput=Raw File Output -dataSourceOutput=Data Source Output type=Type input=Input machine=Machine -bytes=$N$ bytes container=Container host=Host port=Port @@ -52,24 +42,14 @@ method=Method uri=URL distribution=Distribution username=Username -shellType=Shell Type +shellType=Shell type command=Command -target=Target -writeMode=Write Mode -exportStream=Export Stream -browseFile=Browse File -openShell=Open Shell -editFile=Edit File +browseFile=Browse file +openShell=Open shell +editFile=Edit file usage=Usage description=Description -unconnected=Unconnected -waitingForConsumer=Waiting for Consumer -waitingForProducer=Waiting for Producer open=Open -closed=Closed -internalStream.displayName=Internal Stream -local.displayName=Local machine -local.displayDescription= edit=Edit scriptContents=Script contents scriptContentsDescription=The script commands to execute @@ -83,8 +63,8 @@ executionType=Execution type executionTypeDescription=When to run this snippet minimumShellDialect=Shell type minimumShellDialectDescription=The required shell type for this script -dumbOnly=Dumb only -terminalOnly=Terminal only +dumbOnly=Dumb +terminalOnly=Terminal both=Both shouldElevate=Should elevate shouldElevateDescription=Whether to run this script with elevated permissions @@ -93,4 +73,39 @@ script.displayDescription=Create a reusable script scriptGroup.displayName=Script Group scriptGroup.displayDescription=Create a group for scripts scriptGroup=Group -scriptGroupDescription=The group to assign this script to \ No newline at end of file +scriptGroupDescription=The group to assign this script to +openInNewTab=Open in new tab +executeInBackground=in background +executeInTerminal=in $TERM$ +back=Go back +browseInWindowsExplorer=Browse in Windows explorer +browseInDefaultFileManager=Browse in default file manager +browseInFinder=Browse in finder +chmod=Chmod +copy=Copy +paste=Paste +copyLocation=Copy location +absolutePaths=Absolute paths +absoluteLinkPaths=Absolute link paths +absolutePathsQuoted=Absolute quoted paths +fileNames=File names +linkFileNames=Link file names +fileNamesQuoted=File names (Quoted) +deleteFile=Delete $FILE$ +deleteLink=Delete link +editWithEditor=Edit with $EDITOR$ +followLink=Follow link +goForward=Go forward +showDetails=Show details +openFileWith=Open with ... +openWithDefaultApplication=Open with default application +rename=Rename +run=Run +new=New +openInTerminal=Open in terminal +file=File +directory=Directory +symbolicLink=Symbolic link + + + diff --git a/lang/base/strings/translations_es.properties b/lang/base/strings/translations_es.properties new file mode 100644 index 000000000..4eb254280 --- /dev/null +++ b/lang/base/strings/translations_es.properties @@ -0,0 +1,108 @@ +localMachine=Máquina local +destination=Destino +configuration=Configuración +launch=Inicia +start=Inicia +stop=Para +pause=Pausa +refresh=Actualizar +options=Opciones +newFile=Nuevo archivo +newLink=Nuevo enlace +linkName=Nombre del enlace +scanConnections=Encontrar conexiones disponibles ... +observe=Empieza a observar +stopObserve=Dejar de observar +createShortcut=Crear acceso directo en el escritorio +browseFiles=Examinar archivos +clone=Clonar +targetPath=Ruta objetivo +newDirectory=Nuevo directorio +copyShareLink=Copiar enlace +selectStore=Seleccionar tienda +saveSource=Guardar para más tarde +execute=Ejecuta +deleteChildren=Eliminar todos los niños +descriptionDescription=Dale a este grupo una descripción opcional +selectSource=Seleccionar fuente +commandLineRead=Actualiza +commandLineWrite=Escribe +wslHost=Anfitrión WSL +timeout=Tiempo de espera +additionalOptions=Opciones adicionales +type=Escribe +input=Entrada +machine=Máquina +container=Contenedor +host=Anfitrión +port=Puerto +user=Usuario +password=Contraseña +method=Método +uri=URL +distribution=Distribución +username=Nombre de usuario +shellType=Tipo de carcasa +command=Comando +browseFile=Examinar archivo +openShell=Abrir shell +editFile=Editar archivo +usage=Utilización +description=Descripción +open=Abre +edit=Edita +scriptContents=Contenido del guión +scriptContentsDescription=Los comandos de script a ejecutar +snippets=Dependencias del script +snippetsDescription=Otros scripts para ejecutar primero +snippetsDependenciesDescription=Todas las posibles secuencias de comandos que deban ejecutarse, si procede +isDefault=Se ejecuta en init en todos los shells compatibles +bringToShells=Lleva a todas las conchas compatibles +isDefaultGroup=Ejecutar todos los scripts de grupo en shell init +executionType=Tipo de ejecución +executionTypeDescription=Cuándo ejecutar este fragmento +minimumShellDialect=Tipo de carcasa +minimumShellDialectDescription=El tipo de shell requerido para este script +dumbOnly=Mudo +terminalOnly=Terminal +both=Ambos +shouldElevate=Debe elevar +shouldElevateDescription=Si ejecutar este script con permisos elevados +script.displayName=Guión +script.displayDescription=Crear un script reutilizable +scriptGroup.displayName=Grupo de guiones +scriptGroup.displayDescription=Crear un grupo para guiones +scriptGroup=Grupo +scriptGroupDescription=El grupo al que asignar este guión +openInNewTab=Abrir en una pestaña nueva +executeInBackground=en segundo plano +executeInTerminal=en $TERM$ +back=Volver atrás +browseInWindowsExplorer=Navegar en el explorador de Windows +browseInDefaultFileManager=Navegar en el gestor de archivos por defecto +browseInFinder=Navegar en el buscador +chmod=Chmod +copy=Copia +paste=Pegar +copyLocation=Ubicación de la copia +absolutePaths=Rutas absolutas +absoluteLinkPaths=Rutas de enlace absolutas +absolutePathsQuoted=Rutas entre comillas absolutas +fileNames=Nombres de archivo +linkFileNames=Enlazar nombres de archivos +fileNamesQuoted=Nombres de archivo (entre comillas) +deleteFile=Borrar $FILE$ +deleteLink=Borrar enlace +editWithEditor=Editar con $EDITOR$ +followLink=Seguir enlace +goForward=Avanzar +showDetails=Mostrar detalles +openFileWith=Abrir con ... +openWithDefaultApplication=Abrir con la aplicación por defecto +rename=Cambia el nombre de +run=Ejecuta +new=Nuevo +openInTerminal=Abrir en terminal +file=Archivo +directory=Directorio +symbolicLink=Enlace simbólico diff --git a/lang/base/strings/translations_fr.properties b/lang/base/strings/translations_fr.properties new file mode 100644 index 000000000..dd43a2975 --- /dev/null +++ b/lang/base/strings/translations_fr.properties @@ -0,0 +1,108 @@ +localMachine=Machine locale +destination=Destination +configuration=Configuration +launch=Lancer +start=Démarrer +stop=Arrêter +pause=Pause +refresh=Rafraîchir +options=Options +newFile=Nouveau fichier +newLink=Nouveau lien +linkName=Nom du lien +scanConnections=Trouver les connexions disponibles ... +observe=Commencer à observer +stopObserve=Arrêter d'observer +createShortcut=Créer un raccourci sur le bureau +browseFiles=Parcourir les fichiers +clone=Clone +targetPath=Chemin cible +newDirectory=Nouveau répertoire +copyShareLink=Copier le lien +selectStore=Sélectionner un magasin +saveSource=Sauvegarder pour plus tard +execute=Exécuter +deleteChildren=Enlève tous les enfants +descriptionDescription=Donne à ce groupe une description facultative +selectSource=Sélectionner la source +commandLineRead=Mise à jour +commandLineWrite=Ecris +wslHost=Hôte WSL +timeout=Délai d'attente +additionalOptions=Options supplémentaires +type=Type de texte +input=Entrée +machine=Machine +container=Conteneur +host=Hôte +port=Port +user=Utilisateur +password=Mot de passe +method=Méthode +uri=URL +distribution=Distribution +username=Nom d'utilisateur +shellType=Type de coquille +command=Commande +browseFile=Parcourir le fichier +openShell=Ouvrir le shell +editFile=Editer un fichier +usage=Utilisation +description=Description +open=Ouvrir +edit=Éditer +scriptContents=Contenu du script +scriptContentsDescription=Les commandes de script à exécuter +snippets=Dépendances des scripts +snippetsDescription=Autres scripts à exécuter en premier +snippetsDependenciesDescription=Tous les scripts possibles qui doivent être exécutés le cas échéant +isDefault=S'exécute en mode init dans tous les shells compatibles +bringToShells=Apporte à tous les coquillages compatibles +isDefaultGroup=Exécute tous les scripts de groupe au démarrage de l'interpréteur de commandes +executionType=Type d'exécution +executionTypeDescription=Quand exécuter cet extrait +minimumShellDialect=Type de coquille +minimumShellDialectDescription=Le type d'interpréteur de commandes requis pour ce script +dumbOnly=Muet +terminalOnly=Terminal +both=Les deux +shouldElevate=Devrait s'élever +shouldElevateDescription=Si ce script doit être exécuté avec des autorisations élevées +script.displayName=Écriture +script.displayDescription=Créer un script réutilisable +scriptGroup.displayName=Groupe de scripts +scriptGroup.displayDescription=Créer un groupe pour les scripts +scriptGroup=Groupe +scriptGroupDescription=Le groupe à qui attribuer ce texte +openInNewTab=Ouvrir dans un nouvel onglet +executeInBackground=en arrière-plan +executeInTerminal=dans $TERM$ +back=Retourner +browseInWindowsExplorer=Naviguer dans l'explorateur Windows +browseInDefaultFileManager=Parcourir dans le gestionnaire de fichiers par défaut +browseInFinder=Parcourir dans finder +chmod=Chmod +copy=Copie +paste=Coller +copyLocation=Emplacement de la copie +absolutePaths=Chemins absolus +absoluteLinkPaths=Chemins d'accès absolus +absolutePathsQuoted=Chemins d'accès absolus entre guillemets +fileNames=Noms de fichiers +linkFileNames=Noms de fichiers de liaison +fileNamesQuoted=Noms de fichiers (cités) +deleteFile=Effacer $FILE$ +deleteLink=Supprimer le lien +editWithEditor=Éditer avec $EDITOR$ +followLink=Suivre le lien +goForward=Aller de l'avant +showDetails=Afficher les détails +openFileWith=Ouvrir avec ... +openWithDefaultApplication=Ouvrir avec l'application par défaut +rename=Renommer +run=Exécuter +new=Nouveau +openInTerminal=Ouvrir dans le terminal +file=Fichier +directory=Répertoire +symbolicLink=Lien symbolique diff --git a/lang/base/strings/translations_it.properties b/lang/base/strings/translations_it.properties new file mode 100644 index 000000000..dea922a89 --- /dev/null +++ b/lang/base/strings/translations_it.properties @@ -0,0 +1,108 @@ +localMachine=Macchina locale +destination=Destinazione +configuration=Configurazione +launch=Lancio +start=Iniziare +stop=Fermati +pause=Pausa +refresh=Aggiornare +options=Opzioni +newFile=Nuovo file +newLink=Nuovo link +linkName=Nome del link +scanConnections=Trova le connessioni disponibili ... +observe=Iniziare a osservare +stopObserve=Smetti di osservare +createShortcut=Creare un collegamento al desktop +browseFiles=Sfogliare i file +clone=Clone +targetPath=Percorso di destinazione +newDirectory=Nuova directory +copyShareLink=Copia link +selectStore=Seleziona il negozio +saveSource=Salva per dopo +execute=Eseguire +deleteChildren=Rimuovi tutti i bambini +descriptionDescription=Dai a questo gruppo una descrizione opzionale +selectSource=Seleziona la fonte +commandLineRead=Aggiornamento +commandLineWrite=Scrivere +wslHost=Host WSL +timeout=Timeout +additionalOptions=Opzioni aggiuntive +type=Tipo +input=Ingresso +machine=Macchina +container=Contenitore +host=Ospite +port=Porta +user=Utente +password=Password +method=Metodo +uri=URL +distribution=Distribuzione +username=Nome utente +shellType=Tipo di shell +command=Comando +browseFile=Sfogliare un file +openShell=Guscio aperto +editFile=Modifica di un file +usage=Utilizzo +description=Descrizione +open=Aprire +edit=Modifica +scriptContents=Contenuto dello script +scriptContentsDescription=I comandi di script da eseguire +snippets=Dipendenze degli script +snippetsDescription=Altri script da eseguire prima +snippetsDependenciesDescription=Tutti i possibili script che devono essere eseguiti, se applicabile +isDefault=Eseguito su init in tutte le shell compatibili +bringToShells=Porta a tutte le conchiglie compatibili +isDefaultGroup=Esegui tutti gli script del gruppo all'avvio della shell +executionType=Tipo di esecuzione +executionTypeDescription=Quando eseguire questo snippet +minimumShellDialect=Tipo di shell +minimumShellDialectDescription=Il tipo di shell richiesto per questo script +dumbOnly=Muto +terminalOnly=Terminale +both=Entrambi +shouldElevate=Dovrebbe elevare +shouldElevateDescription=Se eseguire questo script con permessi elevati o meno +script.displayName=Scrittura +script.displayDescription=Creare uno script riutilizzabile +scriptGroup.displayName=Gruppo di script +scriptGroup.displayDescription=Crea un gruppo per gli script +scriptGroup=Gruppo +scriptGroupDescription=Il gruppo a cui assegnare questo script +openInNewTab=Aprire una nuova scheda +executeInBackground=in uno sfondo +executeInTerminal=in $TERM$ +back=Torna indietro +browseInWindowsExplorer=Sfogliare in Windows explorer +browseInDefaultFileManager=Sfoglia nel file manager predefinito +browseInFinder=Sfogliare in finder +chmod=Chmod +copy=Copia +paste=Incolla +copyLocation=Posizione di copia +absolutePaths=Percorsi assoluti +absoluteLinkPaths=Percorsi di collegamento assoluti +absolutePathsQuoted=Percorsi quotati assoluti +fileNames=Nomi di file +linkFileNames=Nomi di file di collegamento +fileNamesQuoted=Nomi di file (citati) +deleteFile=Eliminare $FILE$ +deleteLink=Elimina il link +editWithEditor=Modifica con $EDITOR$ +followLink=Segui il link +goForward=Vai avanti +showDetails=Mostra i dettagli +openFileWith=Apri con ... +openWithDefaultApplication=Apri con l'applicazione predefinita +rename=Rinominare +run=Esegui +new=Nuovo +openInTerminal=Aprire nel terminale +file=File +directory=Elenco +symbolicLink=Collegamento simbolico diff --git a/lang/base/strings/translations_ja.properties b/lang/base/strings/translations_ja.properties new file mode 100644 index 000000000..1e5c70ea8 --- /dev/null +++ b/lang/base/strings/translations_ja.properties @@ -0,0 +1,108 @@ +localMachine=ローカルマシン +destination=行き先 +configuration=構成 +launch=起動 +start=スタート +stop=停止する +pause=一時停止 +refresh=リフレッシュする +options=オプション +newFile=新規ファイル +newLink=新しいリンク +linkName=リンク名 +scanConnections=利用可能な接続を検索する +observe=観察を開始する +stopObserve=観察をやめる +createShortcut=デスクトップのショートカットを作成する +browseFiles=ファイルをブラウズする +clone=クローン +targetPath=ターゲットパス +newDirectory=新しいディレクトリ +copyShareLink=リンクをコピーする +selectStore=店舗を選択する +saveSource=後で保存する +execute=実行する +deleteChildren=すべての子供を削除する +descriptionDescription=このグループに任意の説明を与える +selectSource=ソースを選択する +commandLineRead=更新 +commandLineWrite=書く +wslHost=WSLホスト +timeout=タイムアウト +additionalOptions=追加オプション +type=タイプ +input=入力 +machine=機械 +container=コンテナ +host=ホスト +port=ポート +user=ユーザー +password=パスワード +method=方法 +uri=URL +distribution=配布 +username=ユーザー名 +shellType=シェルタイプ +command=コマンド +browseFile=ファイルをブラウズする +openShell=シェルを開く +editFile=ファイルを編集する +usage=使用方法 +description=説明 +open=開く +edit=編集する +scriptContents=スクリプトの内容 +scriptContentsDescription=実行するスクリプトコマンド +snippets=スクリプトの依存関係 +snippetsDescription=最初に実行する他のスクリプト +snippetsDependenciesDescription=該当する場合、実行可能なすべてのスクリプト +isDefault=すべての互換シェルでinit時に実行される +bringToShells=すべての互換性のあるシェルに持ち込む +isDefaultGroup=シェル init ですべてのグループスクリプトを実行する +executionType=実行タイプ +executionTypeDescription=このスニペットを実行するタイミング +minimumShellDialect=シェルタイプ +minimumShellDialectDescription=このスクリプトに必要なシェルタイプ +dumbOnly=ダム +terminalOnly=ターミナル +both=どちらも +shouldElevate=高めるべきである +shouldElevateDescription=このスクリプトを昇格した権限で実行するかどうか +script.displayName=スクリプト +script.displayDescription=再利用可能なスクリプトを作成する +scriptGroup.displayName=スクリプトグループ +scriptGroup.displayDescription=スクリプトのグループを作成する +scriptGroup=グループ +scriptGroupDescription=このスクリプトを割り当てるグループ +openInNewTab=新しいタブで開く +executeInBackground=背景 +executeInTerminal=で$TERM$ +back=戻る +browseInWindowsExplorer=Windowsエクスプローラでブラウズする +browseInDefaultFileManager=デフォルトのファイルマネージャーでブラウズする +browseInFinder=ファインダーでブラウズする +chmod=Chmod +copy=コピー +paste=貼り付け +copyLocation=コピー場所 +absolutePaths=絶対パス +absoluteLinkPaths=絶対リンクパス +absolutePathsQuoted=絶対引用パス +fileNames=ファイル名 +linkFileNames=リンクファイル名 +fileNamesQuoted=ファイル名(引用) +deleteFile=削除する$FILE$ +deleteLink=リンクを削除する +editWithEditor=EDITORで編集する +followLink=リンクをたどる +goForward=進む +showDetails=詳細を表示する +openFileWith=... で開く +openWithDefaultApplication=デフォルトのアプリケーションで開く +rename=名前を変更する +run=実行する +new=新しい +openInTerminal=ターミナルで開く +file=ファイル +directory=ディレクトリ +symbolicLink=シンボリックリンク diff --git a/lang/base/strings/translations_nl.properties b/lang/base/strings/translations_nl.properties new file mode 100644 index 000000000..f28d380ae --- /dev/null +++ b/lang/base/strings/translations_nl.properties @@ -0,0 +1,108 @@ +localMachine=Lokale machine +destination=Bestemming +configuration=Configuratie +launch=Start +start=Start +stop=Stop +pause=Pauze +refresh=Vernieuwen +options=Opties +newFile=Nieuw bestand +newLink=Nieuwe koppeling +linkName=Link naam +scanConnections=Beschikbare verbindingen zoeken ... +observe=Beginnen met observeren +stopObserve=Stoppen met observeren +createShortcut=Snelkoppeling op het bureaublad maken +browseFiles=Door bestanden bladeren +clone=Kloon +targetPath=Doelpad +newDirectory=Nieuwe map +copyShareLink=Link kopiëren +selectStore=Winkel selecteren +saveSource=Opslaan voor later +execute=Uitvoeren +deleteChildren=Alle kinderen verwijderen +descriptionDescription=Geef deze groep een optionele beschrijving +selectSource=Bron selecteren +commandLineRead=Bijwerken +commandLineWrite=Schrijven +wslHost=WSL host +timeout=Time-out +additionalOptions=Extra opties +type=Type +input=Invoer +machine=Machine +container=Container +host=Host +port=Poort +user=Gebruiker +password=Wachtwoord +method=Methode +uri=URL +distribution=Distributie +username=Gebruikersnaam +shellType=Type omhulsel +command=Opdracht +browseFile=Bestand doorbladeren +openShell=Open schil +editFile=Bestand bewerken +usage=Gebruik +description=Beschrijving +open=Open +edit=Bewerken +scriptContents=Inhoud van een script +scriptContentsDescription=De uit te voeren scriptopdrachten +snippets=Script afhankelijkheden +snippetsDescription=Andere scripts om eerst uit te voeren +snippetsDependenciesDescription=Alle mogelijke scripts die moeten worden uitgevoerd, indien van toepassing +isDefault=Uitvoeren op init in alle compatibele shells +bringToShells=Breng naar alle compatibele shells +isDefaultGroup=Alle groepsscripts uitvoeren op shell init +executionType=Type uitvoering +executionTypeDescription=Wanneer dit knipsel uitvoeren +minimumShellDialect=Type omhulsel +minimumShellDialectDescription=Het vereiste shelltype voor dit script +dumbOnly=Stom +terminalOnly=Terminal +both=Beide +shouldElevate=Moet verheffen +shouldElevateDescription=Of dit script met verhoogde rechten moet worden uitgevoerd +script.displayName=Script +script.displayDescription=Een herbruikbaar script maken +scriptGroup.displayName=Script-groep +scriptGroup.displayDescription=Een groep maken voor scripts +scriptGroup=Groep +scriptGroupDescription=De groep om dit script aan toe te wijzen +openInNewTab=In nieuw tabblad openen +executeInBackground=op de achtergrond +executeInTerminal=in $TERM$ +back=Teruggaan +browseInWindowsExplorer=Bladeren in Windows verkenner +browseInDefaultFileManager=Bladeren in standaard bestandsbeheer +browseInFinder=Bladeren in finder +chmod=Chmod +copy=Kopiëren +paste=Plakken +copyLocation=Locatie kopiëren +absolutePaths=Absolute paden +absoluteLinkPaths=Absolute linkpaden +absolutePathsQuoted=Absoluut aangehaalde paden +fileNames=Bestandsnamen +linkFileNames=Bestandsnamen koppelen +fileNamesQuoted=Bestandsnamen (Geciteerd) +deleteFile=Verwijderen $FILE$ +deleteLink=Link verwijderen +editWithEditor=Bewerken met $EDITOR$ +followLink=Link volgen +goForward=Doorgaan +showDetails=Details tonen +openFileWith=Openen met ... +openWithDefaultApplication=Openen met standaardtoepassing +rename=Hernoemen +run=Uitvoeren +new=Nieuw +openInTerminal=Openen in terminal +file=Bestand +directory=Directory +symbolicLink=Symbolische link diff --git a/lang/base/strings/translations_pt.properties b/lang/base/strings/translations_pt.properties new file mode 100644 index 000000000..677655648 --- /dev/null +++ b/lang/base/strings/translations_pt.properties @@ -0,0 +1,108 @@ +localMachine=Máquina local +destination=Destino +configuration=Configuração +launch=Lança +start=Começa +stop=Pára +pause=Pausa +refresh=Actualiza +options=Opções +newFile=Novo ficheiro +newLink=Nova ligação +linkName=Nome da ligação +scanConnections=Procura as ligações disponíveis ... +observe=Começa a observar +stopObserve=Pára de observar +createShortcut=Cria um atalho no ambiente de trabalho +browseFiles=Procurar ficheiros +clone=Clone +targetPath=Caminho de destino +newDirectory=Novo diretório +copyShareLink=Copia a ligação +selectStore=Selecionar loja +saveSource=Guardar para mais tarde +execute=Executa +deleteChildren=Remove todas as crianças +descriptionDescription=Dá a este grupo uma descrição opcional +selectSource=Selecionar fonte +commandLineRead=Atualização +commandLineWrite=Escreve +wslHost=Anfitrião WSL +timeout=Tempo limite +additionalOptions=Opções adicionais +type=Digita +input=Introduzir +machine=Máquina +container=Contentor +host=Aloja +port=Porta +user=Utilizador +password=Palavra-passe +method=Método +uri=URL +distribution=Distribuição +username=Nome de utilizador +shellType=Tipo de shell +command=Comanda +browseFile=Procurar ficheiro +openShell=Abre a shell +editFile=Editar ficheiro +usage=Usa +description=Descrição +open=Abre-te +edit=Edita +scriptContents=Conteúdo do script +scriptContentsDescription=Os comandos de script a executar +snippets=Dependências de scripts +snippetsDescription=Outros scripts para executar primeiro +snippetsDependenciesDescription=Todos os possíveis scripts que devem ser executados, se aplicável +isDefault=Corre no init em todos os shells compatíveis +bringToShells=Traz para todos os shells compatíveis +isDefaultGroup=Executa todos os scripts de grupo no shell init +executionType=Tipo de execução +executionTypeDescription=Quando deves executar este snippet +minimumShellDialect=Tipo de shell +minimumShellDialectDescription=O tipo de shell necessário para este script +dumbOnly=Estúpido +terminalOnly=Terminal +both=Ambos +shouldElevate=Deve elevar +shouldElevateDescription=Se queres executar este script com permissões elevadas +script.displayName=Escreve +script.displayDescription=Cria um script reutilizável +scriptGroup.displayName=Grupo de scripts +scriptGroup.displayDescription=Cria um grupo para scripts +scriptGroup=Agrupa +scriptGroupDescription=O grupo ao qual atribuir este guião +openInNewTab=Abre num novo separador +executeInBackground=em segundo plano +executeInTerminal=em $TERM$ +back=Volta atrás +browseInWindowsExplorer=Navega no Windows Explorer +browseInDefaultFileManager=Navega no gestor de ficheiros predefinido +browseInFinder=Navega no localizador +chmod=Chmod +copy=Copia +paste=Cola +copyLocation=Copia a localização +absolutePaths=Caminhos absolutos +absoluteLinkPaths=Caminhos de ligação absolutos +absolutePathsQuoted=Caminhos absolutos entre aspas +fileNames=Nomes de ficheiros +linkFileNames=Liga nomes de ficheiros +fileNamesQuoted=Nomes de ficheiros (Citado) +deleteFile=Elimina $FILE$ +deleteLink=Elimina a ligação +editWithEditor=Edita com $EDITOR$ +followLink=Segue a ligação +goForward=Avança +showDetails=Mostra os detalhes +openFileWith=Abre com ... +openWithDefaultApplication=Abre com a aplicação por defeito +rename=Renomeia +run=Executa +new=Novo +openInTerminal=Abre no terminal +file=Ficheiro +directory=Diretório +symbolicLink=Ligação simbólica diff --git a/lang/base/strings/translations_ru.properties b/lang/base/strings/translations_ru.properties new file mode 100644 index 000000000..648832360 --- /dev/null +++ b/lang/base/strings/translations_ru.properties @@ -0,0 +1,108 @@ +localMachine=Локальная машина +destination=Назначение +configuration=Конфигурация +launch=Запустите +start=Начни +stop=Стоп +pause=Пауза +refresh=Обновить +options=Опции +newFile=Новый файл +newLink=Новая ссылка +linkName=Название ссылки +scanConnections=Найдите доступные соединения ... +observe=Начни наблюдать +stopObserve=Перестань наблюдать +createShortcut=Создайте ярлык на рабочем столе +browseFiles=Просматривать файлы +clone=Клон +targetPath=Целевой путь +newDirectory=Новый каталог +copyShareLink=Копируемая ссылка +selectStore=Выберите магазин +saveSource=Сохранить на потом +execute=Выполнить +deleteChildren=Удалите всех детей +descriptionDescription=Дайте этой группе дополнительное описание +selectSource=Выберите источник +commandLineRead=Обновление +commandLineWrite=Напиши +wslHost=WSL Host +timeout=Таймаут +additionalOptions=Дополнительные опции +type=Тип +input=Вход +machine=Машина +container=Контейнер +host=Хост +port=Порт +user=Пользователь +password=Пароль +method=Метод +uri=URL +distribution=Рассылка +username=Имя пользователя +shellType=Тип оболочки +command=Команда +browseFile=Просмотр файла +openShell=Открытая оболочка +editFile=Редактировать файл +usage=Использование +description=Описание +open=Открыть +edit=Редактировать +scriptContents=Содержание скрипта +scriptContentsDescription=Команды скрипта, которые нужно выполнить +snippets=Зависимости от сценария +snippetsDescription=Другие скрипты, которые нужно запустить первыми +snippetsDependenciesDescription=Все возможные скрипты, которые следует запустить, если это необходимо +isDefault=Запускается в init во всех совместимых оболочках +bringToShells=Принесите всем совместимым оболочкам +isDefaultGroup=Запустите все групповые скрипты на shell init +executionType=Тип исполнения +executionTypeDescription=Когда запускать этот сниппет +minimumShellDialect=Тип оболочки +minimumShellDialectDescription=Необходимый тип оболочки для этого скрипта +dumbOnly=Тупой +terminalOnly=Терминал +both=Оба +shouldElevate=Должен возвышать +shouldElevateDescription=Нужно ли запускать этот скрипт с повышенными правами +script.displayName=Скрипт +script.displayDescription=Создай скрипт многоразового использования +scriptGroup.displayName=Группа сценариев +scriptGroup.displayDescription=Создайте группу для скриптов +scriptGroup=Группа +scriptGroupDescription=Группа, которой нужно поручить этот скрипт +openInNewTab=Открыть в новой вкладке +executeInBackground=в фоновом режиме +executeInTerminal=в $TERM$ +back=Возвращайся назад +browseInWindowsExplorer=Обзор в проводнике Windows +browseInDefaultFileManager=Обзор в файловом менеджере по умолчанию +browseInFinder=Обзор в программе для поиска +chmod=Chmod +copy=Скопируй +paste=Paste +copyLocation=Место копирования +absolutePaths=Абсолютные пути +absoluteLinkPaths=Абсолютные пути ссылок +absolutePathsQuoted=Абсолютные пути с кавычками +fileNames=Имена файлов +linkFileNames=Имена файлов ссылок +fileNamesQuoted=Имена файлов (в кавычках) +deleteFile=Удалить $FILE$ +deleteLink=Удалить ссылку +editWithEditor=Редактирование с помощью $EDITOR$ +followLink=Перейдите по ссылке +goForward=Иди вперед +showDetails=Показать подробности +openFileWith=Открой с помощью ... +openWithDefaultApplication=Открыть с помощью приложения по умолчанию +rename=Переименовать +run=Запускай +new=Новый +openInTerminal=Открыть в терминале +file=Файл +directory=Каталог +symbolicLink=Символическая ссылка diff --git a/lang/base/strings/translations_tr.properties b/lang/base/strings/translations_tr.properties new file mode 100644 index 000000000..a36482719 --- /dev/null +++ b/lang/base/strings/translations_tr.properties @@ -0,0 +1,108 @@ +localMachine=Yerel Makine +destination=Hedef +configuration=Konfigürasyon +launch=Fırlatma +start=Başlangıç +stop=Dur +pause=Duraklat +refresh=Yenile +options=Seçenekler +newFile=Yeni dosya +newLink=Yeni bağlantı +linkName=Bağlantı adı +scanConnections=Mevcut bağlantıları bulun ... +observe=Gözlemlemeye başlayın +stopObserve=Gözlemlemeyi bırak +createShortcut=Masaüstü kısayolu oluşturma +browseFiles=Dosyalara Gözat +clone=Klon +targetPath=Hedef yol +newDirectory=Yeni dizin +copyShareLink=Bağlantıyı kopyala +selectStore=Mağaza Seçiniz +saveSource=Daha sonrası için kaydet +execute=Yürütmek +deleteChildren=Tüm çocukları kaldırın +descriptionDescription=Bu gruba isteğe bağlı bir açıklama verin +selectSource=Kaynak Seçiniz +commandLineRead=Güncelleme +commandLineWrite=Yazmak +wslHost=WSL Ev Sahibi +timeout=Zaman Aşımı +additionalOptions=Ek Seçenekler +type=Tip +input=Giriş +machine=Makine +container=Konteyner +host=Ev sahibi +port=Liman +user=Kullanıcı +password=Şifre +method=Yöntem +uri=URL +distribution=Dağıtım +username=Kullanıcı Adı +shellType=Kabuk tipi +command=Komuta +browseFile=Dosyaya göz at +openShell=Açık kabuk +editFile=Dosyayı düzenle +usage=Kullanım +description=Açıklama +open=Açık +edit=Düzenle +scriptContents=Senaryo içeriği +scriptContentsDescription=Çalıştırılacak komut dosyası komutları +snippets=Komut dosyası bağımlılıkları +snippetsDescription=Önce çalıştırılacak diğer betikler +snippetsDependenciesDescription=Varsa çalıştırılması gereken tüm olası komut dosyaları +isDefault=Tüm uyumlu kabuklarda init üzerinde çalıştırın +bringToShells=Tüm uyumlu kabukları getirin +isDefaultGroup=Tüm grup komut dosyalarını kabuk başlangıcında çalıştırın +executionType=Yürütme türü +executionTypeDescription=Bu snippet ne zaman çalıştırılır +minimumShellDialect=Kabuk tipi +minimumShellDialectDescription=Bu betik için gerekli kabuk türü +dumbOnly=Aptal +terminalOnly=Terminal +both=Her ikisi de +shouldElevate=Yükseltmeli +shouldElevateDescription=Bu betiğin yükseltilmiş izinlerle çalıştırılıp çalıştırılmayacağı +script.displayName=Senaryo +script.displayDescription=Yeniden kullanılabilir bir komut dosyası oluşturma +scriptGroup.displayName=Senaryo Grubu +scriptGroup.displayDescription=Komut dosyaları için bir grup oluşturma +scriptGroup=Grup +scriptGroupDescription=Bu komut dosyasının atanacağı grup +openInNewTab=Yeni sekmede aç +executeInBackground=arka planda +executeInTerminal=içinde $TERM$ +back=Geri dön +browseInWindowsExplorer=Windows gezgininde göz atın +browseInDefaultFileManager=Varsayılan dosya yöneticisine göz atın +browseInFinder=Bulucuya göz atın +chmod=Chmod +copy=Anlaşıldı +paste=Yapıştır +copyLocation=Kopyalama konumu +absolutePaths=Mutlak yollar +absoluteLinkPaths=Mutlak bağlantı yolları +absolutePathsQuoted=Mutlak alıntılanmış yollar +fileNames=Dosya adları +linkFileNames=Dosya adlarını bağlama +fileNamesQuoted=Dosya adları (Alıntı) +deleteFile=Silme $FILE$ +deleteLink=Bağlantıyı sil +editWithEditor=İle düzenleyin $EDITOR$ +followLink=Bağlantıyı takip edin +goForward=İleri git +showDetails=Detayları göster +openFileWith=İle açın ... +openWithDefaultApplication=Varsayılan uygulama ile aç +rename=Yeniden Adlandır +run=Koşmak +new=Yeni +openInTerminal=Terminalde aç +file=Dosya +directory=Rehber +symbolicLink=Sembolik bağlantı diff --git a/lang/base/strings/translations_zh.properties b/lang/base/strings/translations_zh.properties new file mode 100644 index 000000000..4cfb4fefc --- /dev/null +++ b/lang/base/strings/translations_zh.properties @@ -0,0 +1,108 @@ +localMachine=本地机器 +destination=目的地 +configuration=配置 +launch=启动 +start=开始 +stop=停止 +pause=暂停 +refresh=刷新 +options=选项 +newFile=新文件 +newLink=新链接 +linkName=链接名称 +scanConnections=查找可用连接 ... +observe=开始观察 +stopObserve=停止观察 +createShortcut=创建桌面快捷方式 +browseFiles=浏览文件 +clone=克隆 +targetPath=目标路径 +newDirectory=新目录 +copyShareLink=复制链接 +selectStore=选择商店 +saveSource=保存备用 +execute=执行 +deleteChildren=删除所有儿童 +descriptionDescription=为该组提供可选描述 +selectSource=选择来源 +commandLineRead=更新 +commandLineWrite=书写 +wslHost=WSL 主机 +timeout=超时 +additionalOptions=附加选项 +type=类型 +input=输入 +machine=机器 +container=容器 +host=主机 +port=端口 +user=用户 +password=密码 +method=方法 +uri=网址 +distribution=分发 +username=用户名 +shellType=外壳类型 +command=指令 +browseFile=浏览文件 +openShell=打开外壳 +editFile=编辑文件 +usage=使用方法 +description=说明 +open=打开 +edit=编辑 +scriptContents=脚本内容 +scriptContentsDescription=要执行的脚本命令 +snippets=脚本依赖 +snippetsDescription=先运行的其他脚本 +snippetsDependenciesDescription=如果适用,应运行的所有可能脚本 +isDefault=在所有兼容外壳的 init 中运行 +bringToShells=带入所有兼容外壳 +isDefaultGroup=在 shell 启动时运行所有组脚本 +executionType=执行类型 +executionTypeDescription=何时运行此片段 +minimumShellDialect=外壳类型 +minimumShellDialectDescription=该脚本所需的 shell 类型 +dumbOnly=笨 +terminalOnly=终端 +both=两者 +shouldElevate=应提升 +shouldElevateDescription=是否以提升的权限运行此脚本 +script.displayName=脚本 +script.displayDescription=创建可重复使用的脚本 +scriptGroup.displayName=脚本组 +scriptGroup.displayDescription=创建脚本组 +scriptGroup=组别 +scriptGroupDescription=要将此脚本分配给的组 +openInNewTab=在新标签页中打开 +executeInBackground=在后台 +executeInTerminal=在$TERM$ +back=返回 +browseInWindowsExplorer=在 Windows 资源管理器中浏览 +browseInDefaultFileManager=在默认文件管理器中浏览 +browseInFinder=在查找器中浏览 +chmod=Chmod +copy=复制 +paste=粘贴 +copyLocation=复制位置 +absolutePaths=绝对路径 +absoluteLinkPaths=绝对链接路径 +absolutePathsQuoted=绝对引用路径 +fileNames=文件名 +linkFileNames=链接文件名 +fileNamesQuoted=文件名(引号) +deleteFile=删除$FILE$ +deleteLink=删除链接 +editWithEditor=用 $EDITOR$ 编辑 +followLink=跟踪链接 +goForward=前进 +showDetails=显示详细信息 +openFileWith=用 ... 打开 +openWithDefaultApplication=用默认应用程序打开 +rename=重命名 +run=运行 +new=新 +openInTerminal=在终端中打开 +file=文件 +directory=目录 +symbolicLink=符号链接 diff --git a/lang/base/texts/elevation_de.md b/lang/base/texts/elevation_de.md new file mode 100644 index 000000000..e71427d4a --- /dev/null +++ b/lang/base/texts/elevation_de.md @@ -0,0 +1,14 @@ +## Elevation + +Der Prozess der Elevation ist betriebssystemspezifisch. + +### Linux & macOS + +Jeder erhobene Befehl wird mit `sudo` ausgeführt. Das optionale `sudo` Passwort wird bei Bedarf über XPipe abgefragt. +Du kannst in den Einstellungen festlegen, ob du dein Passwort jedes Mal eingeben willst, wenn es gebraucht wird, oder ob du es für die aktuelle Sitzung zwischenspeichern willst. + +### Windows + +Unter Windows ist es nicht möglich, einen untergeordneten Prozess zu aktivieren, wenn der übergeordnete Prozess nicht auch aktiviert ist. +Wenn XPipe also nicht als Administrator ausgeführt wird, kannst du lokal keine Berechtigungserweiterung nutzen. +Bei Fernverbindungen muss das verbundene Benutzerkonto über Administratorrechte verfügen. \ No newline at end of file diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/elevation_en.md b/lang/base/texts/elevation_en.md similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/elevation_en.md rename to lang/base/texts/elevation_en.md diff --git a/lang/base/texts/elevation_es.md b/lang/base/texts/elevation_es.md new file mode 100644 index 000000000..1eaebc7c9 --- /dev/null +++ b/lang/base/texts/elevation_es.md @@ -0,0 +1,14 @@ +## Elevación + +El proceso de elevación es específico del sistema operativo. + +### Linux y macOS + +Cualquier comando elevado se ejecuta con `sudo`. La contraseña opcional `sudo` se consulta a través de XPipe cuando es necesario. +Tienes la posibilidad de ajustar el comportamiento de elevación en la configuración para controlar si quieres introducir tu contraseña cada vez que se necesite o si quieres guardarla en caché para la sesión actual. + +### Windows + +En Windows, no es posible elevar un proceso hijo si el proceso padre no está también elevado. +Por lo tanto, si XPipe no se ejecuta como administrador, no podrás utilizar ninguna elevación localmente. +Para las conexiones remotas, la cuenta de usuario conectada debe tener privilegios de administrador. \ No newline at end of file diff --git a/lang/base/texts/elevation_fr.md b/lang/base/texts/elevation_fr.md new file mode 100644 index 000000000..481cbf871 --- /dev/null +++ b/lang/base/texts/elevation_fr.md @@ -0,0 +1,14 @@ +## Élévation + +Le processus d'élévation est spécifique au système d'exploitation. + +### Linux et macOS + +Toute commande élevée est exécutée avec `sudo`. Le mot de passe facultatif `sudo` est interrogé via XPipe lorsque cela est nécessaire. +Tu as la possibilité d'ajuster le comportement d'élévation dans les paramètres pour contrôler si tu veux saisir ton mot de passe à chaque fois qu'il est nécessaire ou si tu veux le mettre en cache pour la session en cours. + +### Windows + +Sous Windows, il n'est pas possible d'élever un processus enfant si le processus parent n'est pas lui aussi élevé. +Par conséquent, si XPipe n'est pas exécuté en tant qu'administrateur, tu ne pourras pas utiliser d'élévation localement. +Pour les connexions à distance, le compte utilisateur connecté doit avoir des privilèges d'administrateur. \ No newline at end of file diff --git a/lang/base/texts/elevation_it.md b/lang/base/texts/elevation_it.md new file mode 100644 index 000000000..e78bd00d5 --- /dev/null +++ b/lang/base/texts/elevation_it.md @@ -0,0 +1,14 @@ +## Elevazione + +Il processo di elevazione è specifico del sistema operativo. + +### Linux e macOS + +Qualsiasi comando elevato viene eseguito con `sudo`. La password opzionale `sudo` viene interrogata tramite XPipe quando necessario. +Hai la possibilità di regolare il comportamento di elevazione nelle impostazioni per controllare se vuoi inserire la password ogni volta che è necessaria o se vuoi memorizzarla per la sessione corrente. + +### Windows + +In Windows, non è possibile elevare un processo figlio se anche il processo padre non è elevato. +Pertanto, se XPipe non viene eseguito come amministratore, non potrai utilizzare l'elevazione a livello locale. +Per le connessioni remote, l'account utente collegato deve avere i privilegi di amministratore. \ No newline at end of file diff --git a/lang/base/texts/elevation_ja.md b/lang/base/texts/elevation_ja.md new file mode 100644 index 000000000..69ded4e6a --- /dev/null +++ b/lang/base/texts/elevation_ja.md @@ -0,0 +1,14 @@ +## 標高 + +昇格のプロセスはオペレーティングシステムに依存する。 + +### LinuxとmacOS + +すべての昇格コマンドは`sudo`で実行される。オプションの`sudo`パスワードは、必要に応じてXPipe経由で照会される。 +パスワードが必要になるたびにパスワードを入力するか、現在のセッションのためにパスワードをキャッシュするかを制御するために、設定で昇格の動作を調整する機能がある。 + +### ウィンドウズ + +Windowsでは、親プロセスが昇格していない場合、子プロセスを昇格させることはできない。 +したがって、XPipeが管理者として実行されていない場合、ローカルで昇格を使用することはできない。 +リモート接続の場合、接続するユーザーアカウントに管理者権限を与える必要がある。 \ No newline at end of file diff --git a/lang/base/texts/elevation_nl.md b/lang/base/texts/elevation_nl.md new file mode 100644 index 000000000..6f4b6da77 --- /dev/null +++ b/lang/base/texts/elevation_nl.md @@ -0,0 +1,14 @@ +## Hoogte + +Het proces van elevatie is besturingssysteem specifiek. + +### Linux en macOS + +Elk verhoogd commando wordt uitgevoerd met `sudo`. Het optionele `sudo` wachtwoord wordt indien nodig opgevraagd via XPipe. +Je hebt de mogelijkheid om het verheffingsgedrag aan te passen in de instellingen om te bepalen of je je wachtwoord elke keer wilt invoeren als het nodig is of dat je het wilt cachen voor de huidige sessie. + +### Windows + +In Windows is het niet mogelijk om een kindproces te verheffen als het ouderproces niet ook is verheven. +Als XPipe dus niet als beheerder wordt uitgevoerd, kun je lokaal geen verheffing gebruiken. +Voor verbindingen op afstand moet de verbonden gebruikersaccount beheerdersrechten krijgen. \ No newline at end of file diff --git a/lang/base/texts/elevation_pt.md b/lang/base/texts/elevation_pt.md new file mode 100644 index 000000000..9b7254fd7 --- /dev/null +++ b/lang/base/texts/elevation_pt.md @@ -0,0 +1,14 @@ +## Elevação + +O processo de elevação é específico do sistema operativo. + +### Linux e macOS + +Qualquer comando elevado é executado com `sudo`. A senha opcional `sudo` é consultada via XPipe quando necessário. +Tens a capacidade de ajustar o comportamento de elevação nas definições para controlar se queres introduzir a tua palavra-passe sempre que for necessária ou se a queres guardar em cache para a sessão atual. + +### Windows + +No Windows, não é possível elevar um processo filho se o processo pai também não estiver elevado. +Portanto, se o XPipe não for executado como administrador, não poderás utilizar qualquer elevação localmente. +Para ligações remotas, a conta de utilizador ligada tem de ter privilégios de administrador. \ No newline at end of file diff --git a/lang/base/texts/elevation_ru.md b/lang/base/texts/elevation_ru.md new file mode 100644 index 000000000..dfed0b650 --- /dev/null +++ b/lang/base/texts/elevation_ru.md @@ -0,0 +1,14 @@ +## Elevation + +Процесс поднятия зависит от операционной системы. + +### Linux & macOS + +Любая поднятая команда выполняется с `sudo`. Дополнительный пароль `sudo` при необходимости запрашивается через XPipe. +В настройках у тебя есть возможность регулировать поведение возвышения, чтобы контролировать, хочешь ли ты вводить пароль каждый раз, когда он требуется, или же хочешь кэшировать его для текущей сессии. + +### Windows + +В Windows невозможно поднять дочерний процесс, если родительский процесс также не поднят. +Поэтому, если XPipe не запущен от имени администратора, ты не сможешь использовать повышение локально. +Для удаленных подключений подключаемая учетная запись пользователя должна иметь привилегии администратора. \ No newline at end of file diff --git a/lang/base/texts/elevation_tr.md b/lang/base/texts/elevation_tr.md new file mode 100644 index 000000000..488f62438 --- /dev/null +++ b/lang/base/texts/elevation_tr.md @@ -0,0 +1,14 @@ +## Ykseklik + +Ykseltme i?lemi i?letim sistemine zgdr. + +### Linux ve macOS + +Herhangi bir ykseltilmi? komut `sudo` ile yrtlr. ?ste?e ba?l? `sudo` parolas? gerekti?inde XPipe arac?l???yla sorgulan?r. +Parolan?za her ihtiya duyuldu?unda girmek isteyip istemedi?inizi veya mevcut oturum iin nbelle?e almak isteyip istemedi?inizi kontrol etmek iin ayarlarda ykseltme davran???n? ayarlama olana??na sahipsiniz. + +### Windows + +Windows'ta, st sre de ykseltilmemi?se bir alt sreci ykseltmek mmkn de?ildir. +Bu nedenle, XPipe ynetici olarak al??t?r?lmazsa, yerel olarak herhangi bir ykseltme kullanamazs?n?z. +Uzak ba?lant?lar iin, ba?l? kullan?c? hesab?na ynetici ayr?cal?klar? verilmelidir. \ No newline at end of file diff --git a/lang/base/texts/elevation_zh.md b/lang/base/texts/elevation_zh.md new file mode 100644 index 000000000..6a78b81ec --- /dev/null +++ b/lang/base/texts/elevation_zh.md @@ -0,0 +1,14 @@ +## 升高 + +提升过程与操作系统有关。 + +### Linux 和 macOS + +任何升级命令都使用 `sudo` 执行。需要时,会通过 XPipe 查询可选的 `sudo` 密码。 +您可以在设置中调整提升行为,以控制是每次需要时都输入密码,还是为当前会话缓存密码。 + +### 窗口 + +在 Windows 中,如果父进程未提升,则无法提升子进程。 +因此,如果 XPipe 不是以管理员身份运行,就无法在本地使用任何提升。 +对于远程连接,所连接的用户账户必须具有管理员权限。 \ No newline at end of file diff --git a/lang/base/texts/executionType_de.md b/lang/base/texts/executionType_de.md new file mode 100644 index 000000000..45b36bcfc --- /dev/null +++ b/lang/base/texts/executionType_de.md @@ -0,0 +1,15 @@ +## Ausführungsarten + +Es gibt zwei verschiedene Ausführungsarten, wenn XPipe eine Verbindung zu einem System herstellt. + +### Im Hintergrund + +Die erste Verbindung zu einem System wird im Hintergrund in einer stummen Terminalsitzung hergestellt. + +Blockierende Befehle, die Benutzereingaben erfordern, können den Shell-Prozess einfrieren, wenn XPipe ihn intern zuerst im Hintergrund startet. Um dies zu vermeiden, solltest du diese blockierenden Befehle nur im Terminalmodus aufrufen. + +Der Dateibrowser z. B. verwendet für seine Operationen ausschließlich den dummen Hintergrundmodus. Wenn du also möchtest, dass deine Skriptumgebung für die Dateibrowser-Sitzung gilt, sollte sie im dummen Modus ausgeführt werden. + +### In den Terminals + +Nachdem die anfängliche Dumb-Terminal-Verbindung erfolgreich war, öffnet XPipe eine separate Verbindung im eigentlichen Terminal. Wenn du möchtest, dass das Skript ausgeführt wird, wenn du die Verbindung in einem Terminal öffnest, dann wähle den Terminalmodus. diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/executionType_en.md b/lang/base/texts/executionType_en.md similarity index 56% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/executionType_en.md rename to lang/base/texts/executionType_en.md index 185b08e88..68e77d4b7 100644 --- a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/executionType_en.md +++ b/lang/base/texts/executionType_en.md @@ -2,16 +2,14 @@ There are two distinct execution types when XPipe connects to a system. -### Dumb terminals +### In the background -The first connection to a system is made in the background in a dumb terminal. +The first connection to a system is made in the background in a dumb terminal session. -Blocking commands that require user input can freeze the shell process when XPipe starts it up internally first in the background. -To avoid this, you should only call these blocking commands in the terminal mode. +Blocking commands that require user input can freeze the shell process when XPipe starts it up internally first in the background. To avoid this, you should only call these blocking commands in the terminal mode. The file browser for example entirely uses the dumb background mode to handle its operations, so if you want your script environment to apply to the file browser session, it should run in the dumb mode. -### Proper terminals +### In the terminals -After a dumb terminal connection has succeeded, XPipe will open a separate connection in the actual terminal. -If you want the script to be run when you open the connection in a terminal, then choose the terminal mode. +After the initial dumb terminal connection has succeeded, XPipe will open a separate connection in the actual terminal. If you want the script to be run when you open the connection in a terminal, then choose the terminal mode. diff --git a/lang/base/texts/executionType_es.md b/lang/base/texts/executionType_es.md new file mode 100644 index 000000000..945fb99c2 --- /dev/null +++ b/lang/base/texts/executionType_es.md @@ -0,0 +1,15 @@ +## Tipos de ejecución + +Hay dos tipos de ejecución distintos cuando XPipe se conecta a un sistema. + +### En segundo plano + +La primera conexión a un sistema se realiza en segundo plano en una sesión de terminal tonta. + +Los comandos de bloqueo que requieren la entrada del usuario pueden congelar el proceso shell cuando XPipe lo inicia internamente por primera vez en segundo plano. Para evitarlo, sólo debes llamar a estos comandos de bloqueo en el modo terminal. + +El explorador de archivos, por ejemplo, utiliza enteramente el modo mudo en segundo plano para manejar sus operaciones, así que si quieres que tu entorno de script se aplique a la sesión del explorador de archivos, debe ejecutarse en el modo mudo. + +### En los terminales + +Después de que la conexión inicial de terminal mudo haya tenido éxito, XPipe abrirá una conexión separada en el terminal real. Si quieres que el script se ejecute al abrir la conexión en un terminal, elige el modo terminal. diff --git a/lang/base/texts/executionType_fr.md b/lang/base/texts/executionType_fr.md new file mode 100644 index 000000000..0a502bb3a --- /dev/null +++ b/lang/base/texts/executionType_fr.md @@ -0,0 +1,15 @@ +## Types d'exécution + +Il existe deux types d'exécution distincts lorsque XPipe se connecte à un système. + +### En arrière-plan + +La première connexion à un système est effectuée en arrière-plan dans une session de terminal muet. + +Les commandes de blocage qui nécessitent une entrée de la part de l'utilisateur peuvent geler le processus de l'interpréteur de commandes lorsque XPipe le démarre d'abord en interne en arrière-plan. Pour éviter cela, tu ne dois appeler ces commandes bloquantes qu'en mode terminal. + +Le navigateur de fichiers, par exemple, utilise entièrement le mode d'arrière-plan muet pour gérer ses opérations, donc si tu veux que l'environnement de ton script s'applique à la session du navigateur de fichiers, il doit s'exécuter en mode muet. + +### Dans les terminaux + +Une fois que la connexion initiale au terminal muet a réussi, XPipe ouvre une connexion séparée dans le terminal réel. Si tu veux que le script soit exécuté lorsque tu ouvres la connexion dans un terminal, choisis le mode terminal. diff --git a/lang/base/texts/executionType_it.md b/lang/base/texts/executionType_it.md new file mode 100644 index 000000000..1254010e6 --- /dev/null +++ b/lang/base/texts/executionType_it.md @@ -0,0 +1,15 @@ +## Tipi di esecuzione + +Esistono due tipi di esecuzione distinti quando XPipe si connette a un sistema. + +### In background + +La prima connessione a un sistema avviene in background in una sessione di terminale muta. + +I comandi di blocco che richiedono l'input dell'utente possono bloccare il processo di shell quando XPipe lo avvia internamente in background. Per evitare questo problema, dovresti chiamare questi comandi di blocco solo in modalità terminale. + +Il navigatore di file, ad esempio, utilizza esclusivamente la modalità di sfondo muta per gestire le sue operazioni, quindi se vuoi che il tuo ambiente di script si applichi alla sessione del navigatore di file, deve essere eseguito in modalità muta. + +### Nei terminali + +Dopo che la connessione iniziale del terminale muto è riuscita, XPipe aprirà una connessione separata nel terminale vero e proprio. Se vuoi che lo script venga eseguito quando apri la connessione in un terminale, scegli la modalità terminale. diff --git a/lang/base/texts/executionType_ja.md b/lang/base/texts/executionType_ja.md new file mode 100644 index 000000000..4838ec548 --- /dev/null +++ b/lang/base/texts/executionType_ja.md @@ -0,0 +1,15 @@ +## 実行タイプ + +XPipeがシステムに接続する際、2種類の実行タイプがある。 + +### バックグラウンド + +システムへの最初の接続は、ダム端末セッションでバックグラウンドで行われる。 + +ユーザー入力を必要とするブロックコマンドは、XPipeがバックグラウンドで最初にシェルプロセスを内部的に起動する際に、シェルプロセスをフリーズさせる可能性がある。これを避けるため、これらのブロックコマンドはターミナルモードでのみ呼び出すべきである。 + +例えばファイルブラウザは完全にダムバックグラウンドモードを使用して操作を処理するため、スクリプト環境をファイルブラウザセッションに適用したい場合は、ダムモードで実行する必要がある。 + +### ターミナルでは + +最初のダムターミナル接続が成功すると、XPipeは実際のターミナルで別の接続を開く。ターミナルで接続を開いたときにスクリプトを実行させたい場合は、ターミナルモードを選択する。 diff --git a/lang/base/texts/executionType_nl.md b/lang/base/texts/executionType_nl.md new file mode 100644 index 000000000..505384329 --- /dev/null +++ b/lang/base/texts/executionType_nl.md @@ -0,0 +1,15 @@ +## Uitvoeringstypes + +Er zijn twee verschillende uitvoeringstypen wanneer XPipe verbinding maakt met een systeem. + +### Op de achtergrond + +De eerste verbinding met een systeem wordt op de achtergrond gemaakt in een domme terminal sessie. + +Blokkerende commando's die gebruikersinvoer vereisen kunnen het shell proces bevriezen wanneer XPipe het eerst intern op de achtergrond opstart. Om dit te voorkomen, moet je deze blokkerende commando's alleen in de terminalmodus aanroepen. + +De bestandsbrowser bijvoorbeeld gebruikt volledig de domme achtergrondmodus om zijn bewerkingen af te handelen, dus als je wilt dat je scriptomgeving van toepassing is op de bestandsbrowsersessie, moet deze in de domme modus draaien. + +### In de terminals + +Nadat de initiële domme terminalverbinding is gelukt, opent XPipe een aparte verbinding in de echte terminal. Als je wilt dat het script wordt uitgevoerd wanneer je de verbinding in een terminal opent, kies dan de terminalmodus. diff --git a/lang/base/texts/executionType_pt.md b/lang/base/texts/executionType_pt.md new file mode 100644 index 000000000..a04bf5158 --- /dev/null +++ b/lang/base/texts/executionType_pt.md @@ -0,0 +1,15 @@ +## Tipos de execução + +Existem dois tipos de execução distintos quando o XPipe se liga a um sistema. + +### Em segundo plano + +A primeira conexão com um sistema é feita em segundo plano em uma sessão de terminal burro. + +Os comandos de bloqueio que requerem a entrada do usuário podem congelar o processo do shell quando o XPipe o inicia internamente primeiro em segundo plano. Para evitar isso, só deves chamar estes comandos de bloqueio no modo terminal. + +O navegador de ficheiros, por exemplo, utiliza inteiramente o modo de fundo burro para tratar das suas operações, por isso, se quiseres que o teu ambiente de script se aplique à sessão do navegador de ficheiros, deve ser executado no modo burro. + +### Nos terminais + +Depois que a conexão inicial do terminal burro for bem-sucedida, o XPipe abrirá uma conexão separada no terminal real. Se quiseres que o script seja executado quando abrires a ligação num terminal, então escolhe o modo terminal. diff --git a/lang/base/texts/executionType_ru.md b/lang/base/texts/executionType_ru.md new file mode 100644 index 000000000..f7ff4fb01 --- /dev/null +++ b/lang/base/texts/executionType_ru.md @@ -0,0 +1,15 @@ +## Типы исполнения + +Есть два разных типа исполнения, когда XPipe подключается к системе. + +### В фоновом режиме + +Первое подключение к системе происходит в фоновом режиме в тупой терминальной сессии. + +Блокирующие команды, требующие пользовательского ввода, могут заморозить процесс оболочки, когда XPipe запускает его сначала внутри системы в фоновом режиме. Чтобы этого избежать, вызывай эти блокирующие команды только в терминальном режиме. + +Например, файловый браузер полностью использует немой фоновый режим для обработки своих операций, поэтому, если ты хочешь, чтобы окружение твоего скрипта применялось к сессии файлового браузера, он должен запускаться в немом режиме. + +### В терминалах + +После того как первоначальное подключение к тупому терминалу прошло успешно, XPipe откроет отдельное соединение в реальном терминале. Если ты хочешь, чтобы скрипт запускался при открытии соединения в терминале, то выбирай терминальный режим. diff --git a/lang/base/texts/executionType_tr.md b/lang/base/texts/executionType_tr.md new file mode 100644 index 000000000..fd1b19c29 --- /dev/null +++ b/lang/base/texts/executionType_tr.md @@ -0,0 +1,15 @@ +## Yrtme trleri + +XPipe bir sisteme ba?land???nda iki farkl? yrtme tr vard?r. + +### Arka planda + +Bir sisteme ilk ba?lant? arka planda bir aptal terminal oturumunda yap?l?r. + +Kullan?c? giri?i gerektiren engelleme komutlar?, XPipe arka planda ilk olarak dahili olarak ba?lat?ld???nda kabuk srecini dondurabilir. Bunu nlemek iin, bu engelleme komutlar?n? yaln?zca terminal modunda a??rmal?s?n?z. + +rne?in dosya taray?c?s?, i?lemlerini gerekle?tirmek iin tamamen dilsiz arka plan modunu kullan?r; bu nedenle, kod ortam?n?z?n dosya taray?c?s? oturumuna uygulanmas?n? istiyorsan?z, dilsiz modda al??mas? gerekir. + +### Terminallerde + +?lk dumb terminal ba?lant?s? ba?ar?l? olduktan sonra, XPipe gerek terminalde ayr? bir ba?lant? aacakt?r. Ba?lant?y? bir terminalde at???n?zda komut dosyas?n?n al??t?r?lmas?n? istiyorsan?z, terminal modunu sein. diff --git a/lang/base/texts/executionType_zh.md b/lang/base/texts/executionType_zh.md new file mode 100644 index 000000000..a223fd8ef --- /dev/null +++ b/lang/base/texts/executionType_zh.md @@ -0,0 +1,15 @@ +## 执行类型 + +XPipe 连接到系统时有两种不同的执行类型。 + +### 在后台 + +与系统的首次连接是在后台的哑终端会话中进行的。 + +当 XPipe 首先在后台内部启动 shell 进程时,需要用户输入的阻塞命令会冻结 shell 进程。为避免出现这种情况,只能在终端模式下调用这些阻塞命令。 + +例如,文件浏览器完全使用哑模式后台处理其操作,因此如果您希望脚本环境适用于文件浏览器会话,则应在哑模式下运行。 + +### 在终端中 + +初始哑终端连接成功后,XPipe 将在实际终端中打开一个单独的连接。如果您希望在终端打开连接时运行脚本,那么请选择终端模式。 diff --git a/lang/base/texts/scriptCompatibility_de.md b/lang/base/texts/scriptCompatibility_de.md new file mode 100644 index 000000000..bd8bc5707 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_de.md @@ -0,0 +1,13 @@ +## Skript-Kompatibilität + +Der Shell-Typ bestimmt, wo das Skript ausgeführt werden kann. +Abgesehen von einer exakten Übereinstimmung, d.h. der Ausführung eines `zsh`-Skripts in `zsh`, führt XPipe auch eine breitere Kompatibilitätsprüfung durch. + +### Posix-Shells + +Jedes Skript, das als `sh`-Skript deklariert ist, kann in jeder Posix-Shell-Umgebung wie `bash` oder `zsh` ausgeführt werden. +Wenn du ein grundlegendes Skript auf vielen verschiedenen Systemen ausführen willst, ist die Verwendung von Skripten mit `sh`-Syntax die beste Lösung dafür. + +### PowerShell + +Skripte, die als normale `powershell`-Skripte deklariert sind, können auch in `pwsh`-Umgebungen ausgeführt werden. diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/scriptCompatibility_en.md b/lang/base/texts/scriptCompatibility_en.md similarity index 82% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/scriptCompatibility_en.md rename to lang/base/texts/scriptCompatibility_en.md index 80bcdc2d7..9509de303 100644 --- a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/scriptCompatibility_en.md +++ b/lang/base/texts/scriptCompatibility_en.md @@ -10,4 +10,4 @@ If you intend to run a basic script on many different systems, then using only ` ### PowerShell -Scripts declared as normal PowerShell scripts are also able to run in PowerShell Core environments. +Scripts declared as normal `powershell` scripts are also able to run in `pwsh` environments. diff --git a/lang/base/texts/scriptCompatibility_es.md b/lang/base/texts/scriptCompatibility_es.md new file mode 100644 index 000000000..573f047ed --- /dev/null +++ b/lang/base/texts/scriptCompatibility_es.md @@ -0,0 +1,13 @@ +## Compatibilidad con guiones + +El tipo de shell controla dónde se puede ejecutar este script. +Aparte de una coincidencia exacta, es decir, ejecutar un script `zsh` en `zsh`, XPipe también incluirá una comprobación de compatibilidad más amplia. + +### Shell Posix + +Cualquier script declarado como script `sh` puede ejecutarse en cualquier entorno shell relacionado con posix, como `bash` o `zsh`. +Si pretendes ejecutar un script básico en muchos sistemas distintos, la mejor solución es utilizar sólo scripts de sintaxis `sh`. + +### PowerShell + +Los scripts declarados como scripts `powershell` normales también pueden ejecutarse en entornos `pwsh`. diff --git a/lang/base/texts/scriptCompatibility_fr.md b/lang/base/texts/scriptCompatibility_fr.md new file mode 100644 index 000000000..9e8c583e4 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_fr.md @@ -0,0 +1,13 @@ +## Compatibilité des scripts + +Le type de shell contrôle l'endroit où ce script peut être exécuté. +Outre une correspondance exacte, c'est-à-dire l'exécution d'un script `zsh` dans `zsh`, XPipe inclura également une vérification plus large de la compatibilité. + +### Shells Posix + +Tout script déclaré comme un script `sh` est capable de s'exécuter dans n'importe quel environnement shell lié à Posix, tel que `bash` ou `zsh`. +Si tu as l'intention d'exécuter un script de base sur de nombreux systèmes différents, utiliser uniquement des scripts de syntaxe `sh` est la meilleure solution pour cela. + +### PowerShell + +Les scripts déclarés comme des scripts `powershell` normaux sont également capables de s'exécuter dans des environnements `pwsh`. diff --git a/lang/base/texts/scriptCompatibility_it.md b/lang/base/texts/scriptCompatibility_it.md new file mode 100644 index 000000000..e048f7589 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_it.md @@ -0,0 +1,13 @@ +## Compatibilità con gli script + +Il tipo di shell controlla dove questo script può essere eseguito. +Oltre alla corrispondenza esatta, cioè all'esecuzione di uno script `zsh` in `zsh`, XPipe include anche un controllo di compatibilità più ampio. + +### Gusci Posix + +Qualsiasi script dichiarato come script `sh` è in grado di essere eseguito in qualsiasi ambiente shell posix come `bash` o `zsh`. +Se intendi eseguire uno script di base su molti sistemi diversi, allora utilizzare solo script con sintassi `sh` è la soluzione migliore. + +### PowerShell + +Gli script dichiarati come normali script `powershell` possono essere eseguiti anche in ambienti `pwsh`. diff --git a/lang/base/texts/scriptCompatibility_ja.md b/lang/base/texts/scriptCompatibility_ja.md new file mode 100644 index 000000000..970fba4b5 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_ja.md @@ -0,0 +1,13 @@ +## スクリプトの互換性 + +シェルタイプは、このスクリプトを実行できる場所を制御する。 +完全一致、つまり`zsh`スクリプトを`zsh`で実行する以外に、XPipeはより広い互換性チェックを含む。 + +### Posix シェル + +`sh` スクリプトとして宣言されたスクリプトは、`bash` や `zsh` のような posix 関連のシェル環境で実行できる。 +基本的なスクリプトを多くの異なるシステムで実行するつもりなら、`sh`構文のスクリプトだけを使うのが最適な解決策である。 + +### パワーシェル + +通常の`powershell`スクリプトとして宣言されたスクリプトは、`pwsh`環境でも実行できる。 diff --git a/lang/base/texts/scriptCompatibility_nl.md b/lang/base/texts/scriptCompatibility_nl.md new file mode 100644 index 000000000..e15273de0 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_nl.md @@ -0,0 +1,13 @@ +## Script compatibiliteit + +Het shelltype bepaalt waar dit script kan worden uitgevoerd. +Naast een exacte overeenkomst, d.w.z. het uitvoeren van een `zsh` script in `zsh`, zal XPipe ook bredere compatibiliteitscontroles uitvoeren. + +### Posix Shells + +Elk script dat is gedeclareerd als een `sh` script kan worden uitgevoerd in elke posix-gerelateerde shell-omgeving zoals `bash` of `zsh`. +Als je van plan bent om een basisscript op veel verschillende systemen te draaien, dan is het gebruik van alleen `sh` syntax scripts de beste oplossing. + +### PowerShell + +Scripts die zijn gedeclareerd als normale `powershell` scripts kunnen ook worden uitgevoerd in `pwsh` omgevingen. diff --git a/lang/base/texts/scriptCompatibility_pt.md b/lang/base/texts/scriptCompatibility_pt.md new file mode 100644 index 000000000..df4b0124f --- /dev/null +++ b/lang/base/texts/scriptCompatibility_pt.md @@ -0,0 +1,13 @@ +## Compatibilidade de scripts + +O tipo de shell controla onde este script pode ser executado. +Além de uma correspondência exata, ou seja, executar um script `zsh` em `zsh`, o XPipe também incluirá uma verificação de compatibilidade mais ampla. + +### Shells Posix + +Qualquer script declarado como um script `sh` pode ser executado em qualquer ambiente shell relacionado ao posix, como `bash` ou `zsh`. +Se pretendes correr um script básico em muitos sistemas diferentes, então usar apenas scripts com sintaxe `sh` é a melhor solução para isso. + +### PowerShell + +Os scripts declarados como scripts `powershell` normais também podem ser executados em ambientes `pwsh`. diff --git a/lang/base/texts/scriptCompatibility_ru.md b/lang/base/texts/scriptCompatibility_ru.md new file mode 100644 index 000000000..07b4c7ce2 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_ru.md @@ -0,0 +1,13 @@ +## Совместимость сценариев + +Тип оболочки управляет тем, где этот скрипт может быть запущен. +Помимо точного совпадения, то есть запуска `zsh` скрипта в `zsh`, XPipe также включает более широкую проверку совместимости. + +### Posix Shells + +Любой скрипт, объявленный как `sh`, может быть запущен в любой среде posix-оболочки, такой как `bash` или `zsh`. +Если ты собираешься запускать основной скрипт на множестве различных систем, то использование только скриптов с синтаксисом `sh` - лучшее решение для этого. + +### PowerShell + +Скрипты, объявленные как обычные скрипты `powershell`, также могут выполняться в окружении `pwsh`. diff --git a/lang/base/texts/scriptCompatibility_tr.md b/lang/base/texts/scriptCompatibility_tr.md new file mode 100644 index 000000000..66a2f2d8e --- /dev/null +++ b/lang/base/texts/scriptCompatibility_tr.md @@ -0,0 +1,13 @@ +## Komut dosyas? uyumlulu?u + +Kabuk tr bu beti?in nerede al??t?r?labilece?ini kontrol eder. +Tam e?le?menin yan? s?ra, yani `zsh` beti?ini `zsh` iinde al??t?rman?n yan? s?ra, XPipe daha geni? bir uyumluluk denetimi de ierecektir. + +### Posix Kabuklar? + +`sh` beti?i olarak bildirilen herhangi bir betik, `bash` veya `zsh` gibi posix ile ilgili herhangi bir kabuk ortam?nda al??abilir. +Temel bir beti?i birok farkl? sistemde al??t?rmay? d?nyorsan?z, yaln?zca `sh` szdizimi betiklerini kullanmak bunun iin en iyi zmdr. + +### PowerShell + +Normal `powershell` komut dosyalar? olarak bildirilen komut dosyalar? `pwsh` ortamlar?nda da al??abilir. diff --git a/lang/base/texts/scriptCompatibility_zh.md b/lang/base/texts/scriptCompatibility_zh.md new file mode 100644 index 000000000..1cc5e7291 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_zh.md @@ -0,0 +1,13 @@ +## 脚本兼容性 + +shell 类型控制着脚本的运行位置。 +除了完全匹配(即在 `zsh` 中运行 `zsh` 脚本)外,XPipe 还将进行更广泛的兼容性检查。 + +### Posix Shells + +任何声明为 `sh` 脚本的脚本都可以在任何与 Posix 相关的 shell 环境(如 `bash` 或 `zsh` 中运行。 +如果您打算在许多不同的系统上运行一个基本脚本,那么只使用 `sh` 语法的脚本是最好的解决方案。 + +#### PowerShell + +声明为普通 `powershell` 脚本的脚本也可以在 `pwsh` 环境中运行。 diff --git a/lang/base/texts/scriptDependencies_de.md b/lang/base/texts/scriptDependencies_de.md new file mode 100644 index 000000000..1f3c8bf97 --- /dev/null +++ b/lang/base/texts/scriptDependencies_de.md @@ -0,0 +1,5 @@ +## Skriptabhängigkeiten + +Die Skripte und Skriptgruppen, die zuerst ausgeführt werden sollen. Wenn eine ganze Gruppe zu einer Abhängigkeit gemacht wird, werden alle Skripte in dieser Gruppe als Abhängigkeiten betrachtet. + +Der aufgelöste Abhängigkeitsgraph von Skripten wird abgeflacht, gefiltert und eindeutig gemacht. D.h. es werden nur kompatible Skripte ausgeführt und wenn ein Skript mehrmals ausgeführt werden würde, wird es nur beim ersten Mal ausgeführt. diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/scriptDependencies_en.md b/lang/base/texts/scriptDependencies_en.md similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/scriptDependencies_en.md rename to lang/base/texts/scriptDependencies_en.md diff --git a/lang/base/texts/scriptDependencies_es.md b/lang/base/texts/scriptDependencies_es.md new file mode 100644 index 000000000..a00ff6fc6 --- /dev/null +++ b/lang/base/texts/scriptDependencies_es.md @@ -0,0 +1,5 @@ +## Dependencias del script + +Los scripts y grupos de scripts que deben ejecutarse primero. Si un grupo entero se convierte en dependencia, todos los scripts de este grupo se considerarán dependencias. + +El gráfico de dependencia resuelto de los scripts se aplana, se filtra y se hace único. Es decir, sólo se ejecutarán los scripts compatibles y si un script se ejecutara varias veces, sólo se ejecutará la primera vez. diff --git a/lang/base/texts/scriptDependencies_fr.md b/lang/base/texts/scriptDependencies_fr.md new file mode 100644 index 000000000..336826fff --- /dev/null +++ b/lang/base/texts/scriptDependencies_fr.md @@ -0,0 +1,5 @@ +## Dépendances du script + +Les scripts et les groupes de scripts à exécuter en premier. Si un groupe entier devient une dépendance, tous les scripts de ce groupe seront considérés comme des dépendances. + +Le graphe de dépendance résolu des scripts est aplati, filtré et rendu unique. C'est-à-dire que seuls les scripts compatibles seront exécutés et que si un script devait être exécuté plusieurs fois, il ne sera exécuté que la première fois. diff --git a/lang/base/texts/scriptDependencies_it.md b/lang/base/texts/scriptDependencies_it.md new file mode 100644 index 000000000..90ad9ea17 --- /dev/null +++ b/lang/base/texts/scriptDependencies_it.md @@ -0,0 +1,5 @@ +## Dipendenze degli script + +Gli script e i gruppi di script da eseguire per primi. Se un intero gruppo viene reso una dipendenza, tutti gli script di questo gruppo verranno considerati come dipendenze. + +Il grafico delle dipendenze degli script viene appiattito, filtrato e reso unico. In altre parole, verranno eseguiti solo gli script compatibili e se uno script verrà eseguito più volte, verrà eseguito solo la prima volta. diff --git a/lang/base/texts/scriptDependencies_ja.md b/lang/base/texts/scriptDependencies_ja.md new file mode 100644 index 000000000..57568158d --- /dev/null +++ b/lang/base/texts/scriptDependencies_ja.md @@ -0,0 +1,5 @@ +## スクリプトの依存関係 + +最初に実行するスクリプトとスクリプトグループ。あるグループ全体を依存関係にした場合、そのグループに含まれる すべてのスクリプトが依存関係とみなされる。 + +解決されたスクリプトの依存グラフは、平坦化され、フィルタリングされ、一意になる。つまり、互換性のあるスクリプトだけが実行され、スクリプトが複数回実行される場合は、最初の1回だけが実行される。 diff --git a/lang/base/texts/scriptDependencies_nl.md b/lang/base/texts/scriptDependencies_nl.md new file mode 100644 index 000000000..dae6d2afc --- /dev/null +++ b/lang/base/texts/scriptDependencies_nl.md @@ -0,0 +1,5 @@ +## Script afhankelijkheden + +De scripts en scriptgroepen die als eerste moeten worden uitgevoerd. Als van een hele groep een afhankelijkheid wordt gemaakt, worden alle scripts in deze groep beschouwd als afhankelijkheden. + +De opgeloste afhankelijkheidsgrafiek van scripts wordt afgevlakt, gefilterd en uniek gemaakt. Alleen compatibele scripts worden uitgevoerd en als een script meerdere keren wordt uitgevoerd, wordt het alleen de eerste keer uitgevoerd. diff --git a/lang/base/texts/scriptDependencies_pt.md b/lang/base/texts/scriptDependencies_pt.md new file mode 100644 index 000000000..4bdf03c33 --- /dev/null +++ b/lang/base/texts/scriptDependencies_pt.md @@ -0,0 +1,5 @@ +## Dependências do script + +Os scripts e grupos de scripts a serem executados primeiro. Se um grupo inteiro se tornar uma dependência, todos os scripts desse grupo serão considerados como dependências. + +O gráfico de dependência resolvido dos scripts é achatado, filtrado e tornado único. Ou seja, apenas os scripts compatíveis serão executados e, se um script for executado várias vezes, só será executado na primeira vez. diff --git a/lang/base/texts/scriptDependencies_ru.md b/lang/base/texts/scriptDependencies_ru.md new file mode 100644 index 000000000..0262dae27 --- /dev/null +++ b/lang/base/texts/scriptDependencies_ru.md @@ -0,0 +1,5 @@ +## Зависимости от сценария + +Скрипты и группы скриптов, которые нужно запускать в первую очередь. Если всю группу сделать зависимой, то все скрипты в этой группе будут считаться зависимыми. + +Граф разрешенных зависимостей скриптов сплющивается, фильтруется и становится уникальным. То есть будут запускаться только совместимые скрипты, а если скрипт будет выполняться несколько раз, то он будет запущен только в первый раз. diff --git a/lang/base/texts/scriptDependencies_tr.md b/lang/base/texts/scriptDependencies_tr.md new file mode 100644 index 000000000..2b9eb2616 --- /dev/null +++ b/lang/base/texts/scriptDependencies_tr.md @@ -0,0 +1,5 @@ +## Betik ba??ml?l?klar? + +nce al??t?r?lacak komut dosyalar? ve komut dosyas? gruplar?. Bir grubun tamam? ba??ml?l?k haline getirilirse, bu gruptaki tm komut dosyalar? ba??ml?l?k olarak kabul edilecektir. + +Komut dosyalar?n?n zmlenmi? ba??ml?l?k grafi?i dzle?tirilir, filtrelenir ve benzersiz hale getirilir. Yani, yaln?zca uyumlu komut dosyalar? al??t?r?lacak ve bir komut dosyas? birden ok kez al??t?r?lacaksa, yaln?zca ilk seferde al??t?r?lacakt?r. diff --git a/lang/base/texts/scriptDependencies_zh.md b/lang/base/texts/scriptDependencies_zh.md new file mode 100644 index 000000000..c0d00cc7c --- /dev/null +++ b/lang/base/texts/scriptDependencies_zh.md @@ -0,0 +1,5 @@ +## 脚本依赖 + +首先运行的脚本和脚本组。如果将整个组作为依赖项,则该组中的所有脚本都将被视为依赖项。 + +解析后的脚本依赖关系图将被扁平化、过滤并变得唯一。也就是说,只有兼容的脚本才会被运行,如果一个脚本会被执行多次,那么它只会在第一次被运行。 diff --git a/lang/base/texts/script_de.md b/lang/base/texts/script_de.md new file mode 100644 index 000000000..7793b812d --- /dev/null +++ b/lang/base/texts/script_de.md @@ -0,0 +1,5 @@ +## Skriptinhalt + +Der Inhalt des Skripts, das ausgeführt werden soll. Du kannst ihn entweder direkt bearbeiten oder die Schaltfläche "Externe Bearbeitung" in der oberen rechten Ecke verwenden, um einen externen Texteditor zu starten. + +Bei Shells, die dies unterstützen, musst du keine Shebang-Zeile angeben, sie wird automatisch mit dem entsprechenden Shell-Typ hinzugefügt. diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/script_en.md b/lang/base/texts/script_en.md similarity index 100% rename from ext/base/src/main/resources/io/xpipe/ext/base/resources/lang/script_en.md rename to lang/base/texts/script_en.md diff --git a/lang/base/texts/script_es.md b/lang/base/texts/script_es.md new file mode 100644 index 000000000..7d3b92406 --- /dev/null +++ b/lang/base/texts/script_es.md @@ -0,0 +1,5 @@ +## Contenido del guión + +El contenido del script a ejecutar. Puedes elegir editarlo in situ o utilizar el botón de edición externa de la esquina superior derecha para lanzar un editor de texto externo. + +No tienes que especificar una línea shebang para los intérpretes de comandos que lo admitan, se añade una automáticamente con el tipo de intérprete de comandos apropiado. diff --git a/lang/base/texts/script_fr.md b/lang/base/texts/script_fr.md new file mode 100644 index 000000000..636ae2b81 --- /dev/null +++ b/lang/base/texts/script_fr.md @@ -0,0 +1,5 @@ +## Contenu du script + +Le contenu du script à exécuter. Tu peux choisir de le modifier sur place ou d'utiliser le bouton d'édition externe dans le coin supérieur droit pour lancer un éditeur de texte externe. + +Tu n'as pas besoin de spécifier une ligne shebang pour les shells qui la prennent en charge, une ligne est ajoutée automatiquement avec le type de shell approprié. diff --git a/lang/base/texts/script_it.md b/lang/base/texts/script_it.md new file mode 100644 index 000000000..67bc487de --- /dev/null +++ b/lang/base/texts/script_it.md @@ -0,0 +1,5 @@ +## Contenuto dello script + +Il contenuto dello script da eseguire. Puoi scegliere di modificarlo direttamente o di utilizzare il pulsante di modifica esterna nell'angolo in alto a destra per lanciare un editor di testo esterno. + +Non è necessario specificare una riga di shebang per le shell che la supportano: viene aggiunta automaticamente con il tipo di shell appropriato. diff --git a/lang/base/texts/script_ja.md b/lang/base/texts/script_ja.md new file mode 100644 index 000000000..1476c30a8 --- /dev/null +++ b/lang/base/texts/script_ja.md @@ -0,0 +1,5 @@ +## スクリプトの内容 + +実行するスクリプトの内容。インプレースで編集するか、右上の外部編集ボタンを使って外部のテキストエディタを起動するかを選択できる。 + +shebang行をサポートしているシェルでは、shebang行を指定する必要はない。 diff --git a/lang/base/texts/script_nl.md b/lang/base/texts/script_nl.md new file mode 100644 index 000000000..1675137ad --- /dev/null +++ b/lang/base/texts/script_nl.md @@ -0,0 +1,5 @@ +## Scriptinhoud + +De inhoud van het uit te voeren script. Je kunt ervoor kiezen om dit ter plekke te bewerken of om de externe bewerkingsknop in de rechterbovenhoek te gebruiken om een externe teksteditor te starten. + +Je hoeft geen shebang regel op te geven voor shells die dat ondersteunen, er wordt er automatisch een toegevoegd bij het juiste shell type. diff --git a/lang/base/texts/script_pt.md b/lang/base/texts/script_pt.md new file mode 100644 index 000000000..f77bde9c3 --- /dev/null +++ b/lang/base/texts/script_pt.md @@ -0,0 +1,5 @@ +## Conteúdo do guião + +O conteúdo do script a ser executado. Podes optar por editar isto no local ou utilizar o botão de edição externa no canto superior direito para lançar um editor de texto externo. + +Não tens de especificar uma linha shebang para shells que a suportam, uma é adicionada automaticamente com o tipo de shell apropriado. diff --git a/lang/base/texts/script_ru.md b/lang/base/texts/script_ru.md new file mode 100644 index 000000000..662a36e1e --- /dev/null +++ b/lang/base/texts/script_ru.md @@ -0,0 +1,5 @@ +## Содержание сценария + +Содержимое скрипта, который нужно запустить. Ты можешь либо отредактировать его на месте, либо воспользоваться кнопкой внешнего редактирования в правом верхнем углу, чтобы запустить внешний текстовый редактор. + +Тебе не нужно указывать строку shebang для оболочек, которые ее поддерживают, она добавляется автоматически с соответствующим типом оболочки. diff --git a/lang/base/texts/script_tr.md b/lang/base/texts/script_tr.md new file mode 100644 index 000000000..bfbcd303e --- /dev/null +++ b/lang/base/texts/script_tr.md @@ -0,0 +1,5 @@ +## Komut dosyas? ieri?i + +al??t?r?lacak beti?in ieri?i. Bunu yerinde dzenlemeyi seebilir veya harici bir metin dzenleyici ba?latmak iin sa? st k?edeki harici dzenleme d?mesini kullanabilirsiniz. + +Bunu destekleyen kabuklar iin bir shebang sat?r? belirtmeniz gerekmez, uygun kabuk tryle otomatik olarak bir tane eklenir. diff --git a/lang/base/texts/script_zh.md b/lang/base/texts/script_zh.md new file mode 100644 index 000000000..959dfd5b2 --- /dev/null +++ b/lang/base/texts/script_zh.md @@ -0,0 +1,5 @@ +## 脚本内容 + +要运行的脚本内容。您可以选择就地编辑,或使用右上角的外部编辑按钮启动外部文本编辑器。 + +对于支持 Shebang 的 shell,无需指定 Shebang 行,系统会根据相应的 shell 类型自动添加 Shebang 行。 diff --git a/lang/jdbc/strings/translations_de.properties b/lang/jdbc/strings/translations_de.properties new file mode 100644 index 000000000..0b6a263b4 --- /dev/null +++ b/lang/jdbc/strings/translations_de.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Eine psql-Shell für einen PostgreSQL-Server öffnen +query=Abfrage +proxy=Proxy +peerAuth=Peer-Authentifizierung +port=Port +url=URL +instance=Instanz +username=Benutzername +usernameDescription=Der Benutzer, als der man sich anmeldet +password=Passwort +passwordDescription=Das Passwort zur Authentifizierung +authentication=Authentifizierung +authenticationType=Methode +connection=Verbindung +connectionUrl=Verbindungs-URL +connectionString=Verbindungsstring +passwordAuth=Passwort-Authentifizierung +windowsAuth=Windows-Authentifizierung +psqlShell=PSQL-Shell im Terminal öffnen diff --git a/lang/jdbc/strings/translations_en.properties b/lang/jdbc/strings/translations_en.properties new file mode 100644 index 000000000..9998d944b --- /dev/null +++ b/lang/jdbc/strings/translations_en.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Open a psql shell to a PostgreSQL Server +query=Query +proxy=Proxy +peerAuth=Peer Authentication +port=Port +url=URL +instance=Instance +username=Username +usernameDescription=The user to log in as +password=Password +passwordDescription=The password to authenticate +authentication=Authentication +authenticationType=Method +connection=Connection +connectionUrl=Connection URL +connectionString=Connection String +passwordAuth=Password Authentication +windowsAuth=Windows Authentication +psqlShell=Open PSQL Shell in Terminal \ No newline at end of file diff --git a/lang/jdbc/strings/translations_es.properties b/lang/jdbc/strings/translations_es.properties new file mode 100644 index 000000000..091927fe1 --- /dev/null +++ b/lang/jdbc/strings/translations_es.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Abrir un shell psql a un servidor PostgreSQL +query=Consulta +proxy=Proxy +peerAuth=Autenticación por pares +port=Puerto +url=URL +instance=Instancia +username=Nombre de usuario +usernameDescription=El usuario con el que iniciar sesión +password=Contraseña +passwordDescription=La contraseña para autenticar +authentication=Autenticación +authenticationType=Método +connection=Conexión +connectionUrl=URL de conexión +connectionString=Cadena de conexión +passwordAuth=Autenticación por contraseña +windowsAuth=Autenticación de Windows +psqlShell=Abrir PSQL Shell en Terminal diff --git a/lang/jdbc/strings/translations_fr.properties b/lang/jdbc/strings/translations_fr.properties new file mode 100644 index 000000000..2ccb9c259 --- /dev/null +++ b/lang/jdbc/strings/translations_fr.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Ouvrir un shell psql sur un serveur PostgreSQL +query=Requête +proxy=Proxy +peerAuth=Authentification par les pairs +port=Port +url=URL +instance=Instance +username=Nom d'utilisateur +usernameDescription=L'utilisateur à connecter en tant que +password=Mot de passe +passwordDescription=Le mot de passe pour s'authentifier +authentication=Authentification +authenticationType=Méthode +connection=Connexion +connectionUrl=URL de connexion +connectionString=Chaîne de connexion +passwordAuth=Authentification par mot de passe +windowsAuth=Authentification Windows +psqlShell=Ouvrir le shell PSQL dans le terminal diff --git a/lang/jdbc/strings/translations_it.properties b/lang/jdbc/strings/translations_it.properties new file mode 100644 index 000000000..1d508cf60 --- /dev/null +++ b/lang/jdbc/strings/translations_it.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Aprire una shell psql su un server PostgreSQL +query=Query +proxy=Proxy +peerAuth=Autenticazione tra pari +port=Porta +url=URL +instance=Istanza +username=Nome utente +usernameDescription=L'utente con cui accedere +password=Password +passwordDescription=La password per l'autenticazione +authentication=Autenticazione +authenticationType=Metodo +connection=Connessione +connectionUrl=URL di connessione +connectionString=Stringa di connessione +passwordAuth=Autenticazione con password +windowsAuth=Autenticazione di Windows +psqlShell=Aprire la shell PSQL nel terminale diff --git a/lang/jdbc/strings/translations_ja.properties b/lang/jdbc/strings/translations_ja.properties new file mode 100644 index 000000000..42af0d885 --- /dev/null +++ b/lang/jdbc/strings/translations_ja.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=PostgreSQLサーバーにpsqlシェルを開く +query=クエリー +proxy=プロキシ +peerAuth=ピア認証 +port=ポート +url=URL +instance=インスタンス +username=ユーザー名 +usernameDescription=ログインするユーザー +password=パスワード +passwordDescription=認証のためのパスワード +authentication=認証 +authenticationType=方法 +connection=接続 +connectionUrl=接続URL +connectionString=接続文字列 +passwordAuth=パスワード認証 +windowsAuth=Windows認証 +psqlShell=ターミナルで PSQL シェルを開く diff --git a/lang/jdbc/strings/translations_nl.properties b/lang/jdbc/strings/translations_nl.properties new file mode 100644 index 000000000..15a80744f --- /dev/null +++ b/lang/jdbc/strings/translations_nl.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Open een psql-shell naar een PostgreSQL-server +query=Query +proxy=Proxy +peerAuth=Peer Authenticatie +port=Poort +url=URL +instance=Instantie +username=Gebruikersnaam +usernameDescription=De gebruiker om als in te loggen +password=Wachtwoord +passwordDescription=Het wachtwoord voor verificatie +authentication=Authenticatie +authenticationType=Methode +connection=Verbinding +connectionUrl=URL verbinding +connectionString=Verbindingsstring +passwordAuth=Wachtwoordverificatie +windowsAuth=Windows verificatie +psqlShell=Open PSQL Shell in Terminal diff --git a/lang/jdbc/strings/translations_pt.properties b/lang/jdbc/strings/translations_pt.properties new file mode 100644 index 000000000..bc2ab5134 --- /dev/null +++ b/lang/jdbc/strings/translations_pt.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Abre uma shell psql para um servidor PostgreSQL +query=Consulta +proxy=Proxy +peerAuth=Autenticação de pares +port=Porta +url=URL +instance=Instância +username=Nome de utilizador +usernameDescription=O utilizador para iniciar sessão como +password=Palavra-passe +passwordDescription=A palavra-passe para autenticar +authentication=Autenticação +authenticationType=Método +connection=Ligação +connectionUrl=URL de ligação +connectionString=Cadeia de ligação +passwordAuth=Autenticação por palavra-passe +windowsAuth=Autenticação do Windows +psqlShell=Abre o shell PSQL no Terminal diff --git a/lang/jdbc/strings/translations_ru.properties b/lang/jdbc/strings/translations_ru.properties new file mode 100644 index 000000000..0b9f6e48d --- /dev/null +++ b/lang/jdbc/strings/translations_ru.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Откройте оболочку psql для сервера PostgreSQL +query=Запрос +proxy=Прокси +peerAuth=Пиринговая аутентификация +port=Порт +url=URL +instance=Инстанс +username=Имя пользователя +usernameDescription=Пользователь, от имени которого нужно войти в систему +password=Пароль +passwordDescription=Пароль для аутентификации +authentication=Аутентификация +authenticationType=Метод +connection=Соединение +connectionUrl=URL-адрес подключения +connectionString=Строка подключения +passwordAuth=Проверка подлинности пароля +windowsAuth=Аутентификация Windows +psqlShell=Открыть оболочку PSQL в терминале diff --git a/lang/jdbc/strings/translations_tr.properties b/lang/jdbc/strings/translations_tr.properties new file mode 100644 index 000000000..6693dca10 --- /dev/null +++ b/lang/jdbc/strings/translations_tr.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=PostgreSQL Sunucusuna bir psql kabuğu açma +query=Sorgu +proxy=Proxy +peerAuth=Eş Kimlik Doğrulama +port=Liman +url=URL +instance=Örnek +username=Kullanıcı Adı +usernameDescription=Oturum açılacak kullanıcı +password=Şifre +passwordDescription=Kimlik doğrulaması için parola +authentication=Kimlik Doğrulama +authenticationType=Yöntem +connection=Bağlantı +connectionUrl=Bağlantı URL'si +connectionString=Bağlantı Dizesi +passwordAuth=Şifre Doğrulama +windowsAuth=Windows Kimlik Doğrulama +psqlShell=Terminal'de PSQL Kabuğunu Açın diff --git a/lang/jdbc/strings/translations_zh.properties b/lang/jdbc/strings/translations_zh.properties new file mode 100644 index 000000000..b38044227 --- /dev/null +++ b/lang/jdbc/strings/translations_zh.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=为 PostgreSQL 服务器打开 psql shell +query=查询 +proxy=代理 +peerAuth=对等认证 +port=端口 +url=网址 +instance=实例 +username=用户名 +usernameDescription=登录用户 +password=密码 +passwordDescription=验证密码 +authentication=认证 +authenticationType=方法 +connection=连接 +connectionUrl=连接 URL +connectionString=连接字符串 +passwordAuth=密码验证 +windowsAuth=Windows 身份验证 +psqlShell=在终端中打开 PSQL Shell diff --git a/lang/proc/strings/translations_de.properties b/lang/proc/strings/translations_de.properties new file mode 100644 index 000000000..a6ce69122 --- /dev/null +++ b/lang/proc/strings/translations_de.properties @@ -0,0 +1,299 @@ +showInternalPods=Interne Pods anzeigen +showAllNamespaces=Alle Namespaces anzeigen +showInternalContainers=Interne Container anzeigen +refresh=Aktualisieren +vmwareGui=GUI starten +monitorVm=VM überwachen +addCluster=Cluster hinzufügen ... +showNonRunningInstances=Nicht laufende Instanzen anzeigen +vmwareGuiDescription=Ob eine virtuelle Maschine im Hintergrund oder in einem Fenster gestartet werden soll. +vmwareEncryptionPassword=Verschlüsselungspasswort +vmwareEncryptionPasswordDescription=Das optionale Passwort, das zur Verschlüsselung der VM verwendet wird. +vmwarePasswordDescription=Das erforderliche Passwort für den Gastbenutzer. +vmwarePassword=Benutzer-Passwort +vmwareUser=Gast-Benutzer +runTempContainer=Temporärer Container ausführen +vmwareUserDescription=Der Benutzername deines primären Gastbenutzers +dockerTempRunAlertTitle=Temporärer Container ausführen +dockerTempRunAlertHeader=Damit wird ein Shell-Prozess in einem temporären Container ausgeführt, der automatisch entfernt wird, sobald er gestoppt wird. +imageName=Bildname +imageNameDescription=Die zu verwendende Kennung des Containerbildes +containerName=Container-Name +containerNameDescription=Der optionale benutzerdefinierte Containername +vm=Virtuelle Maschine +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Die zugehörige Konfigurationsdatei. +vmwareScan=VMware Desktop-Hypervisoren +library=Bibliothek +customPkcs11Library=Benutzerdefinierte PKCS#11-Bibliothek (Pro) +vmwareMachine.displayName=VMware Virtuelle Maschine +vmwareMachine.displayDescription=Verbindung zu einer virtuellen Maschine über SSH +vmwareInstallation.displayName=VMware Desktop Hypervisor Installation +vmwareInstallation.displayDescription=Interaktion mit den installierten VMs über deren CLI +start=Start +stop=Stopp +pause=Pause +rdpTunnelHost=Tunnel-Host +rdpTunnelHostDescription=Die optionale SSH-Verbindung, die als Tunnel verwendet wird +rdpFileLocation=Dateispeicherort +rdpFileLocationDescription=Der Dateipfad der .rdp-Datei +rdpPasswordAuthentication=Passwort-Authentifizierung +rdpPasswordAuthenticationDescription=Das Passwort, das automatisch ausgefüllt wird, wenn es unterstützt wird +rdpFile.displayName=RDP-Datei +rdpFile.displayDescription=Verbindung zu einem System über eine bestehende .rdp-Datei +requiredSshServerAlertTitle=SSH-Server einrichten +requiredSshServerAlertHeader=Es kann kein installierter SSH-Server in der VM gefunden werden. +requiredSshServerAlertContent=Um sich mit der VM zu verbinden, sucht XPipe nach einem laufenden SSH-Server, aber es wurde kein verfügbarer SSH-Server für die VM gefunden. +computerName=Computer Name +pssComputerNameDescription=Der Computername, zu dem eine Verbindung hergestellt werden soll. Es wird angenommen, dass er bereits in deinen vertrauenswürdigen Hosts enthalten ist. +credentialUser=Berechtigungsnachweis Benutzer +pssCredentialUserDescription=Der Benutzer, als der du dich anmeldest. +credentialPassword=Berechtigungsnachweis Passwort +pssCredentialPasswordDescription=Das Passwort des Benutzers. +sshConfig=SSH-Konfigurationsdateien +autostart=Automatisches Verbinden beim Start von XPipe +acceptHostKey=Host-Schlüssel akzeptieren +modifyHostKeyPermissions=Host Key Berechtigungen ändern +attachContainer=Am Container anhängen +openInVsCode=In VSCode öffnen +containerLogs=Containerprotokolle anzeigen +openSftpClient=In einem externen SFTP-Client öffnen +openTermius=In Termius öffnen +showInternalInstances=Interne Instanzen anzeigen +editPod=Pod bearbeiten +acceptHostKeyDescription=Vertraue dem neuen Host-Schlüssel und fahre fort +modifyHostKeyPermissionsDescription=Versuchen Sie, die Berechtigungen der Originaldatei zu entfernen, damit OpenSSH zufrieden ist +psSession.displayName=PowerShell Remote-Sitzung +psSession.displayDescription=Verbinden über New-PSSession und Enter-PSSession +sshLocalTunnel.displayName=Lokaler SSH-Tunnel +sshLocalTunnel.displayDescription=Einen SSH-Tunnel zu einem entfernten Host einrichten +sshRemoteTunnel.displayName=Entfernter SSH-Tunnel +sshRemoteTunnel.displayDescription=Einen umgekehrten SSH-Tunnel von einem entfernten Host aus aufbauen +sshDynamicTunnel.displayName=Dynamischer SSH-Tunnel +sshDynamicTunnel.displayDescription=Einen SOCKS-Proxy über eine SSH-Verbindung einrichten +shellEnvironmentGroup.displayName=Shell-Umgebungen +shellEnvironmentGroup.displayDescription=Shell-Umgebungen +shellEnvironment.displayName=Benutzerdefinierte Shell-Umgebung +shellEnvironment.displayDescription=Eine angepasste Shell-Init-Umgebung erstellen +shellEnvironment.informationFormat=$TYPE$ umgebung +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ umgebung +environmentConnectionDescription=Die Basisverbindung, um eine Umgebung zu schaffen für +environmentScriptDescription=Das optionale benutzerdefinierte Init-Skript, das in der Shell ausgeführt wird +environmentSnippets=Skript-Schnipsel +commandSnippetsDescription=Die optionalen vordefinierten Skriptschnipsel, die zuerst ausgeführt werden +environmentSnippetsDescription=Die optionalen vordefinierten Skript-Snippets, die bei der Initialisierung ausgeführt werden +shellTypeDescription=Der explizite Shell-Typ zum Starten +originPort=Ursprungsport +originAddress=Herkunftsadresse +remoteAddress=Entfernte Adresse +remotePort=Entfernter Anschluss +remoteSourceAddress=Entfernte Quelladresse +remoteSourcePort=Entfernter Quellport +originDestinationPort=Ursprung Zielhafen +originDestinationAddress=Herkunft Zieladresse +origin=Herkunft +remoteHost=Entfernter Host +address=Adresse +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Verbindung zu Systemen in einer virtuellen Umgebung von Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Verbindung zu einer virtuellen Maschine in einer Proxmox VE über SSH +proxmoxContainer.displayName=Proxmox Container +proxmoxContainer.displayDescription=Verbindung zu einem Container in einer Proxmox VE +sshDynamicTunnel.originDescription=Das System, von dem aus die ssh-Verbindung geöffnet werden soll +sshDynamicTunnel.hostDescription=Das System, das als SOCKS-Proxy verwendet werden soll +sshDynamicTunnel.bindingDescription=An welche Adressen der Tunnel gebunden werden soll +sshRemoteTunnel.originDescription=Das System, von dem aus die ssh-Verbindung geöffnet werden soll und zu dem der Tunnel geöffnet werden soll +sshRemoteTunnel.hostDescription=Das System, von dem aus der Ferntunnel zum Ursprung gestartet werden soll +sshRemoteTunnel.bindingDescription=An welche Adressen der Tunnel gebunden werden soll +sshLocalTunnel.originDescription=Das System, von dem aus der Tunnel gestartet werden soll +sshLocalTunnel.hostDescription=Das System, zu dem der Tunnel geöffnet werden soll +sshLocalTunnel.bindingDescription=An welche Adressen der Tunnel gebunden werden soll +sshLocalTunnel.localAddressDescription=Die lokale Adresse zum Binden +sshLocalTunnel.remoteAddressDescription=Die zu bindende Remote-Adresse +cmd.displayName=Benutzerdefinierter Terminal-Befehl +cmd.displayDescription=Einen benutzerdefinierten Befehl auf einem System in deinem Terminal ausführen +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=Verbinden mit einem Pod und seinen Containern über kubectl +k8sContainer.displayName=Kubernetes Container +k8sContainer.displayDescription=Eine Shell für einen Container öffnen +k8sCluster.displayName=Kubernetes Cluster +k8sCluster.displayDescription=Verbinden mit einem Cluster und seinen Pods über kubectl +sshTunnelGroup.displayName=SSH-Tunnel +sshTunnelGroup.displayCategory=Alle Arten von SSH-Tunneln +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Zugriff auf Podman-Container über den CLI-Client +podmanContainers=Podman Container +local.displayName=Lokale Maschine +local.displayDescription=Die Shell des lokalen Rechners +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git für Windows +gitForWindows.displayName=Git für Windows +gitForWindows.displayDescription=Zugriff auf deine lokale Git For Windows-Umgebung +msys2.displayName=MSYS2 +msys2.displayDescription=Zugriff auf die Shells deiner MSYS2 Umgebung +cygwin.displayName=Cygwin +cygwin.displayDescription=Zugriff auf die Shells deiner Cygwin-Umgebung +namespace=Namespace +gitVaultIdentityStrategy=Git SSH Identität +gitVaultIdentityStrategyDescription=Wenn du dich entschieden hast, eine SSH-Git-URL als Remote zu verwenden und dein Remote-Repository eine SSH-Identität erfordert, dann setze diese Option.\n\nFalls du eine HTTP-URL angegeben hast, kannst du diese Option ignorieren. +dockerContainers=Docker-Container +lxdContainers=LXD-Container +dockerCmd.displayName=docker CLI-Client +dockerCmd.displayDescription=Zugriff auf Docker-Container über den Docker CLI-Client +lxdCmd.displayName=LXD CLI-Client +lxdCmd.displayDescription=Zugriff auf LXD-Container über das lxc CLI cient +wslCmd.displayName=wsl-Client +wslCmd.displayDescription=Zugriff auf WSL-Instanzen über das wsl CLI cient +k8sCmd.displayName=kubectl-Client +k8sCmd.displayDescription=Zugriff auf Kubernetes-Cluster über kubectl +k8sClusters=Kubernetes-Cluster +#custom +shells=Verfügbare Shells +startContainer=Container starten +stopContainer=Container anhalten +inspectContainer=Container inspizieren +k8sClusterNameDescription=Der Name des Kontexts, in dem sich der Cluster befindet. +pod=Pod +podName=Pod-Name +k8sClusterContext=Kontext +k8sClusterContextDescription=Der Name des Kontexts, in dem sich der Cluster befindet +k8sClusterNamespace=Namespace +k8sClusterNamespaceDescription=Der benutzerdefinierte Namespace oder der Standard-Namespace, falls leer +k8sConfigLocation=Config-Datei +k8sConfigLocationDescription=Die benutzerdefinierte kubeconfig-Datei oder die Standarddatei, wenn sie leer ist +inspectPod=Pod inspizieren +showAllContainers=Nicht laufende Container anzeigen +showAllPods=Nicht laufende Pods anzeigen +wsl=WSL +docker=Docker +k8sPodHostDescription=Der Host, auf dem sich der Pod befindet +k8sContainerDescription=Der Name des Kubernetes-Containers +k8sPodDescription=Der Name des Kubernetes-Pods +podDescription=Der Pod, auf dem sich der Container befindet +k8sClusterHostDescription=Der Host, über den auf den Cluster zugegriffen werden soll. Muss kubectl installiert und konfiguriert haben, um auf den Cluster zugreifen zu können. +script=Init-Skript +connection=Verbindung +shellCommand.displayName=Benutzerdefinierter Shell-Öffner-Befehl +shellCommand.displayDescription=Eine Standard-Shell über einen benutzerdefinierten Befehl öffnen +ssh.displayName=Einfache SSH-Verbindung +ssh.displayDescription=Verbindung über einen SSH-Befehlszeilen-Client +sshConfig.displayName=SSH-Konfigurationsdatei +sshConfig.displayDescription=Verbindung zu Hosts, die in einer SSH-Konfigurationsdatei definiert sind +sshConfigHost.displayName=SSH-Konfigurationsdatei Host +sshConfigHost.displayDescription=Sich mit einem in einer SSH-Konfigurationsdatei definierten Host verbinden +sshConfigHost.password=Passwort +sshConfigHost.passwordDescription=Gib das optionale Passwort für die Benutzeranmeldung an. +sshConfigHost.identityPassphrase=Identitäts-Passphrase +sshConfigHost.identityPassphraseDescription=Gib die optionale Passphrase für deinen Identitätsschlüssel an. +binary.displayName=Binär +binary.displayDescription=Binäre Daten +text.displayName=Text +shellCommand.hostDescription=Der Host, auf dem der Befehl ausgeführt werden soll +shellCommand.commandDescription=Der Befehl, mit dem eine Shell geöffnet wird +sshAgent=SSH-Agent +none=Keine +commandDescription=Die Befehle, die in einem Shell-Skript auf dem Host ausgeführt werden sollen. +commandHostDescription=Der Host, auf dem der Befehl ausgeführt werden soll +commandDataFlowDescription=Wie dieser Befehl Ein- und Ausgaben behandelt +commandElevationDescription=Diesen Befehl mit erweiterten Rechten ausführen +commandShellTypeDescription=Die Shell, die für diesen Befehl verwendet werden soll +ssh.passwordDescription=Das optionale Passwort, das bei der Authentifizierung verwendet wird +keyAuthentication=Schlüsselbasierte Authentifizierung +keyAuthenticationDescription=Die zu verwendende Authentifizierungsmethode, wenn eine schlüsselbasierte Authentifizierung erforderlich ist. +dontInteractWithSystem=Nicht mit dem System interagieren (Pro) +dontInteractWithSystemDescription=Versuche nicht, den Typ der Shell und des Betriebssystems zu identifizieren +sshForwardX11=X11 weiterleiten +sshForwardX11Description=Aktiviert die X11-Weiterleitung für die Verbindung +customAgent=Benutzerdefinierter Agent +identityAgent=Identitätsagent +ssh.proxyDescription=Der optionale Proxy-Host, der beim Aufbau der SSH-Verbindung verwendet wird. Es muss ein SSH-Client installiert sein. +usage=Verwendung +wslHostDescription=Der Host, auf dem sich die WSL-Instanz befindet. Muss wsl installiert haben. +wslDistributionDescription=Der Name der WSL-Instanz +wslUsernameDescription=Der explizite Benutzername, mit dem du dich anmeldest. Wenn er nicht angegeben wird, wird der Standardbenutzername verwendet. +wslPasswordDescription=Das Passwort des Benutzers, das für sudo-Befehle verwendet werden kann. +dockerHostDescription=Der Host, auf dem sich der Docker-Container befindet. Muss Docker installiert haben. +dockerContainerDescription=Der Name des Docker-Containers +lxdHostDescription=Der Host, auf dem sich der LXD-Container befindet. Muss lxc installiert haben. +lxdContainerDescription=Der Name des LXD-Containers +localMachine=Lokale Maschine +rootScan=Root-Shell-Umgebung +loginEnvironmentScan=Benutzerdefinierte Anmeldeumgebung +k8sScan=Kubernetes-Cluster +options=Optionen +dockerRunningScan=Docker-Container ausführen +dockerAllScan=Alle Docker-Container +wslScan=WSL-Instanzen +sshScan=SSH-Konfigurationsverbindungen +requiresElevation=Erhöht ausführen +default=Standard +wslHost=WSL-Host +timeout=Timeout +installLocation=Installationsort +installLocationDescription=Der Ort, an dem deine $NAME$ Umgebung installiert ist +wsl.displayName=Windows Subsystem für Linux +wsl.displayDescription=Verbindung zu einer WSL-Instanz unter Windows +docker.displayName=Docker Container +docker.displayDescription=Mit einem Docker-Container verbinden +podman.displayName=Podman Container +podman.displayDescription=Mit einem Podman-Container verbinden +lxd.displayName=LXD-Container +lxd.displayDescription=Verbindung zu einem LXD-Container über lxc +container=Container +host=Host +port=Port +user=Benutzer +password=Passwort +method=Methode +uri=URL +proxy=Proxy +distribution=Vertrieb +username=Benutzername +shellType=Shell-Typ +browseFile=Datei durchsuchen +openShell=Shell im Terminal öffnen +openCommand=Befehl im Terminal ausführen +editFile=Datei bearbeiten +description=Beschreibung +keyFile=Identitätsdatei +keyPassword=Passphrase +key=Schlüssel +furtherCustomization=Weitere Anpassungen +furtherCustomizationDescription=Weitere Konfigurationsoptionen findest du in den ssh-Konfigurationsdateien +location=Standort +browse=Durchsuchen +locationDescription=Der Dateipfad deines entsprechenden privaten Schlüssels +configHost=Host +configHostDescription=Der Host, auf dem sich die Konfiguration befindet +configLocation=Config-Speicherort +configLocationDescription=Der Dateipfad der Konfigurationsdatei +pageant=Pageant +gpgAgent=GPG Agent (Pro) +gateway=Gateway +gatewayDescription=Das optionale Gateway, das bei der Verbindung verwendet wird. +connectionInformation=Verbindungsinformationen +connectionInformationDescription=Mit welchem System soll eine Verbindung hergestellt werden? +passwordAuthentication=Passwort-Authentifizierung +passwordDescription=Das optionale Passwort, das zur Authentifizierung verwendet wird. +sshConfigString.displayName=Angepasste SSH-Verbindung +sshConfigString.displayDescription=Eine vollständig angepasste SSH-Verbindung erstellen +sshConfigStringContent=Konfiguration +sshConfigStringContentDescription=SSH-Optionen für die Verbindung im OpenSSH-Config-Format +vnc.displayName=VNC-Verbindung +vnc.displayDescription=Eine VNC-Sitzung über einen SSH-Tunnel öffnen +#custom +binding=Bindings +vncPortDescription=Der Port, an dem der VNC-Server lauscht +vncUsername=Benutzername +vncUsernameDescription=Der optionale VNC-Benutzername +vncPassword=Passwort +vncPasswordDescription=Das VNC-Passwort +x11WslInstance=X11 Forward WSL-Instanz +x11WslInstanceDescription=Die lokale Windows Subsystem für Linux-Distribution, die als X11-Server verwendet werden soll, wenn die X11-Weiterleitung in einer SSH-Verbindung genutzt wird. Diese Distribution muss eine WSL2-Distribution sein.\n\nErfordert einen Neustart zur Anwendung. +openAsRoot=Als Root öffnen +openInVsCodeRemote=Öffnen in VSCode remote +openInWSL=In WSL öffnen +launch=Starten diff --git a/lang/proc/strings/translations_en.properties b/lang/proc/strings/translations_en.properties new file mode 100644 index 000000000..93a3cb898 --- /dev/null +++ b/lang/proc/strings/translations_en.properties @@ -0,0 +1,298 @@ +showInternalPods=Show internal pods +showAllNamespaces=Show all namespaces +showInternalContainers=Show internal containers +refresh=Refresh +vmwareGui=Start GUI +monitorVm=Monitor VM +addCluster=Add cluster ... +showNonRunningInstances=Show non-running instances +vmwareGuiDescription=Whether to start a virtual machine in the background or in a window. +vmwareEncryptionPassword=Encryption password +vmwareEncryptionPasswordDescription=The optional password used to encrypt the VM. +vmwarePasswordDescription=The required password for the guest user. +vmwarePassword=User password +vmwareUser=Guest user +runTempContainer=Run temporary container +vmwareUserDescription=The username of your primary guest user +dockerTempRunAlertTitle=Run temporary container +dockerTempRunAlertHeader=This will run a shell process in a temporary container that will get automatically removed once it is stopped. +imageName=Image name +imageNameDescription=The container image identifier to use +containerName=Container name +containerNameDescription=The optional custom container name +vm=Virtual machine +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=The associated configuration file. +vmwareScan=VMware desktop hypervisors +library=Library +customPkcs11Library=Custom PKCS#11 library (Pro) +vmwareMachine.displayName=VMware Virtual Machine +vmwareMachine.displayDescription=Connect to a virtual machine via SSH +vmwareInstallation.displayName=VMware desktop hypervisor installation +vmwareInstallation.displayDescription=Interact with the installed VMs via its CLI +start=Start +stop=Stop +pause=Pause +rdpTunnelHost=Tunnel host +rdpTunnelHostDescription=The optional SSH connection to use as a tunnel +rdpFileLocation=File location +rdpFileLocationDescription=The file path of the .rdp file +rdpPasswordAuthentication=Password authentication +rdpPasswordAuthenticationDescription=The password to automatically fill in if supported +rdpFile.displayName=RDP File +rdpFile.displayDescription=Connect to a system via an existing .rdp file +requiredSshServerAlertTitle=Setup SSH server +requiredSshServerAlertHeader=Unable to find an installed SSH server in the VM. +requiredSshServerAlertContent=To connect to the VM, XPipe is looking for a running SSH server but no available SSH server was detected for the VM.. +computerName=Computer Name +pssComputerNameDescription=The computer name to connect to. It is assumed that it is already included in your trusted hosts. +credentialUser=Credential User +pssCredentialUserDescription=The user to login as. +credentialPassword=Credential Password +pssCredentialPasswordDescription=The password of the user. +sshConfig=SSH config files +autostart=Automatically connect on XPipe startup +acceptHostKey=Accept host key +modifyHostKeyPermissions=Modify host key permissions +attachContainer=Attach to container +openInVsCode=Open in VSCode +containerLogs=Show container logs +openSftpClient=Open in external SFTP client +openTermius=Open in Termius +showInternalInstances=Show internal instances +editPod=Edit pod +acceptHostKeyDescription=Trust the new host key and continue +modifyHostKeyPermissionsDescription=Attempt to remove permissions of the original file so that OpenSSH is happy +psSession.displayName=PowerShell Remote Session +psSession.displayDescription=Connect via New-PSSession and Enter-PSSession +sshLocalTunnel.displayName=Local SSH tunnel +sshLocalTunnel.displayDescription=Establish an SSH tunnel to a remote host +sshRemoteTunnel.displayName=Remote SSH tunnel +sshRemoteTunnel.displayDescription=Establish a reverse SSH tunnel from a remote host +sshDynamicTunnel.displayName=Dynamic SSH tunnel +sshDynamicTunnel.displayDescription=Establish a SOCKS proxy through an SSH connection +shellEnvironmentGroup.displayName=Shell Environments +shellEnvironmentGroup.displayDescription=Shell Environments +shellEnvironment.displayName=Custom Shell Environment +shellEnvironment.displayDescription=Create a customized shell init environment +shellEnvironment.informationFormat=$TYPE$ environment +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ environment +environmentConnectionDescription=The base connection to create an environment for +environmentScriptDescription=The optional custom init script to run in the shell +environmentSnippets=Script snippets +commandSnippetsDescription=The optional predefined script snippets to run first +environmentSnippetsDescription=The optional predefined script snippets to run on initialization +shellTypeDescription=The explicit shell type to launch +originPort=Origin port +originAddress=Origin address +remoteAddress=Remote address +remotePort=Remote port +remoteSourceAddress=Remote source address +remoteSourcePort=Remote source port +originDestinationPort=Origin destination port +originDestinationAddress=Origin destination address +origin=Origin +remoteHost=Remote host +address=Address +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Connect to systems in a Proxmox Virtual Environment +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Connect to a virtual machine in a Proxmox VE via SSH +proxmoxContainer.displayName=Proxmox Container +proxmoxContainer.displayDescription=Connect to a container in a Proxmox VE +sshDynamicTunnel.originDescription=The system from where to open the ssh connection +sshDynamicTunnel.hostDescription=The system to use as SOCKS proxy +sshDynamicTunnel.bindingDescription=What addresses to bind the tunnel to +sshRemoteTunnel.originDescription=The system from where to open the ssh connection and to open the tunnel to +sshRemoteTunnel.hostDescription=The system from which to start the remote tunnel to the origin +sshRemoteTunnel.bindingDescription=What addresses to bind the tunnel to +sshLocalTunnel.originDescription=The system from where to start the tunnel +sshLocalTunnel.hostDescription=The system to open the tunnel to +sshLocalTunnel.bindingDescription=What addresses to bind the tunnel to +sshLocalTunnel.localAddressDescription=The local address to bind +sshLocalTunnel.remoteAddressDescription=The remote address to bind +cmd.displayName=Custom Terminal Command +cmd.displayDescription=Run a custom command on a system in your terminal +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=Connect to a pod and its containers via kubectl +k8sContainer.displayName=Kubernetes Container +k8sContainer.displayDescription=Open a shell to a container +k8sCluster.displayName=Kubernetes Cluster +k8sCluster.displayDescription=Connect to a cluster and its pods via kubectl +sshTunnelGroup.displayName=SSH Tunnels +sshTunnelGroup.displayCategory=All types of SSH tunnels +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Access Podman containers via the CLI client +podmanContainers=Podman containers +local.displayName=Local machine +local.displayDescription=The shell of the local machine +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git For Windows +gitForWindows.displayName=Git For Windows +gitForWindows.displayDescription=Access your local Git For Windows environment +msys2.displayName=MSYS2 +msys2.displayDescription=Access shells of your MSYS2 environment +cygwin.displayName=Cygwin +cygwin.displayDescription=Access shells of your Cygwin environment +namespace=Namespace +gitVaultIdentityStrategy=Git SSH identity +gitVaultIdentityStrategyDescription=If you chose to use an SSH git URL as the remote and your remote repository requires an SSH identity, then set this option.\n\nIn case you provided an HTTP url, you can ignore this option. +dockerContainers=Docker containers +lxdContainers=LXD containers +dockerCmd.displayName=docker CLI client +dockerCmd.displayDescription=Access Docker containers via the docker CLI client +lxdCmd.displayName=LXD CLI client +lxdCmd.displayDescription=Access LXD containers via the lxc CLI cient +wslCmd.displayName=wsl client +wslCmd.displayDescription=Access WSL instances via the wsl CLI cient +k8sCmd.displayName=kubectl client +k8sCmd.displayDescription=Access Kubernetes clusters via kubectl +k8sClusters=Kubernetes clusters +shells=Available shells +startContainer=Start container +stopContainer=Stop container +inspectContainer=Inspect container +k8sClusterNameDescription=The name of the context the cluster is in. +pod=Pod +podName=Pod name +k8sClusterContext=Context +k8sClusterContextDescription=The name of the context the cluster is in +k8sClusterNamespace=Namespace +k8sClusterNamespaceDescription=The custom namespace or the default one if empty +k8sConfigLocation=Config file +k8sConfigLocationDescription=The custom kubeconfig file or the default one if left empty +inspectPod=Inspect pod +showAllContainers=Show non-running containers +showAllPods=Show non-running pods +wsl=WSL +docker=Docker +k8sPodHostDescription=The host on which the pod is located +k8sContainerDescription=The name of the Kubernetes container +k8sPodDescription=The name of the Kubernetes pod +podDescription=The pod on which the container is located +k8sClusterHostDescription=The host through which the cluster should be accessed. Must have kubectl installed and configured to be able to access the cluster. +script=Init Script +connection=Connection +shellCommand.displayName=Custom Shell Opener Command +shellCommand.displayDescription=Open a standard shell through a custom command +ssh.displayName=Simple SSH Connection +ssh.displayDescription=Connect via an SSH command-line client +sshConfig.displayName=SSH Config File +sshConfig.displayDescription=Connect to hosts defined in an SSH config file +sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayDescription=Connect to a host defined in an SSH config file +sshConfigHost.password=Password +sshConfigHost.passwordDescription=Provide the optional password for the user login. +sshConfigHost.identityPassphrase=Identity passphrase +sshConfigHost.identityPassphraseDescription=Provide the optional passphrase for your identity key. +binary.displayName=Binary +binary.displayDescription=Binary data +text.displayName=Text +shellCommand.hostDescription=The host to execute the command on +shellCommand.commandDescription=The command that will open a shell +sshAgent=SSH-Agent +none=None +commandDescription=The commands to execute in a shell script on the host. +commandHostDescription=The host to run the command on +commandDataFlowDescription=How this command handles input and output +commandElevationDescription=Run this command with elevated permissions +commandShellTypeDescription=The shell to use for this command +ssh.passwordDescription=The optional password to use when authenticating +keyAuthentication=Key-based authentication +keyAuthenticationDescription=The authentication method to use if key-based authentication is required. +dontInteractWithSystem=Don't interact with system (Pro) +dontInteractWithSystemDescription=Don't try to identify shell and operating system type +sshForwardX11=Forward X11 +sshForwardX11Description=Enables X11 forwarding for the connection +customAgent=Custom agent +identityAgent=Identity agent +ssh.proxyDescription=The optional proxy host to use when establishing the SSH connection. Must have an ssh client installed. +usage=Usage +wslHostDescription=The host on which the WSL instance is located on. Must have wsl installed. +wslDistributionDescription=The name of the WSL instance +wslUsernameDescription=The explicit username to login as. If not specified, the default username will be used. +wslPasswordDescription=The user's password which can be used for sudo commands. +dockerHostDescription=The host on which the docker container is located on. Must have docker installed. +dockerContainerDescription=The name of the docker container +lxdHostDescription=The host on which the LXD container is located on. Must have lxc installed. +lxdContainerDescription=The name of the LXD container +localMachine=Local Machine +rootScan=Root shell environment +loginEnvironmentScan=Custom login environment +k8sScan=Kubernetes cluster +options=Options +dockerRunningScan=Running docker containers +dockerAllScan=All docker containers +wslScan=WSL instances +sshScan=SSH config connections +requiresElevation=Run Elevated +default=Default +wslHost=WSL Host +timeout=Timeout +installLocation=Install location +installLocationDescription=The location where your $NAME$ environment is installed +wsl.displayName=Windows Subsystem for Linux +wsl.displayDescription=Connect to a WSL instance running on Windows +docker.displayName=Docker Container +docker.displayDescription=Connect to a docker container +podman.displayName=Podman Container +podman.displayDescription=Connect to a Podman container +lxd.displayName=LXD Container +lxd.displayDescription=Connect to a LXD container via lxc +container=Container +host=Host +port=Port +user=User +password=Password +method=Method +uri=URL +proxy=Proxy +distribution=Distribution +username=Username +shellType=Shell Type +browseFile=Browse File +openShell=Open Shell in Terminal +openCommand=Execute Command in Terminal +editFile=Edit File +description=Description +keyFile=Identity File +keyPassword=Passphrase +key=Key +furtherCustomization=Further customization +furtherCustomizationDescription=For more configuration options, use the ssh config files +location=Location +browse=Browse +locationDescription=The file path of your corresponding private key +configHost=Host +configHostDescription=The host on which the config is located on +configLocation=Config location +configLocationDescription=The file path of the config file +pageant=Pageant +gpgAgent=GPG Agent (Pro) +gateway=Gateway +gatewayDescription=The optional gateway to use when connecting. +connectionInformation=Connection information +#context: title +connectionInformationDescription=Which system to connect to +passwordAuthentication=Password authentication +passwordDescription=The optional password to use to authenticate. +sshConfigString.displayName=Customized SSH Connection +sshConfigString.displayDescription=Create a fully customized SSH connection +sshConfigStringContent=Configuration +sshConfigStringContentDescription=SSH options for the connection in OpenSSH config format +vnc.displayName=VNC connection +vnc.displayDescription=Open a VNC session via an SSH tunnel +binding=Binding +vncPortDescription=The port the VNC server is listening on +vncUsername=Username +vncUsernameDescription=The optional VNC username +vncPassword=Password +vncPasswordDescription=The VNC password +x11WslInstance=X11 Forward WSL instance +x11WslInstanceDescription=The local Windows Subsystem for Linux distribution to use as an X11 server when using X11 forwarding in an SSH connection. This distribution must be a WSL2 distribution.\n\nRequires a restart to apply. +openAsRoot=Open as root +openInVsCodeRemote=Open in VSCode remote +openInWSL=Open in WSL +launch=Launch diff --git a/lang/proc/strings/translations_es.properties b/lang/proc/strings/translations_es.properties new file mode 100644 index 000000000..bb0ff6414 --- /dev/null +++ b/lang/proc/strings/translations_es.properties @@ -0,0 +1,297 @@ +showInternalPods=Mostrar vainas internas +showAllNamespaces=Mostrar todos los espacios de nombres +showInternalContainers=Mostrar contenedores internos +refresh=Actualizar +vmwareGui=Iniciar GUI +monitorVm=Monitor VM +addCluster=Añadir clúster ... +showNonRunningInstances=Mostrar instancias no en ejecución +vmwareGuiDescription=Si iniciar una máquina virtual en segundo plano o en una ventana. +vmwareEncryptionPassword=Contraseña de encriptación +vmwareEncryptionPasswordDescription=La contraseña opcional utilizada para encriptar la VM. +vmwarePasswordDescription=La contraseña necesaria para el usuario invitado. +vmwarePassword=Contraseña de usuario +vmwareUser=Usuario invitado +runTempContainer=Ejecutar un contenedor temporal +vmwareUserDescription=El nombre de usuario de tu usuario invitado principal +dockerTempRunAlertTitle=Ejecutar un contenedor temporal +dockerTempRunAlertHeader=Esto ejecutará un proceso shell en un contenedor temporal que se eliminará automáticamente cuando se detenga. +imageName=Nombre de la imagen +imageNameDescription=El identificador de la imagen contenedora a utilizar +containerName=Nombre del contenedor +containerNameDescription=El nombre opcional del contenedor personalizado +vm=Máquina virtual +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=El archivo de configuración asociado. +vmwareScan=Hipervisores de escritorio VMware +library=Biblioteca +customPkcs11Library=Biblioteca PKCS#11 personalizada (Pro) +vmwareMachine.displayName=Máquina virtual VMware +vmwareMachine.displayDescription=Conectarse a una máquina virtual mediante SSH +vmwareInstallation.displayName=Instalación del hipervisor de escritorio VMware +vmwareInstallation.displayDescription=Interactúa con las máquinas virtuales instaladas a través de su CLI +start=Inicia +stop=Para +pause=Pausa +rdpTunnelHost=Túnel anfitrión +rdpTunnelHostDescription=La conexión SSH opcional a utilizar como túnel +rdpFileLocation=Ubicación del archivo +rdpFileLocationDescription=La ruta del archivo .rdp +rdpPasswordAuthentication=Autenticación de contraseña +rdpPasswordAuthenticationDescription=La contraseña para rellenar automáticamente si se admite +rdpFile.displayName=Archivo RDP +rdpFile.displayDescription=Conectarse a un sistema a través de un archivo .rdp existente +requiredSshServerAlertTitle=Configurar servidor SSH +requiredSshServerAlertHeader=No se puede encontrar un servidor SSH instalado en la máquina virtual. +requiredSshServerAlertContent=Para conectarse a la VM, XPipe busca un servidor SSH en ejecución, pero no se ha detectado ningún servidor SSH disponible para la VM.. +computerName=Nombre del ordenador +pssComputerNameDescription=El nombre del ordenador al que conectarse. Se supone que ya está incluido en tus hosts de confianza. +credentialUser=Credencial de usuario +pssCredentialUserDescription=El usuario con el que iniciar sesión. +credentialPassword=Contraseña credencial +pssCredentialPasswordDescription=La contraseña del usuario. +sshConfig=Archivos de configuración SSH +autostart=Conectarse automáticamente al iniciar XPipe +acceptHostKey=Aceptar clave de host +modifyHostKeyPermissions=Modificar los permisos de la clave host +attachContainer=Adjuntar al contenedor +openInVsCode=Abrir en VSCode +containerLogs=Mostrar registros de contenedores +openSftpClient=Abrir en cliente SFTP externo +openTermius=Abrir en Termius +showInternalInstances=Mostrar instancias internas +editPod=Editar vaina +acceptHostKeyDescription=Confía en la nueva clave de host y continúa +modifyHostKeyPermissionsDescription=Intenta eliminar los permisos del archivo original para que OpenSSH esté contento +psSession.displayName=Sesión remota PowerShell +psSession.displayDescription=Conectar mediante Nueva-PSSession y Entrar-PSSession +sshLocalTunnel.displayName=Túnel SSH local +sshLocalTunnel.displayDescription=Establecer un túnel SSH a un host remoto +sshRemoteTunnel.displayName=Túnel SSH remoto +sshRemoteTunnel.displayDescription=Establecer un túnel SSH inverso desde un host remoto +sshDynamicTunnel.displayName=Túnel SSH dinámico +sshDynamicTunnel.displayDescription=Establecer un proxy SOCKS a través de una conexión SSH +shellEnvironmentGroup.displayName=Entornos Shell +shellEnvironmentGroup.displayDescription=Entornos Shell +shellEnvironment.displayName=Entorno Shell personalizado +shellEnvironment.displayDescription=Crear un entorno shell init personalizado +shellEnvironment.informationFormat=$TYPE$ entorno +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ entorno +environmentConnectionDescription=La conexión base para crear un entorno para +environmentScriptDescription=El script init personalizado opcional que se ejecutará en el intérprete de comandos +environmentSnippets=Fragmentos de guión +commandSnippetsDescription=Los fragmentos de guión predefinidos opcionales para ejecutar primero +environmentSnippetsDescription=Los fragmentos de guión predefinidos opcionales para ejecutar en la inicialización +shellTypeDescription=El tipo de shell explícito que hay que lanzar +originPort=Puerto de origen +originAddress=Dirección de origen +remoteAddress=Dirección remota +remotePort=Puerto remoto +remoteSourceAddress=Dirección de origen remoto +remoteSourcePort=Puerto de origen remoto +originDestinationPort=Puerto de origen destino +originDestinationAddress=Dirección de destino de origen +origin=Origen +remoteHost=Host remoto +address=Dirección +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Conectarse a sistemas en un Entorno Virtual Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Conectarse a una máquina virtual en un VE Proxmox mediante SSH +proxmoxContainer.displayName=Contenedor Proxmox +proxmoxContainer.displayDescription=Conectarse a un contenedor en un VE Proxmox +sshDynamicTunnel.originDescription=El sistema desde el que abrir la conexión ssh +sshDynamicTunnel.hostDescription=El sistema a utilizar como proxy SOCKS +sshDynamicTunnel.bindingDescription=A qué direcciones enlazar el túnel +sshRemoteTunnel.originDescription=El sistema desde el que abrir la conexión ssh y abrir el túnel a +sshRemoteTunnel.hostDescription=El sistema desde el que iniciar el túnel remoto hacia el origen +sshRemoteTunnel.bindingDescription=A qué direcciones enlazar el túnel +sshLocalTunnel.originDescription=El sistema desde el que iniciar el túnel +sshLocalTunnel.hostDescription=El sistema para abrir el túnel hacia +sshLocalTunnel.bindingDescription=A qué direcciones enlazar el túnel +sshLocalTunnel.localAddressDescription=La dirección local a enlazar +sshLocalTunnel.remoteAddressDescription=La dirección remota a enlazar +cmd.displayName=Comando de terminal personalizado +cmd.displayDescription=Ejecuta un comando personalizado en un sistema en tu terminal +k8sPod.displayName=Pod Kubernetes +k8sPod.displayDescription=Conectarse a un pod y sus contenedores mediante kubectl +k8sContainer.displayName=Contenedor Kubernetes +k8sContainer.displayDescription=Abrir un shell a un contenedor +k8sCluster.displayName=Clúster Kubernetes +k8sCluster.displayDescription=Conectarse a un clúster y sus pods mediante kubectl +sshTunnelGroup.displayName=Túneles SSH +sshTunnelGroup.displayCategory=Todos los tipos de túneles SSH +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Accede a los contenedores Podman a través del cliente CLI +podmanContainers=Contenedores Podman +local.displayName=Máquina local +local.displayDescription=El shell de la máquina local +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git para Windows +gitForWindows.displayName=Git para Windows +gitForWindows.displayDescription=Accede a tu entorno local de Git para Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Conchas de acceso de tu entorno MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Accede a los shells de tu entorno Cygwin +namespace=Espacio de nombres +gitVaultIdentityStrategy=Identidad SSH Git +gitVaultIdentityStrategyDescription=Si has elegido utilizar una URL git SSH como remota y tu repositorio remoto requiere una identidad SSH, activa esta opción.\n\nEn caso de que hayas proporcionado una url HTTP, puedes ignorar esta opción. +dockerContainers=Contenedores Docker +lxdContainers=Contenedores LXD +dockerCmd.displayName=cliente docker CLI +dockerCmd.displayDescription=Accede a los contenedores Docker mediante el cliente CLI Docker +lxdCmd.displayName=Cliente CLI LXD +lxdCmd.displayDescription=Accede a los contenedores LXD mediante la CLI lxc cient +wslCmd.displayName=cliente wsl +wslCmd.displayDescription=Acceder a instancias WSL mediante la CLI wsl cient +k8sCmd.displayName=cliente kubectl +k8sCmd.displayDescription=Acceder a clusters Kubernetes mediante kubectl +k8sClusters=Clústeres Kubernetes +shells=Conchas disponibles +startContainer=Contenedor de inicio +stopContainer=Contenedor de parada +inspectContainer=Inspeccionar contenedor +k8sClusterNameDescription=El nombre del contexto en el que se encuentra el clúster. +pod=Pod +podName=Nombre del pod +k8sClusterContext=Contexto +k8sClusterContextDescription=El nombre del contexto en el que se encuentra el clúster +k8sClusterNamespace=Espacio de nombres +k8sClusterNamespaceDescription=El espacio de nombres personalizado o el predeterminado si está vacío +k8sConfigLocation=Archivo de configuración +k8sConfigLocationDescription=El archivo kubeconfig personalizado o el predeterminado si se deja vacío +inspectPod=Inspeccionar vaina +showAllContainers=Mostrar contenedores no en ejecución +showAllPods=Mostrar pods no en ejecución +wsl=WSL +docker=Docker +k8sPodHostDescription=El host en el que se encuentra el pod +k8sContainerDescription=El nombre del contenedor Kubernetes +k8sPodDescription=El nombre del pod de Kubernetes +podDescription=La vaina en la que se encuentra el contenedor +k8sClusterHostDescription=El host a través del cual se debe acceder al clúster. Debe tener kubectl instalado y configurado para poder acceder al clúster. +script=Guión de inicio +connection=Conexión +shellCommand.displayName=Comando de apertura de shell personalizado +shellCommand.displayDescription=Abrir un shell estándar mediante un comando personalizado +ssh.displayName=Conexión SSH simple +ssh.displayDescription=Conectarse mediante un cliente de línea de comandos SSH +sshConfig.displayName=Archivo de configuración SSH +sshConfig.displayDescription=Conectarse a hosts definidos en un archivo de configuración SSH +sshConfigHost.displayName=Archivo SSH Config Anfitrión +sshConfigHost.displayDescription=Conectarse a un host definido en un archivo de configuración SSH +sshConfigHost.password=Contraseña +sshConfigHost.passwordDescription=Proporciona la contraseña opcional para el inicio de sesión del usuario. +sshConfigHost.identityPassphrase=Frase de contraseña de identidad +sshConfigHost.identityPassphraseDescription=Proporciona la frase de contraseña opcional para tu clave de identidad. +binary.displayName=Binario +binary.displayDescription=Datos binarios +text.displayName=Texto +shellCommand.hostDescription=El host en el que ejecutar el comando +shellCommand.commandDescription=El comando que abrirá un intérprete de comandos +sshAgent=Agente SSH +none=Ninguno +commandDescription=Los comandos a ejecutar en un script de shell en el host. +commandHostDescription=El host en el que ejecutar el comando +commandDataFlowDescription=Cómo gestiona este comando la entrada y la salida +commandElevationDescription=Ejecuta este comando con permisos elevados +commandShellTypeDescription=El shell a utilizar para este comando +ssh.passwordDescription=La contraseña opcional que se utilizará al autenticarse +keyAuthentication=Autenticación basada en claves +keyAuthenticationDescription=El método de autenticación a utilizar si se requiere una autenticación basada en claves. +dontInteractWithSystem=No interactuar con el sistema (Pro) +dontInteractWithSystemDescription=No intentes identificar el shell y el tipo de sistema operativo +sshForwardX11=Adelante X11 +sshForwardX11Description=Activa el reenvío X11 para la conexión +customAgent=Agente personalizado +identityAgent=Agente de identidad +ssh.proxyDescription=El host proxy opcional que se utilizará al establecer la conexión SSH. Debe tener instalado un cliente ssh. +usage=Utilización +wslHostDescription=El host en el que se encuentra la instancia WSL. Debe tener instalado wsl. +wslDistributionDescription=El nombre de la instancia WSL +wslUsernameDescription=El nombre de usuario explícito con el que iniciar sesión. Si no se especifica, se utilizará el nombre de usuario por defecto. +wslPasswordDescription=La contraseña del usuario que se puede utilizar para los comandos sudo. +dockerHostDescription=El host en el que se encuentra el contenedor docker. Debe tener docker instalado. +dockerContainerDescription=El nombre del contenedor docker +lxdHostDescription=El host en el que se encuentra el contenedor LXD. Debe tener lxc instalado. +lxdContainerDescription=El nombre del contenedor LXD +localMachine=Máquina local +rootScan=Entorno shell raíz +loginEnvironmentScan=Entorno de inicio de sesión personalizado +k8sScan=Clúster Kubernetes +options=Opciones +dockerRunningScan=Ejecutar contenedores Docker +dockerAllScan=Todos los contenedores docker +wslScan=Instancias WSL +sshScan=Conexiones de configuración SSH +requiresElevation=Ejecutar Elevado +default=Por defecto +wslHost=Anfitrión WSL +timeout=Tiempo de espera +installLocation=Lugar de instalación +installLocationDescription=La ubicación donde está instalado tu entorno $NAME$ +wsl.displayName=Subsistema Windows para Linux +wsl.displayDescription=Conectarse a una instancia WSL que se ejecuta en Windows +docker.displayName=Contenedor Docker +docker.displayDescription=Conectarse a un contenedor Docker +podman.displayName=Contenedor Podman +podman.displayDescription=Conectarse a un contenedor Podman +lxd.displayName=Contenedor LXD +lxd.displayDescription=Conectarse a un contenedor LXD mediante lxc +container=Contenedor +host=Anfitrión +port=Puerto +user=Usuario +password=Contraseña +method=Método +uri=URL +proxy=Proxy +distribution=Distribución +username=Nombre de usuario +shellType=Tipo de carcasa +browseFile=Examinar archivo +openShell=Abrir Shell en Terminal +openCommand=Ejecutar un comando en el terminal +editFile=Editar archivo +description=Descripción +keyFile=Fichero de identidad +keyPassword=Frase de contraseña +key=Clave +furtherCustomization=Mayor personalización +furtherCustomizationDescription=Para más opciones de configuración, utiliza los archivos de configuración de ssh +location=Localización +browse=Navega por +locationDescription=La ruta del archivo de tu clave privada correspondiente +configHost=Anfitrión +configHostDescription=El host en el que se encuentra la configuración +configLocation=Ubicación de la configuración +configLocationDescription=La ruta del archivo de configuración +pageant=Concurso +gpgAgent=Agente GPG (Pro) +gateway=Pasarela +gatewayDescription=La puerta de enlace opcional que se utilizará al conectarse. +connectionInformation=Información de conexión +connectionInformationDescription=A qué sistema conectarse +passwordAuthentication=Autenticación de contraseña +passwordDescription=La contraseña opcional que se utilizará para autenticarse. +sshConfigString.displayName=Conexión SSH personalizada +sshConfigString.displayDescription=Crear una conexión SSH totalmente personalizada +sshConfigStringContent=Configuración +sshConfigStringContentDescription=Opciones SSH para la conexión en formato de configuración OpenSSH +vnc.displayName=Conexión VNC +vnc.displayDescription=Abrir una sesión VNC a través de un túnel SSH +binding=Encuadernación +vncPortDescription=El puerto en el que escucha el servidor VNC +vncUsername=Nombre de usuario +vncUsernameDescription=El nombre de usuario VNC opcional +vncPassword=Contraseña +vncPasswordDescription=La contraseña VNC +x11WslInstance=Instancia X11 Forward WSL +x11WslInstanceDescription=La distribución local del Subsistema Windows para Linux que se utilizará como servidor X11 cuando se utilice el reenvío X11 en una conexión SSH. Esta distribución debe ser una distribución WSL2.\n\nRequiere un reinicio para aplicarse. +openAsRoot=Abrir como raíz +openInVsCodeRemote=Abrir en VSCode remoto +openInWSL=Abrir en WSL +launch=Inicia diff --git a/lang/proc/strings/translations_fr.properties b/lang/proc/strings/translations_fr.properties new file mode 100644 index 000000000..ca08ad4cb --- /dev/null +++ b/lang/proc/strings/translations_fr.properties @@ -0,0 +1,297 @@ +showInternalPods=Montre les cosses internes +showAllNamespaces=Afficher tous les espaces de noms +showInternalContainers=Afficher les conteneurs internes +refresh=Rafraîchir +vmwareGui=Démarrer l'interface graphique +monitorVm=Moniteur VM +addCluster=Ajouter une grappe ... +showNonRunningInstances=Afficher les instances non exécutées +vmwareGuiDescription=S'il faut démarrer une machine virtuelle en arrière-plan ou dans une fenêtre. +vmwareEncryptionPassword=Mot de passe de cryptage +vmwareEncryptionPasswordDescription=Le mot de passe facultatif utilisé pour crypter la VM. +vmwarePasswordDescription=Le mot de passe requis pour l'utilisateur invité. +vmwarePassword=Mot de passe de l'utilisateur +vmwareUser=Utilisateur invité +runTempContainer=Exécuter un conteneur temporaire +vmwareUserDescription=Le nom d'utilisateur de l'invité principal +dockerTempRunAlertTitle=Exécuter un conteneur temporaire +dockerTempRunAlertHeader=Cela permet d'exécuter un processus shell dans un conteneur temporaire qui sera automatiquement supprimé une fois qu'il aura été arrêté. +imageName=Nom de l'image +imageNameDescription=L'identifiant de l'image du conteneur à utiliser +containerName=Nom du conteneur +containerNameDescription=Le nom facultatif du conteneur personnalisé +vm=Machine virtuelle +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Le fichier de configuration associé. +vmwareScan=Hyperviseurs de bureau VMware +library=Bibliothèque +customPkcs11Library=Bibliothèque PKCS#11 personnalisée (Pro) +vmwareMachine.displayName=Machine virtuelle VMware +vmwareMachine.displayDescription=Se connecter à une machine virtuelle via SSH +vmwareInstallation.displayName=Installation de l'hyperviseur de bureau VMware +vmwareInstallation.displayDescription=Interagir avec les machines virtuelles installées par l'intermédiaire de son CLI +start=Démarrer +stop=Arrêter +pause=Pause +rdpTunnelHost=Hôte du tunnel +rdpTunnelHostDescription=La connexion SSH optionnelle à utiliser comme tunnel +rdpFileLocation=Emplacement du fichier +rdpFileLocationDescription=Le chemin d'accès au fichier .rdp +rdpPasswordAuthentication=Authentification par mot de passe +rdpPasswordAuthenticationDescription=Le mot de passe à remplir automatiquement s'il est pris en charge +rdpFile.displayName=Fichier RDP +rdpFile.displayDescription=Se connecter à un système via un fichier .rdp existant +requiredSshServerAlertTitle=Configurer le serveur SSH +requiredSshServerAlertHeader=Impossible de trouver un serveur SSH installé dans la VM. +requiredSshServerAlertContent=Pour se connecter à la VM, XPipe recherche un serveur SSH en cours d'exécution mais aucun serveur SSH disponible n'a été détecté pour la VM... +computerName=Nom de l'ordinateur +pssComputerNameDescription=Le nom de l'ordinateur auquel se connecter. On suppose qu'il est déjà inclus dans tes hôtes de confiance. +credentialUser=Utilisateur de justificatifs +pssCredentialUserDescription=L'utilisateur sous lequel tu dois te connecter. +credentialPassword=Mot de passe d'identification +pssCredentialPasswordDescription=Le mot de passe de l'utilisateur. +sshConfig=Fichiers de configuration SSH +autostart=Se connecter automatiquement au démarrage de XPipe +acceptHostKey=Accepter la clé de l'hôte +modifyHostKeyPermissions=Modifier les permissions de la clé de l'hôte +attachContainer=Attacher à un contenant +openInVsCode=Ouvrir en VSCode +containerLogs=Afficher les journaux des conteneurs +openSftpClient=Ouvrir dans un client SFTP externe +openTermius=Ouvrir dans Termius +showInternalInstances=Afficher les instances internes +editPod=Editer le pod +acceptHostKeyDescription=Fais confiance à la nouvelle clé de l'hôte et continue +modifyHostKeyPermissionsDescription=Tente de supprimer les permissions du fichier d'origine pour que OpenSSH soit satisfait +psSession.displayName=Session à distance PowerShell +psSession.displayDescription=Se connecter via New-PSSession et Enter-PSSession +sshLocalTunnel.displayName=Tunnel SSH local +sshLocalTunnel.displayDescription=Établir un tunnel SSH vers un hôte distant +sshRemoteTunnel.displayName=Tunnel SSH à distance +sshRemoteTunnel.displayDescription=Établir un tunnel SSH inverse à partir d'un hôte distant +sshDynamicTunnel.displayName=Tunnel SSH dynamique +sshDynamicTunnel.displayDescription=Établir un proxy SOCKS par le biais d'une connexion SSH +shellEnvironmentGroup.displayName=Environnements Shell +shellEnvironmentGroup.displayDescription=Environnements Shell +shellEnvironment.displayName=Environnement Shell personnalisé +shellEnvironment.displayDescription=Créer un environnement d'initialisation de l'interpréteur de commandes personnalisé +shellEnvironment.informationFormat=$TYPE$ l'environnement +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ l'environnement +environmentConnectionDescription=La connexion de base pour créer un environnement pour +environmentScriptDescription=Le script d'initialisation personnalisé facultatif à exécuter dans l'interpréteur de commandes +environmentSnippets=Extraits de scripts +commandSnippetsDescription=Les extraits de scripts prédéfinis facultatifs à exécuter en premier +environmentSnippetsDescription=Les extraits de scripts prédéfinis facultatifs à exécuter lors de l'initialisation +shellTypeDescription=Le type de shell explicite à lancer +originPort=Port d'origine +originAddress=Adresse d'origine +remoteAddress=Adresse à distance +remotePort=Port distant +remoteSourceAddress=Adresse de la source distante +remoteSourcePort=Port source à distance +originDestinationPort=Origine destination port +originDestinationAddress=Adresse d'origine et de destination +origin=Origine +remoteHost=Hôte distant +address=Adresse +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Se connecter à des systèmes dans un environnement virtuel Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Se connecter à une machine virtuelle dans un Proxmox VE via SSH +proxmoxContainer.displayName=Conteneur Proxmox +proxmoxContainer.displayDescription=Se connecter à un conteneur dans un Proxmox VE +sshDynamicTunnel.originDescription=Le système à partir duquel ouvrir la connexion ssh +sshDynamicTunnel.hostDescription=Le système à utiliser comme proxy SOCKS +sshDynamicTunnel.bindingDescription=A quelles adresses lier le tunnel +sshRemoteTunnel.originDescription=Le système à partir duquel il faut ouvrir la connexion ssh et ouvrir le tunnel vers.. +sshRemoteTunnel.hostDescription=Le système à partir duquel démarrer le tunnel à distance vers l'origine +sshRemoteTunnel.bindingDescription=A quelles adresses lier le tunnel +sshLocalTunnel.originDescription=Le système à partir duquel il faut commencer le tunnel +sshLocalTunnel.hostDescription=Le système pour ouvrir le tunnel vers +sshLocalTunnel.bindingDescription=A quelles adresses lier le tunnel +sshLocalTunnel.localAddressDescription=L'adresse locale à lier +sshLocalTunnel.remoteAddressDescription=L'adresse distante à lier +cmd.displayName=Commande personnalisée du terminal +cmd.displayDescription=Exécute une commande personnalisée sur un système dans ton terminal +k8sPod.displayName=Pod Kubernetes +k8sPod.displayDescription=Se connecter à un pod et à ses conteneurs via kubectl +k8sContainer.displayName=Conteneur Kubernetes +k8sContainer.displayDescription=Ouvrir un shell à un conteneur +k8sCluster.displayName=Cluster Kubernetes +k8sCluster.displayDescription=Se connecter à un cluster et à ses pods via kubectl +sshTunnelGroup.displayName=Tunnels SSH +sshTunnelGroup.displayCategory=Tous les types de tunnels SSH +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Accéder aux conteneurs Podman via le client CLI +podmanContainers=Conteneurs Podman +local.displayName=Machine locale +local.displayDescription=Le shell de la machine locale +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git pour Windows +gitForWindows.displayName=Git pour Windows +gitForWindows.displayDescription=Accède à ton environnement local Git pour Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Les shells d'accès de ton environnement MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Accède aux shells de ton environnement Cygwin +namespace=Espace de noms +gitVaultIdentityStrategy=Identité SSH Git +gitVaultIdentityStrategyDescription=Si tu as choisi d'utiliser une URL SSH git comme distant et que ton dépôt distant nécessite une identité SSH, alors définis cette option.\n\nSi tu as fourni une URL HTTP, tu peux ignorer cette option. +dockerContainers=Conteneurs Docker +lxdContainers=Conteneurs LXD +dockerCmd.displayName=client CLI de docker +dockerCmd.displayDescription=Accède aux conteneurs Docker via le client CLI de Docker +lxdCmd.displayName=Client CLI LXD +lxdCmd.displayDescription=Accéder aux conteneurs LXD via le CLI lxc cient +wslCmd.displayName=client wsl +wslCmd.displayDescription=Accéder aux instances WSL via le CLI wsl cient +k8sCmd.displayName=client kubectl +k8sCmd.displayDescription=Accéder aux clusters Kubernetes via kubectl +k8sClusters=Clusters Kubernetes +shells=Coquilles disponibles +startContainer=Conteneur de départ +stopContainer=Arrêter le conteneur +inspectContainer=Inspecter le conteneur +k8sClusterNameDescription=Le nom du contexte dans lequel se trouve le cluster. +pod=Cosse +podName=Nom du pod +k8sClusterContext=Contexte +k8sClusterContextDescription=Le nom du contexte dans lequel se trouve le cluster +k8sClusterNamespace=Espace de noms +k8sClusterNamespaceDescription=L'espace de noms personnalisé ou l'espace de noms par défaut s'il est vide +k8sConfigLocation=Fichier de configuration +k8sConfigLocationDescription=Le fichier kubeconfig personnalisé ou celui par défaut s'il est laissé vide +inspectPod=Inspecter la capsule +showAllContainers=Afficher les conteneurs qui ne fonctionnent pas +showAllPods=Afficher les pods qui ne fonctionnent pas +wsl=WSL +docker=Docker +k8sPodHostDescription=L'hôte sur lequel se trouve le pod +k8sContainerDescription=Le nom du conteneur Kubernetes +k8sPodDescription=Le nom du pod Kubernetes +podDescription=Le pod sur lequel se trouve le conteneur +k8sClusterHostDescription=L'hôte par lequel il faut accéder au cluster. Doit avoir kubectl installé et configuré pour pouvoir accéder au cluster. +script=Script d'initialisation +connection=Connexion +shellCommand.displayName=Commande d'ouverture de shell personnalisée +shellCommand.displayDescription=Ouvrir un shell standard par le biais d'une commande personnalisée +ssh.displayName=Connexion SSH simple +ssh.displayDescription=Se connecter via un client de ligne de commande SSH +sshConfig.displayName=Fichier de configuration SSH +sshConfig.displayDescription=Se connecter aux hôtes définis dans un fichier de configuration SSH +sshConfigHost.displayName=Fichier de configuration SSH Hôte +sshConfigHost.displayDescription=Se connecter à un hôte défini dans un fichier de configuration SSH +sshConfigHost.password=Mot de passe +sshConfigHost.passwordDescription=Fournir le mot de passe facultatif pour la connexion de l'utilisateur. +sshConfigHost.identityPassphrase=Phrase d'identité +sshConfigHost.identityPassphraseDescription=Indique la phrase de passe facultative pour ta clé d'identité. +binary.displayName=Binaire +binary.displayDescription=Données binaires +text.displayName=Texte +shellCommand.hostDescription=L'hôte sur lequel exécuter la commande +shellCommand.commandDescription=La commande qui ouvre un shell +sshAgent=Agent SSH +none=Aucun +commandDescription=Les commandes à exécuter dans un script shell sur l'hôte. +commandHostDescription=L'hôte sur lequel exécuter la commande +commandDataFlowDescription=Comment cette commande gère les entrées et les sorties +commandElevationDescription=Exécute cette commande avec des autorisations élevées +commandShellTypeDescription=L'interpréteur de commandes à utiliser pour cette commande +ssh.passwordDescription=Le mot de passe facultatif à utiliser lors de l'authentification +keyAuthentication=Authentification par clé +keyAuthenticationDescription=La méthode d'authentification à utiliser si l'authentification par clé est requise. +dontInteractWithSystem=Ne pas interagir avec le système (Pro) +dontInteractWithSystemDescription=N'essaie pas d'identifier le type de shell et de système d'exploitation +sshForwardX11=Faire suivre X11 +sshForwardX11Description=Active le transfert X11 pour la connexion +customAgent=Agent personnalisé +identityAgent=Agent d'identité +ssh.proxyDescription=L'hôte proxy facultatif à utiliser lors de l'établissement de la connexion SSH. Un client ssh doit être installé. +usage=Utilisation +wslHostDescription=L'hôte sur lequel se trouve l'instance WSL. Doit avoir installé wsl. +wslDistributionDescription=Le nom de l'instance WSL +wslUsernameDescription=Le nom d'utilisateur explicite sous lequel se connecter. S'il n'est pas spécifié, le nom d'utilisateur par défaut sera utilisé. +wslPasswordDescription=Le mot de passe de l'utilisateur qui peut être utilisé pour les commandes sudo. +dockerHostDescription=L'hôte sur lequel se trouve le conteneur docker. Doit avoir installé docker. +dockerContainerDescription=Le nom du conteneur docker +lxdHostDescription=L'hôte sur lequel se trouve le conteneur LXD. Lxc doit être installé. +lxdContainerDescription=Le nom du conteneur LXD +localMachine=Machine locale +rootScan=Environnement de l'interpréteur de commandes racine +loginEnvironmentScan=Environnement de connexion personnalisé +k8sScan=Cluster Kubernetes +options=Options +dockerRunningScan=Exécuter des conteneurs docker +dockerAllScan=Tous les conteneurs docker +wslScan=Instances WSL +sshScan=Connexions de configuration SSH +requiresElevation=Exécuter en hauteur +default=Défaut +wslHost=Hôte WSL +timeout=Délai d'attente +installLocation=Emplacement de l'installation +installLocationDescription=L'endroit où ton environnement $NAME$ est installé +wsl.displayName=Sous-système Windows pour Linux +wsl.displayDescription=Se connecter à une instance WSL fonctionnant sous Windows +docker.displayName=Conteneur Docker +docker.displayDescription=Se connecter à un conteneur docker +podman.displayName=Conteneur Podman +podman.displayDescription=Se connecter à un conteneur Podman +lxd.displayName=Conteneur LXD +lxd.displayDescription=Se connecter à un conteneur LXD via lxc +container=Conteneur +host=Hôte +port=Port +user=Utilisateur +password=Mot de passe +method=Méthode +uri=URL +proxy=Proxy +distribution=Distribution +username=Nom d'utilisateur +shellType=Type de coquille +browseFile=Parcourir le fichier +openShell=Ouvrir le shell dans le terminal +openCommand=Exécuter une commande dans le terminal +editFile=Editer le fichier +description=Description +keyFile=Fichier d'identité +keyPassword=Phrase de passe +key=Clé +furtherCustomization=Personnalisation supplémentaire +furtherCustomizationDescription=Pour plus d'options de configuration, utilise les fichiers de configuration ssh +location=Lieu +browse=Parcourir +locationDescription=Le chemin d'accès au fichier de ta clé privée correspondante +configHost=Hôte +configHostDescription=L'hôte sur lequel se trouve le config +configLocation=Emplacement de la configuration +configLocationDescription=Le chemin d'accès au fichier de configuration +pageant=Pageant +gpgAgent=Agent GPG (Pro) +gateway=Passerelle +gatewayDescription=La passerelle optionnelle à utiliser lors de la connexion. +connectionInformation=Informations sur la connexion +connectionInformationDescription=A quel système se connecter +passwordAuthentication=Authentification par mot de passe +passwordDescription=Le mot de passe facultatif à utiliser pour s'authentifier. +sshConfigString.displayName=Connexion SSH personnalisée +sshConfigString.displayDescription=Créer une connexion SSH entièrement personnalisée +sshConfigStringContent=Configuration +sshConfigStringContentDescription=Options SSH pour la connexion au format OpenSSH config +vnc.displayName=Connexion VNC +vnc.displayDescription=Ouvrir une session VNC via un tunnel SSH +binding=Reliure +vncPortDescription=Le port sur lequel le serveur VNC écoute +vncUsername=Nom d'utilisateur +vncUsernameDescription=Le nom d'utilisateur optionnel de VNC +vncPassword=Mot de passe +vncPasswordDescription=Le mot de passe VNC +x11WslInstance=Instance X11 Forward WSL +x11WslInstanceDescription=La distribution locale du sous-système Windows pour Linux à utiliser comme serveur X11 lors de l'utilisation du transfert X11 dans une connexion SSH. Cette distribution doit être une distribution WSL2.\n\nUn redémarrage est nécessaire pour l'appliquer. +openAsRoot=Ouvrir en tant que racine +openInVsCodeRemote=Ouvrir en VSCode à distance +openInWSL=Ouvrir en WSL +launch=Lancer diff --git a/lang/proc/strings/translations_it.properties b/lang/proc/strings/translations_it.properties new file mode 100644 index 000000000..a476d9a13 --- /dev/null +++ b/lang/proc/strings/translations_it.properties @@ -0,0 +1,297 @@ +showInternalPods=Mostra i pod interni +showAllNamespaces=Mostra tutti gli spazi dei nomi +showInternalContainers=Mostra i contenitori interni +refresh=Aggiornare +vmwareGui=Avvio dell'interfaccia grafica +monitorVm=Monitor VM +addCluster=Aggiungi cluster ... +showNonRunningInstances=Mostra le istanze non in esecuzione +vmwareGuiDescription=Se avviare una macchina virtuale in background o in una finestra. +vmwareEncryptionPassword=Password di crittografia +vmwareEncryptionPasswordDescription=La password opzionale utilizzata per criptare la VM. +vmwarePasswordDescription=La password richiesta per l'utente ospite. +vmwarePassword=Password utente +vmwareUser=Utente ospite +runTempContainer=Eseguire un contenitore temporaneo +vmwareUserDescription=Il nome utente dell'utente ospite principale +dockerTempRunAlertTitle=Eseguire un contenitore temporaneo +dockerTempRunAlertHeader=Esegue un processo di shell in un contenitore temporaneo che verrà rimosso automaticamente una volta terminato. +imageName=Nome dell'immagine +imageNameDescription=L'identificatore dell'immagine del contenitore da utilizzare +containerName=Nome del contenitore +containerNameDescription=Il nome opzionale del contenitore personalizzato +vm=Macchina virtuale +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Il file di configurazione associato. +vmwareScan=Ipervisori desktop VMware +library=Biblioteca +customPkcs11Library=Libreria PKCS#11 personalizzata (Pro) +vmwareMachine.displayName=Macchina virtuale VMware +vmwareMachine.displayDescription=Connettersi a una macchina virtuale tramite SSH +vmwareInstallation.displayName=Installazione dell'hypervisor desktop VMware +vmwareInstallation.displayDescription=Interagire con le macchine virtuali installate tramite la sua CLI +start=Iniziare +stop=Fermati +pause=Pausa +rdpTunnelHost=Tunnel host +rdpTunnelHostDescription=La connessione SSH opzionale da utilizzare come tunnel +rdpFileLocation=Posizione del file +rdpFileLocationDescription=Il percorso del file .rdp +rdpPasswordAuthentication=Password di autenticazione +rdpPasswordAuthenticationDescription=La password da inserire automaticamente se supportata +rdpFile.displayName=File RDP +rdpFile.displayDescription=Collegarsi a un sistema tramite un file .rdp esistente +requiredSshServerAlertTitle=Configurazione del server SSH +requiredSshServerAlertHeader=Impossibile trovare un server SSH installato nella macchina virtuale. +requiredSshServerAlertContent=Per connettersi alla macchina virtuale, XPipe sta cercando un server SSH funzionante, ma non è stato rilevato alcun server SSH disponibile per la macchina virtuale. +computerName=Nome del computer +pssComputerNameDescription=Il nome del computer a cui connettersi. Si presume che sia già incluso negli host attendibili. +credentialUser=Credenziale Utente +pssCredentialUserDescription=L'utente con cui effettuare il login. +credentialPassword=Password della credenziale +pssCredentialPasswordDescription=La password dell'utente. +sshConfig=File di configurazione SSH +autostart=Connettersi automaticamente all'avvio di XPipe +acceptHostKey=Accetta la chiave host +modifyHostKeyPermissions=Modificare i permessi della chiave host +attachContainer=Collegare al contenitore +openInVsCode=Apri in VSCode +containerLogs=Mostra i log del contenitore +openSftpClient=Aprire in un client SFTP esterno +openTermius=Apri in Termius +showInternalInstances=Mostra le istanze interne +editPod=Modifica pod +acceptHostKeyDescription=Fidati della nuova chiave host e continua +modifyHostKeyPermissionsDescription=Tentare di rimuovere i permessi del file originale in modo che OpenSSH sia soddisfatto +psSession.displayName=Sessione remota PowerShell +psSession.displayDescription=Connettersi tramite New-PSSession e Enter-PSSession +sshLocalTunnel.displayName=Tunnel SSH locale +sshLocalTunnel.displayDescription=Stabilire un tunnel SSH verso un host remoto +sshRemoteTunnel.displayName=Tunnel SSH remoto +sshRemoteTunnel.displayDescription=Stabilire un tunnel SSH inverso da un host remoto +sshDynamicTunnel.displayName=Tunnel SSH dinamico +sshDynamicTunnel.displayDescription=Stabilire un proxy SOCKS attraverso una connessione SSH +shellEnvironmentGroup.displayName=Ambienti shell +shellEnvironmentGroup.displayDescription=Ambienti shell +shellEnvironment.displayName=Ambiente Shell personalizzato +shellEnvironment.displayDescription=Creare un ambiente di init della shell personalizzato +shellEnvironment.informationFormat=$TYPE$ ambiente +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ ambiente +environmentConnectionDescription=La connessione di base per creare un ambiente per +environmentScriptDescription=Lo script di avvio personalizzato opzionale da eseguire nella shell +environmentSnippets=Snippet di script +commandSnippetsDescription=Gli snippet di script predefiniti opzionali da eseguire per primi +environmentSnippetsDescription=Gli snippet di script predefiniti opzionali da eseguire all'inizializzazione +shellTypeDescription=Il tipo di shell esplicita da lanciare +originPort=Porta di origine +originAddress=Indirizzo di origine +remoteAddress=Indirizzo remoto +remotePort=Porta remota +remoteSourceAddress=Indirizzo sorgente remoto +remoteSourcePort=Porta sorgente remota +originDestinationPort=Porta di origine e destinazione +originDestinationAddress=Indirizzo di origine e destinazione +origin=Origine +remoteHost=Host remoto +address=Indirizzo +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Connettersi ai sistemi in un ambiente virtuale Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Connettersi a una macchina virtuale in un VE Proxmox tramite SSH +proxmoxContainer.displayName=Contenitore Proxmox +proxmoxContainer.displayDescription=Connettersi a un contenitore in un VE Proxmox +sshDynamicTunnel.originDescription=Il sistema da cui aprire la connessione ssh +sshDynamicTunnel.hostDescription=Il sistema da utilizzare come proxy SOCKS +sshDynamicTunnel.bindingDescription=Quali sono gli indirizzi a cui associare il tunnel +sshRemoteTunnel.originDescription=Il sistema da cui aprire la connessione ssh e aprire il tunnel verso +sshRemoteTunnel.hostDescription=Il sistema da cui far partire il tunnel remoto verso l'origine +sshRemoteTunnel.bindingDescription=Quali sono gli indirizzi a cui associare il tunnel +sshLocalTunnel.originDescription=Il sistema da cui iniziare il tunnel +sshLocalTunnel.hostDescription=Il sistema per aprire il tunnel a +sshLocalTunnel.bindingDescription=Quali sono gli indirizzi a cui associare il tunnel +sshLocalTunnel.localAddressDescription=L'indirizzo locale a cui fare il bind +sshLocalTunnel.remoteAddressDescription=L'indirizzo remoto a cui fare il bind +cmd.displayName=Comando terminale personalizzato +cmd.displayDescription=Esegui un comando personalizzato su un sistema nel tuo terminale +k8sPod.displayName=Pod Kubernetes +k8sPod.displayDescription=Connettersi a un pod e ai suoi contenitori tramite kubectl +k8sContainer.displayName=Contenitore Kubernetes +k8sContainer.displayDescription=Aprire una shell in un contenitore +k8sCluster.displayName=Cluster Kubernetes +k8sCluster.displayDescription=Connettersi a un cluster e ai suoi pod tramite kubectl +sshTunnelGroup.displayName=Tunnel SSH +sshTunnelGroup.displayCategory=Tutti i tipi di tunnel SSH +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Accedere ai contenitori Podman tramite il client CLI +podmanContainers=Contenitori Podman +local.displayName=Macchina locale +local.displayDescription=La shell della macchina locale +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git per Windows +gitForWindows.displayName=Git per Windows +gitForWindows.displayDescription=Accedi all'ambiente locale di Git per Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Gusci di accesso del tuo ambiente MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Accesso alle shell dell'ambiente Cygwin +namespace=Spazio dei nomi +gitVaultIdentityStrategy=Identità Git SSH +gitVaultIdentityStrategyDescription=Se hai scelto di utilizzare un URL git SSH come remoto e il tuo repository remoto richiede un'identità SSH, imposta questa opzione.\n\nSe hai fornito un URL HTTP, puoi ignorare questa opzione. +dockerContainers=Contenitori Docker +lxdContainers=Contenitori LXD +dockerCmd.displayName=client docker CLI +dockerCmd.displayDescription=Accedere ai contenitori Docker tramite il client docker CLI +lxdCmd.displayName=Client CLI LXD +lxdCmd.displayDescription=Accesso ai contenitori LXD tramite la CLI lxc cient +wslCmd.displayName=client wsl +wslCmd.displayDescription=Accesso alle istanze WSL tramite la CLI wsl cient +k8sCmd.displayName=client kubectl +k8sCmd.displayDescription=Accedere ai cluster Kubernetes tramite kubectl +k8sClusters=Cluster Kubernetes +shells=Gusci disponibili +startContainer=Contenitore iniziale +stopContainer=Contenitore di arresto +inspectContainer=Ispezionare il contenitore +k8sClusterNameDescription=Il nome del contesto in cui si trova il cluster. +pod=Pod +podName=Nome del pod +k8sClusterContext=Contesto +k8sClusterContextDescription=Il nome del contesto in cui si trova il cluster +k8sClusterNamespace=Spazio dei nomi +k8sClusterNamespaceDescription=Lo spazio dei nomi personalizzato o quello predefinito se vuoto +k8sConfigLocation=File di configurazione +k8sConfigLocationDescription=Il file kubeconfig personalizzato o quello predefinito se lasciato vuoto +inspectPod=Ispezionare il pod +showAllContainers=Mostra i contenitori non in esecuzione +showAllPods=Mostra i pod non in esecuzione +wsl=WSL +docker=Docker +k8sPodHostDescription=L'host su cui si trova il pod +k8sContainerDescription=Il nome del contenitore Kubernetes +k8sPodDescription=Il nome del pod Kubernetes +podDescription=Il pod su cui si trova il contenitore +k8sClusterHostDescription=L'host attraverso il quale si deve accedere al cluster. Deve avere kubectl installato e configurato per poter accedere al cluster. +script=Script Init +connection=Connessione +shellCommand.displayName=Comando personalizzato di apertura della shell +shellCommand.displayDescription=Aprire una shell standard attraverso un comando personalizzato +ssh.displayName=Connessione SSH semplice +ssh.displayDescription=Connettersi tramite un client a riga di comando SSH +sshConfig.displayName=File di configurazione SSH +sshConfig.displayDescription=Connettersi agli host definiti in un file di configurazione SSH +sshConfigHost.displayName=File di configurazione SSH Host +sshConfigHost.displayDescription=Connettersi a un host definito in un file di configurazione SSH +sshConfigHost.password=Password +sshConfigHost.passwordDescription=Fornisce la password opzionale per il login dell'utente. +sshConfigHost.identityPassphrase=Passphrase di identità +sshConfigHost.identityPassphraseDescription=Fornisci la passphrase opzionale per la tua chiave di identità. +binary.displayName=Binario +binary.displayDescription=Dati binari +text.displayName=Testo +shellCommand.hostDescription=L'host su cui eseguire il comando +shellCommand.commandDescription=Il comando che apre una shell +sshAgent=Agente SSH +none=Nessuno +commandDescription=I comandi da eseguire in uno script di shell sull'host. +commandHostDescription=L'host su cui eseguire il comando +commandDataFlowDescription=Come questo comando gestisce l'input e l'output +commandElevationDescription=Esegui questo comando con permessi elevati +commandShellTypeDescription=La shell da utilizzare per questo comando +ssh.passwordDescription=La password opzionale da utilizzare per l'autenticazione +keyAuthentication=Autenticazione basata su chiavi +keyAuthenticationDescription=Il metodo di autenticazione da utilizzare se è richiesta un'autenticazione basata su chiavi. +dontInteractWithSystem=Non interagire con il sistema (Pro) +dontInteractWithSystemDescription=Non cercare di identificare la shell e il tipo di sistema operativo +sshForwardX11=Avanti X11 +sshForwardX11Description=Abilita l'inoltro X11 per la connessione +customAgent=Agente personalizzato +identityAgent=Agente di identità +ssh.proxyDescription=L'host proxy opzionale da utilizzare per stabilire la connessione SSH. Deve essere installato un client ssh. +usage=Utilizzo +wslHostDescription=L'host su cui si trova l'istanza WSL. Deve essere installato wsl. +wslDistributionDescription=Il nome dell'istanza WSL +wslUsernameDescription=Il nome utente esplicito con cui effettuare il login. Se non viene specificato, verrà utilizzato il nome utente predefinito. +wslPasswordDescription=La password dell'utente che può essere utilizzata per i comandi sudo. +dockerHostDescription=L'host su cui si trova il contenitore docker. Deve essere installato docker. +dockerContainerDescription=Il nome del contenitore docker +lxdHostDescription=L'host su cui si trova il contenitore LXD. Deve essere installato lxc. +lxdContainerDescription=Il nome del contenitore LXD +localMachine=Macchina locale +rootScan=Ambiente shell root +loginEnvironmentScan=Ambiente di login personalizzato +k8sScan=Cluster Kubernetes +options=Opzioni +dockerRunningScan=Esecuzione di container docker +dockerAllScan=Tutti i contenitori docker +wslScan=Istanze WSL +sshScan=Connessioni di configurazione SSH +requiresElevation=Esecuzione elevata +default=Predefinito +wslHost=Host WSL +timeout=Timeout +installLocation=Posizione di installazione +installLocationDescription=La posizione in cui è installato l'ambiente $NAME$ +wsl.displayName=Sottosistema Windows per Linux +wsl.displayDescription=Connettersi a un'istanza WSL in esecuzione su Windows +docker.displayName=Contenitore Docker +docker.displayDescription=Connettersi a un container docker +podman.displayName=Contenitore Podman +podman.displayDescription=Connettersi a un contenitore Podman +lxd.displayName=Contenitore LXD +lxd.displayDescription=Connettersi a un contenitore LXD tramite lxc +container=Contenitore +host=Ospite +port=Porta +user=Utente +password=Password +method=Metodo +uri=URL +proxy=Proxy +distribution=Distribuzione +username=Nome utente +shellType=Tipo di conchiglia +browseFile=Sfogliare un file +openShell=Aprire la Shell nel Terminale +openCommand=Eseguire un comando nel terminale +editFile=Modifica file +description=Descrizione +keyFile=File di identità +keyPassword=Passphrase +key=Chiave di lettura +furtherCustomization=Ulteriore personalizzazione +furtherCustomizationDescription=Per ulteriori opzioni di configurazione, usa i file di configurazione di ssh +location=Posizione +browse=Sfogliare +locationDescription=Il percorso del file della chiave privata corrispondente +configHost=Ospite +configHostDescription=L'host su cui si trova la configurazione +configLocation=Posizione della configurazione +configLocationDescription=Il percorso del file di configurazione +pageant=Pagina +gpgAgent=Agente GPG (Pro) +gateway=Gateway +gatewayDescription=Il gateway opzionale da utilizzare per la connessione. +connectionInformation=Informazioni sulla connessione +connectionInformationDescription=A quale sistema connettersi +passwordAuthentication=Password di autenticazione +passwordDescription=La password opzionale da utilizzare per l'autenticazione. +sshConfigString.displayName=Connessione SSH personalizzata +sshConfigString.displayDescription=Crea una connessione SSH completamente personalizzata +sshConfigStringContent=Configurazione +sshConfigStringContentDescription=Opzioni SSH per la connessione in formato OpenSSH config +vnc.displayName=Connessione VNC +vnc.displayDescription=Aprire una sessione VNC tramite un tunnel SSH +binding=Rilegatura +vncPortDescription=La porta su cui è in ascolto il server VNC +vncUsername=Nome utente +vncUsernameDescription=Il nome utente VNC opzionale +vncPassword=Password +vncPasswordDescription=La password di VNC +x11WslInstance=Istanza X11 Forward WSL +x11WslInstanceDescription=La distribuzione locale di Windows Subsystem for Linux da utilizzare come server X11 quando si utilizza l'inoltro X11 in una connessione SSH. Questa distribuzione deve essere una distribuzione WSL2.\n\nRichiede un riavvio per essere applicata. +openAsRoot=Apri come root +openInVsCodeRemote=Aprire in VSCode remoto +openInWSL=Aprire in WSL +launch=Lancio diff --git a/lang/proc/strings/translations_ja.properties b/lang/proc/strings/translations_ja.properties new file mode 100644 index 000000000..6d576e6e0 --- /dev/null +++ b/lang/proc/strings/translations_ja.properties @@ -0,0 +1,297 @@ +showInternalPods=内部ポッドを表示する +showAllNamespaces=すべての名前空間を表示する +showInternalContainers=内部コンテナを表示する +refresh=リフレッシュする +vmwareGui=GUIを起動する +monitorVm=モニターVM +addCluster=クラスターを追加する +showNonRunningInstances=実行されていないインスタンスを表示する +vmwareGuiDescription=仮想マシンをバックグラウンドで起動するか、ウィンドウで起動するか。 +vmwareEncryptionPassword=暗号化パスワード +vmwareEncryptionPasswordDescription=VMを暗号化するためのオプションのパスワード。 +vmwarePasswordDescription=ゲストユーザーに必要なパスワード。 +vmwarePassword=ユーザーパスワード +vmwareUser=ゲストユーザー +runTempContainer=一時コンテナを実行する +vmwareUserDescription=プライマリゲストユーザーのユーザー名 +dockerTempRunAlertTitle=一時コンテナを実行する +dockerTempRunAlertHeader=これは一時的なコンテナでシェルプロセスを実行し、停止されると自動的に削除される。 +imageName=画像名 +imageNameDescription=使用するコンテナ画像識別子 +containerName=コンテナ名 +containerNameDescription=オプションのカスタムコンテナ名 +vm=仮想マシン +yubikeyPiv=ユビキーPIV(プロ) +vmDescription=関連する設定ファイル。 +vmwareScan=VMwareデスクトップハイパーバイザー +library=ライブラリ +customPkcs11Library=カスタムPKCS#11ライブラリ(Pro) +vmwareMachine.displayName=VMware仮想マシン +vmwareMachine.displayDescription=SSH経由で仮想マシンに接続する +vmwareInstallation.displayName=VMwareデスクトップハイパーバイザーのインストール +vmwareInstallation.displayDescription=CLI経由でインストールされたVMと対話する +start=スタート +stop=停止する +pause=一時停止 +rdpTunnelHost=トンネルホスト +rdpTunnelHostDescription=トンネルとして使用するオプションのSSH接続 +rdpFileLocation=ファイルの場所 +rdpFileLocationDescription=.rdpファイルのファイルパス +rdpPasswordAuthentication=パスワード認証 +rdpPasswordAuthenticationDescription=サポートされている場合、自動的に入力されるパスワード +rdpFile.displayName=RDPファイル +rdpFile.displayDescription=既存の.rdpファイルを介してシステムに接続する +requiredSshServerAlertTitle=SSHサーバーをセットアップする +requiredSshServerAlertHeader=VMにインストールされているSSHサーバーが見つからない。 +requiredSshServerAlertContent=VMに接続するため、XPipeは稼働中のSSHサーバーを探しているが、VMで利用可能なSSHサーバーが検出されなかった。 +computerName=コンピュータ名 +pssComputerNameDescription=接続先のコンピュータ名。すでに信頼済みホストに含まれているものとする。 +credentialUser=クレデンシャル・ユーザー +pssCredentialUserDescription=ログインするユーザー +credentialPassword=クレデンシャルパスワード +pssCredentialPasswordDescription=ユーザーのパスワード。 +sshConfig=SSH設定ファイル +autostart=XPipe起動時に自動的に接続する +acceptHostKey=ホスト・キーを受け付ける +modifyHostKeyPermissions=ホストキーのパーミッションを変更する +attachContainer=コンテナに取り付ける +openInVsCode=VSCodeで開く +containerLogs=コンテナのログを表示する +openSftpClient=外部のSFTPクライアントで開く +openTermius=テルミウスで開く +showInternalInstances=内部インスタンスを表示する +editPod=ポッドを編集する +acceptHostKeyDescription=新しいホスト・キーを信頼して続行する +modifyHostKeyPermissionsDescription=OpenSSHが満足するように、オリジナルファイルのパーミッションの削除を試みる。 +psSession.displayName=PowerShellリモートセッション +psSession.displayDescription=New-PSSessionとEnter-PSSessionで接続する。 +sshLocalTunnel.displayName=ローカルSSHトンネル +sshLocalTunnel.displayDescription=リモートホストへのSSHトンネルを確立する +sshRemoteTunnel.displayName=リモートSSHトンネル +sshRemoteTunnel.displayDescription=リモートホストから逆SSHトンネルを確立する +sshDynamicTunnel.displayName=動的SSHトンネル +sshDynamicTunnel.displayDescription=SSH接続でSOCKSプロキシを確立する +shellEnvironmentGroup.displayName=シェル環境 +shellEnvironmentGroup.displayDescription=シェル環境 +shellEnvironment.displayName=カスタムシェル環境 +shellEnvironment.displayDescription=カスタマイズされたシェルinit環境を作成する +shellEnvironment.informationFormat=$TYPE$ 環境 +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ 環境 +environmentConnectionDescription=の環境を作るためのベースとなる接続 +environmentScriptDescription=シェルで実行するカスタムinitスクリプト(オプション +environmentSnippets=スクリプトスニペット +commandSnippetsDescription=最初に実行する定義済みスクリプトスニペット(オプション +environmentSnippetsDescription=初期化時に実行する定義済みスクリプトスニペット(オプション +shellTypeDescription=起動する明示的なシェルタイプ +originPort=オリジンポート +originAddress=オリジンアドレス +remoteAddress=リモートアドレス +remotePort=リモートポート +remoteSourceAddress=リモート発信元アドレス +remoteSourcePort=リモート・ソース・ポート +originDestinationPort=オリジン宛先ポート +originDestinationAddress=送信元アドレス +origin=由来 +remoteHost=リモートホスト +address=アドレス +proxmox=プロックスモックス +proxmox.displayName=プロックスモックス +proxmox.displayDescription=Proxmox仮想環境のシステムに接続する +proxmoxVm.displayName=プロックスモックスVM +proxmoxVm.displayDescription=SSH 経由で Proxmox VE の仮想マシンに接続する +proxmoxContainer.displayName=Proxmoxコンテナ +proxmoxContainer.displayDescription=Proxmox VEでコンテナに接続する +sshDynamicTunnel.originDescription=ssh接続を開くシステム +sshDynamicTunnel.hostDescription=SOCKSプロキシとして使用するシステム +sshDynamicTunnel.bindingDescription=トンネルをどのアドレスにバインドするか +sshRemoteTunnel.originDescription=どこからssh接続を開き、どこにトンネルを開くか。 +sshRemoteTunnel.hostDescription=オリジンへのリモートトンネルを開始するシステム +sshRemoteTunnel.bindingDescription=トンネルをどのアドレスにバインドするか +sshLocalTunnel.originDescription=トンネルをどこから始めるか +sshLocalTunnel.hostDescription=トンネルを開くシステム +sshLocalTunnel.bindingDescription=トンネルをどのアドレスにバインドするか +sshLocalTunnel.localAddressDescription=バインドするローカルアドレス +sshLocalTunnel.remoteAddressDescription=バインドするリモートアドレス +cmd.displayName=カスタムターミナルコマンド +cmd.displayDescription=ターミナルでカスタムコマンドを実行する +k8sPod.displayName=Kubernetesポッド +k8sPod.displayDescription=kubectlでポッドとそのコンテナに接続する +k8sContainer.displayName=Kubernetesコンテナ +k8sContainer.displayDescription=コンテナにシェルを開く +k8sCluster.displayName=Kubernetesクラスタ +k8sCluster.displayDescription=クラスタとそのポッドにkubectlで接続する +sshTunnelGroup.displayName=SSHトンネル +sshTunnelGroup.displayCategory=すべてのタイプのSSHトンネル +podmanCmd.displayName=ポッドマンCLI +podmanCmd.displayCategory=CLIクライアントを使ってPodmanコンテナにアクセスする +podmanContainers=ポッドマンコンテナ +local.displayName=ローカルマシン +local.displayDescription=ローカルマシンのシェル +cygwin=サイグウィン +msys2=MSYS2 +gitWindows=Windows用Git +gitForWindows.displayName=Windows用Git +gitForWindows.displayDescription=ローカルの Git For Windows 環境にアクセスする +msys2.displayName=MSYS2 +msys2.displayDescription=MSYS2環境のシェルにアクセスする +cygwin.displayName=サイグウィン +cygwin.displayDescription=Cygwin環境のシェルにアクセスする +namespace=名前空間 +gitVaultIdentityStrategy=Git SSH ID +gitVaultIdentityStrategyDescription=リモートに SSH git URL を使うことにしていて、リモートリポジトリに SSH ID が必要な場合は、このオプションを設定する。\n\nHTTP URL を指定した場合は、このオプションを無視してもよい。 +dockerContainers=Dockerコンテナ +lxdContainers=LXDコンテナ +dockerCmd.displayName=docker CLIクライアント +dockerCmd.displayDescription=docker CLIクライアントを使ってDockerコンテナにアクセスする +lxdCmd.displayName=LXD CLIクライアント +lxdCmd.displayDescription=lxc CLIを使用してLXDコンテナにアクセスする。 +wslCmd.displayName=wslクライアント +wslCmd.displayDescription=wsl CLI を使用して WSL インスタンスにアクセスする。 +k8sCmd.displayName=kubectlクライアント +k8sCmd.displayDescription=kubectlを使ってKubernetesクラスタにアクセスする +k8sClusters=Kubernetesクラスタ +shells=利用可能なシェル +startContainer=スタートコンテナ +stopContainer=停止コンテナ +inspectContainer=コンテナを検査する +k8sClusterNameDescription=クラスタが存在するコンテキストの名前。 +pod=ポッド +podName=ポッド名 +k8sClusterContext=コンテキスト +k8sClusterContextDescription=クラスタが存在するコンテキストの名前 +k8sClusterNamespace=名前空間 +k8sClusterNamespaceDescription=カスタム名前空間、または空の場合はデフォルトの名前空間。 +k8sConfigLocation=コンフィグファイル +k8sConfigLocationDescription=カスタムkubeconfigファイル、または空の場合はデフォルトのkubeconfigファイル +inspectPod=ポッドを検査する +showAllContainers=実行されていないコンテナを表示する +showAllPods=起動していないポッドを表示する +wsl=WSL +docker=ドッカー +k8sPodHostDescription=ポッドが置かれているホスト +k8sContainerDescription=Kubernetesコンテナの名前 +k8sPodDescription=Kubernetesポッドの名前 +podDescription=コンテナが置かれているポッド +k8sClusterHostDescription=クラスタにアクセスするホスト。クラスタにアクセスするにはkubectlがインストールされ、設定されている必要がある。 +script=初期スクリプト +connection=接続 +shellCommand.displayName=カスタムシェルオープナーコマンド +shellCommand.displayDescription=カスタムコマンドで標準シェルを開く +ssh.displayName=シンプルなSSH接続 +ssh.displayDescription=SSHコマンドラインクライアントで接続する +sshConfig.displayName=SSH設定ファイル +sshConfig.displayDescription=SSH設定ファイルで定義されたホストに接続する +sshConfigHost.displayName=SSH設定ファイルホスト +sshConfigHost.displayDescription=SSH設定ファイルで定義されたホストに接続する。 +sshConfigHost.password=パスワード +sshConfigHost.passwordDescription=ユーザーログイン用の任意のパスワードを入力する。 +sshConfigHost.identityPassphrase=IDパスフレーズ +sshConfigHost.identityPassphraseDescription=IDキーのパスフレーズ(オプション)を入力する。 +binary.displayName=バイナリ +binary.displayDescription=バイナリデータ +text.displayName=テキスト +shellCommand.hostDescription=コマンドを実行するホスト +shellCommand.commandDescription=シェルを開くコマンド +sshAgent=SSHエージェント +none=なし +commandDescription=ホスト上のシェルスクリプトで実行するコマンド。 +commandHostDescription=コマンドを実行するホスト +commandDataFlowDescription=このコマンドはどのように入出力を処理するか +commandElevationDescription=このコマンドを昇格した権限で実行する +commandShellTypeDescription=このコマンドに使用するシェル +ssh.passwordDescription=認証時に使用する任意のパスワード +keyAuthentication=鍵ベースの認証 +keyAuthenticationDescription=鍵ベースの認証が必要な場合に使用する認証方法。 +dontInteractWithSystem=システムと対話しない(プロ) +dontInteractWithSystemDescription=シェルやオペレーティングシステムの種類を特定しようとするな +sshForwardX11=フォワードX11 +sshForwardX11Description=接続のX11転送を有効にする +customAgent=カスタムエージェント +identityAgent=アイデンティティ・エージェント +ssh.proxyDescription=SSH接続を確立するときに使用するオプションのプロキシホスト。sshクライアントがインストールされている必要がある。 +usage=使用方法 +wslHostDescription=WSL インスタンスが置かれているホスト。wslがインストールされている必要がある。 +wslDistributionDescription=WSL インスタンスの名前 +wslUsernameDescription=ログインするための明示的なユーザー名。指定しない場合は、デフォルトのユーザー名が使われる。 +wslPasswordDescription=sudoコマンドで使用できるユーザーのパスワード。 +dockerHostDescription=dockerコンテナが置かれているホスト。dockerがインストールされている必要がある。 +dockerContainerDescription=ドッカーコンテナの名前 +lxdHostDescription=LXD コンテナが置かれているホスト。lxc がインストールされている必要がある。 +lxdContainerDescription=LXDコンテナの名前 +localMachine=ローカルマシン +rootScan=ルートシェル環境 +loginEnvironmentScan=カスタムログイン環境 +k8sScan=Kubernetesクラスタ +options=オプション +dockerRunningScan=ドッカーコンテナを実行する +dockerAllScan=すべてのドッカーコンテナ +wslScan=WSLインスタンス +sshScan=SSHコンフィグ接続 +requiresElevation=昇格を実行する +default=デフォルト +wslHost=WSLホスト +timeout=タイムアウト +installLocation=インストール場所 +installLocationDescription=$NAME$ 環境がインストールされている場所 +wsl.displayName=Linux用Windowsサブシステム +wsl.displayDescription=Windows上で動作するWSLインスタンスに接続する +docker.displayName=ドッカーコンテナ +docker.displayDescription=ドッカーコンテナに接続する +podman.displayName=ポッドマンコンテナ +podman.displayDescription=Podmanコンテナに接続する +lxd.displayName=LXDコンテナ +lxd.displayDescription=lxc経由でLXDコンテナに接続する +container=コンテナ +host=ホスト +port=ポート +user=ユーザー +password=パスワード +method=方法 +uri=URL +proxy=プロキシ +distribution=配布 +username=ユーザー名 +shellType=シェルタイプ +browseFile=ファイルをブラウズする +openShell=ターミナルでシェルを開く +openCommand=ターミナルでコマンドを実行する +editFile=ファイルを編集する +description=説明 +keyFile=IDファイル +keyPassword=パスフレーズ +key=キー +furtherCustomization=さらなるカスタマイズ +furtherCustomizationDescription=その他の設定オプションについては、ssh設定ファイルを使用する。 +location=場所 +browse=閲覧する +locationDescription=対応する秘密鍵のファイルパス +configHost=ホスト +configHostDescription=コンフィグが置かれているホスト +configLocation=設定場所 +configLocationDescription=コンフィグファイルのファイルパス +pageant=ページェント +gpgAgent=GPGエージェント(Pro) +gateway=ゲートウェイ +gatewayDescription=接続時に使用するオプションのゲートウェイ。 +connectionInformation=接続情報 +connectionInformationDescription=どのシステムに接続するか +passwordAuthentication=パスワード認証 +passwordDescription=認証に使用するオプションのパスワード。 +sshConfigString.displayName=カスタマイズされたSSH接続 +sshConfigString.displayDescription=完全にカスタマイズされたSSH接続を作成する +sshConfigStringContent=構成 +sshConfigStringContentDescription=OpenSSHコンフィグフォーマットでの接続のためのSSHオプション +vnc.displayName=VNC接続 +vnc.displayDescription=SSHトンネル経由でVNCセッションを開く +binding=バインディング +vncPortDescription=VNCサーバーがリッスンしているポート +vncUsername=ユーザー名 +vncUsernameDescription=オプションのVNCユーザー名 +vncPassword=パスワード +vncPasswordDescription=VNCパスワード +x11WslInstance=X11フォワードWSLインスタンス +x11WslInstanceDescription=SSH接続でX11転送を使用する際に、X11サーバーとして使用するローカルのWindows Subsystem for Linuxディストリビューション。このディストリビューションはWSL2ディストリビューションでなければならない。\n\n適用には再起動が必要である。 +openAsRoot=ルートとして開く +openInVsCodeRemote=VSCodeリモートで開く +openInWSL=WSLで開く +launch=起動 diff --git a/lang/proc/strings/translations_nl.properties b/lang/proc/strings/translations_nl.properties new file mode 100644 index 000000000..fdf7bf90f --- /dev/null +++ b/lang/proc/strings/translations_nl.properties @@ -0,0 +1,297 @@ +showInternalPods=Interne pods tonen +showAllNamespaces=Toon alle naamruimten +showInternalContainers=Interne containers tonen +refresh=Vernieuwen +vmwareGui=GUI starten +monitorVm=Monitor VM +addCluster=Cluster toevoegen ... +showNonRunningInstances=Niet-lopende instanties tonen +vmwareGuiDescription=Of een virtuele machine op de achtergrond of in een venster moet worden gestart. +vmwareEncryptionPassword=Encryptie wachtwoord +vmwareEncryptionPasswordDescription=Het optionele wachtwoord dat wordt gebruikt om de VM te versleutelen. +vmwarePasswordDescription=Het vereiste wachtwoord voor de gastgebruiker. +vmwarePassword=Wachtwoord gebruiker +vmwareUser=Gast gebruiker +runTempContainer=Tijdelijke container uitvoeren +vmwareUserDescription=De gebruikersnaam van je primaire gastgebruiker +dockerTempRunAlertTitle=Tijdelijke container uitvoeren +dockerTempRunAlertHeader=Hiermee wordt een shellproces uitgevoerd in een tijdelijke container die automatisch wordt verwijderd zodra het wordt gestopt. +imageName=Naam afbeelding +imageNameDescription=De te gebruiken container image identifier +containerName=Containernaam +containerNameDescription=De optionele aangepaste containernaam +vm=Virtuele machine +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Het bijbehorende configuratiebestand. +vmwareScan=VMware desktop hypervisors +library=Bibliotheek +customPkcs11Library=Aangepaste PKCS#11-bibliotheek (Pro) +vmwareMachine.displayName=VMware virtuele machine +vmwareMachine.displayDescription=Verbinding maken met een virtuele machine via SSH +vmwareInstallation.displayName=VMware desktop hypervisor installatie +vmwareInstallation.displayDescription=Interactie met de geïnstalleerde VM's via de CLI +start=Start +stop=Stop +pause=Pauze +rdpTunnelHost=Tunnel host +rdpTunnelHostDescription=De optionele SSH-verbinding om als tunnel te gebruiken +rdpFileLocation=Bestandslocatie +rdpFileLocationDescription=Het bestandspad van het .rdp bestand +rdpPasswordAuthentication=Wachtwoord verificatie +rdpPasswordAuthenticationDescription=Het wachtwoord om automatisch in te vullen indien ondersteund +rdpFile.displayName=RDP-bestand +rdpFile.displayDescription=Verbinding maken met een systeem via een bestaand .rdp bestand +requiredSshServerAlertTitle=SSH-server instellen +requiredSshServerAlertHeader=Kan geen geïnstalleerde SSH-server in de VM vinden. +requiredSshServerAlertContent=Om verbinding te maken met de VM zoekt XPipe naar een actieve SSH-server, maar er is geen beschikbare SSH-server gedetecteerd voor de VM. +computerName=Computernaam +pssComputerNameDescription=De computernaam om verbinding mee te maken. Er wordt aangenomen dat deze al is opgenomen in je vertrouwde hosts. +credentialUser=Credential Gebruiker +pssCredentialUserDescription=De gebruiker om als in te loggen. +credentialPassword=Wachtwoord +pssCredentialPasswordDescription=Het wachtwoord van de gebruiker. +sshConfig=SSH-configuratiebestanden +autostart=Automatisch verbinding maken bij het opstarten van XPipe +acceptHostKey=Accepteer hostsleutel +modifyHostKeyPermissions=Machtigingen voor hostsleutels wijzigen +attachContainer=Aan container bevestigen +openInVsCode=Openen in VSCode +containerLogs=Containerlogboeken tonen +openSftpClient=Openen in externe SFTP-client +openTermius=Openen in Termius +showInternalInstances=Interne instanties tonen +editPod=Bewerk pod +acceptHostKeyDescription=Vertrouw de nieuwe hostsleutel en ga verder +modifyHostKeyPermissionsDescription=Proberen de rechten van het originele bestand te verwijderen zodat OpenSSH tevreden is +psSession.displayName=PowerShell externe sessie +psSession.displayDescription=Verbinding maken via New-PSSession en Enter-PSSession +sshLocalTunnel.displayName=Lokale SSH-tunnel +sshLocalTunnel.displayDescription=Een SSH-tunnel opzetten naar een host op afstand +sshRemoteTunnel.displayName=SSH-tunnel op afstand +sshRemoteTunnel.displayDescription=Een omgekeerde SSH-tunnel opzetten vanaf een host op afstand +sshDynamicTunnel.displayName=Dynamische SSH-tunnel +sshDynamicTunnel.displayDescription=Een SOCKS proxy opzetten via een SSH verbinding +shellEnvironmentGroup.displayName=Shell-omgevingen +shellEnvironmentGroup.displayDescription=Shell-omgevingen +shellEnvironment.displayName=Aangepaste Shell-omgeving +shellEnvironment.displayDescription=Een aangepaste shell init-omgeving maken +shellEnvironment.informationFormat=$TYPE$ omgeving +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ omgeving +environmentConnectionDescription=De basisverbinding om een omgeving te creëren voor +environmentScriptDescription=Het optionele aangepaste init-script dat in de shell wordt uitgevoerd +environmentSnippets=Scriptfragmenten +commandSnippetsDescription=De optionele voorgedefinieerde scriptfragmenten om eerst uit te voeren +environmentSnippetsDescription=De optionele voorgedefinieerde scriptfragmenten om uit te voeren bij initialisatie +shellTypeDescription=Het expliciete shell-type om te starten +originPort=Oorsprong poort +originAddress=Adres van herkomst +remoteAddress=Adres op afstand +remotePort=Externe poort +remoteSourceAddress=Bronadres op afstand +remoteSourcePort=Bronpoort op afstand +originDestinationPort=Oorsprong bestemmingspoort +originDestinationAddress=Herkomst bestemmingsadres +origin=Oorsprong +remoteHost=Externe host +address=Adres +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Verbinding maken met systemen in een Proxmox virtuele omgeving +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Verbinding maken met een virtuele machine in een Proxmox VE via SSH +proxmoxContainer.displayName=Proxmox Container +proxmoxContainer.displayDescription=Verbinding maken met een container in een Proxmox VE +sshDynamicTunnel.originDescription=Het systeem van waaruit de ssh-verbinding moet worden geopend +sshDynamicTunnel.hostDescription=Het systeem om te gebruiken als SOCKS proxy +sshDynamicTunnel.bindingDescription=Aan welke adressen de tunnel moet worden gebonden +sshRemoteTunnel.originDescription=Het systeem van waaruit de ssh-verbinding moet worden geopend en waarnaar de tunnel moet worden geopend +sshRemoteTunnel.hostDescription=Het systeem van waaruit de tunnel op afstand naar de oorsprong wordt gestart +sshRemoteTunnel.bindingDescription=Aan welke adressen de tunnel moet worden gebonden +sshLocalTunnel.originDescription=Het systeem van waaruit de tunnel start +sshLocalTunnel.hostDescription=Het systeem om de tunnel naar te openen +sshLocalTunnel.bindingDescription=Aan welke adressen de tunnel moet worden gebonden +sshLocalTunnel.localAddressDescription=Het lokale adres om te binden +sshLocalTunnel.remoteAddressDescription=Het externe adres om te binden +cmd.displayName=Aangepast Terminal Commando +cmd.displayDescription=Een aangepast commando uitvoeren op een systeem in je terminal +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=Verbinding maken met een pod en zijn containers via kubectl +k8sContainer.displayName=Kubernetes Container +k8sContainer.displayDescription=Een shell naar een container openen +k8sCluster.displayName=Kubernetes Cluster +k8sCluster.displayDescription=Verbinding maken met een cluster en zijn pods via kubectl +sshTunnelGroup.displayName=SSH-tunnels +sshTunnelGroup.displayCategory=Alle soorten SSH-tunnels +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Toegang tot Podman containers via de CLI-client +podmanContainers=Podman containers +local.displayName=Lokale machine +local.displayDescription=De shell van de lokale machine +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git voor Windows +gitForWindows.displayName=Git voor Windows +gitForWindows.displayDescription=Toegang tot je lokale Git For Windows omgeving +msys2.displayName=MSYS2 +msys2.displayDescription=Toegangsshells van je MSYS2-omgeving +cygwin.displayName=Cygwin +cygwin.displayDescription=Toegang tot shells van je Cygwin-omgeving +namespace=Naamruimte +gitVaultIdentityStrategy=Git SSH identiteit +gitVaultIdentityStrategyDescription=Als je ervoor hebt gekozen om een SSH git URL te gebruiken als de remote en je remote repository vereist een SSH identiteit, stel dan deze optie in.\n\nAls je een HTTP url hebt opgegeven, dan kun je deze optie negeren. +dockerContainers=Docker containers +lxdContainers=LXD containers +dockerCmd.displayName=docker CLI-client +dockerCmd.displayDescription=Toegang tot Docker-containers via de docker CLI-client +lxdCmd.displayName=LXD CLI-client +lxdCmd.displayDescription=Toegang tot LXD-containers via de lxc CLI cient +wslCmd.displayName=wsl-client +wslCmd.displayDescription=Toegang tot WSL instanties via de wsl CLI cient +k8sCmd.displayName=kubectl cliënt +k8sCmd.displayDescription=Toegang tot Kubernetes-clusters via kubectl +k8sClusters=Kubernetes clusters +shells=Beschikbare schelpen +startContainer=Start container +stopContainer=Stopcontainer +inspectContainer=Container inspecteren +k8sClusterNameDescription=De naam van de context waarin het cluster zich bevindt. +pod=Pod +podName=Pod naam +k8sClusterContext=Context +k8sClusterContextDescription=De naam van de context waarin het cluster zich bevindt +k8sClusterNamespace=Naamruimte +k8sClusterNamespaceDescription=De aangepaste naamruimte of de standaard naamruimte als deze leeg is +k8sConfigLocation=Configuratiebestand +k8sConfigLocationDescription=Het aangepaste kubeconfig bestand of het standaard kubeconfig bestand indien leeg gelaten +inspectPod=Peul inspecteren +showAllContainers=Niet-lopende containers tonen +showAllPods=Niet-lopende pods tonen +wsl=WSL +docker=Docker +k8sPodHostDescription=De host waarop de pod zich bevindt +k8sContainerDescription=De naam van de Kubernetes container +k8sPodDescription=De naam van de Kubernetes pod +podDescription=De pod waarop de container zich bevindt +k8sClusterHostDescription=De host via welke het cluster benaderd moet worden. Kubectl moet geïnstalleerd en geconfigureerd zijn om toegang te krijgen tot het cluster. +script=Init script +connection=Verbinding +shellCommand.displayName=Aangepast commando Shell-opener +shellCommand.displayDescription=Een standaard shell openen via een aangepast commando +ssh.displayName=Eenvoudige SSH-verbinding +ssh.displayDescription=Verbinding maken via een SSH-opdrachtregelclient +sshConfig.displayName=SSH-configuratiebestand +sshConfig.displayDescription=Verbinding maken met hosts gedefinieerd in een SSH config bestand +sshConfigHost.displayName=SSH configuratiebestand host +sshConfigHost.displayDescription=Verbinding maken met een host gedefinieerd in een SSH config bestand +sshConfigHost.password=Wachtwoord +sshConfigHost.passwordDescription=Geef het optionele wachtwoord voor het inloggen van de gebruiker. +sshConfigHost.identityPassphrase=Identiteitspaswoord +sshConfigHost.identityPassphraseDescription=Geef de optionele wachtwoordzin voor je identiteitsleutel. +binary.displayName=Binair +binary.displayDescription=Binaire gegevens +text.displayName=Tekst +shellCommand.hostDescription=De host waarop het commando moet worden uitgevoerd +shellCommand.commandDescription=Het commando dat een shell opent +sshAgent=SSH-agent +none=Geen +commandDescription=De commando's om uit te voeren in een shellscript op de host. +commandHostDescription=De host waarop het commando moet worden uitgevoerd +commandDataFlowDescription=Hoe dit commando omgaat met invoer en uitvoer +commandElevationDescription=Voer dit commando uit met verhoogde rechten +commandShellTypeDescription=De shell die gebruikt moet worden voor dit commando +ssh.passwordDescription=Het optionele wachtwoord om te gebruiken bij verificatie +keyAuthentication=Verificatie op basis van sleutels +keyAuthenticationDescription=De te gebruiken verificatiemethode als verificatie op basis van sleutels vereist is. +dontInteractWithSystem=Geen interactie met systeem (Pro) +dontInteractWithSystemDescription=Probeer het type shell en besturingssysteem niet te identificeren +sshForwardX11=Vooruit X11 +sshForwardX11Description=Schakelt X11-forwarding in voor de verbinding +customAgent=Aangepaste agent +identityAgent=Identiteitsagent +ssh.proxyDescription=De optionele proxy host om te gebruiken bij het maken van de SSH verbinding. Er moet een ssh-client geïnstalleerd zijn. +usage=Gebruik +wslHostDescription=De host waarop de WSL instantie zich bevindt. Moet wsl geïnstalleerd hebben. +wslDistributionDescription=De naam van de WSL instantie +wslUsernameDescription=De expliciete gebruikersnaam om mee in te loggen. Als deze niet wordt opgegeven, wordt de standaard gebruikersnaam gebruikt. +wslPasswordDescription=Het wachtwoord van de gebruiker dat gebruikt kan worden voor sudo commando's. +dockerHostDescription=De host waarop de docker container zich bevindt. Docker moet geïnstalleerd zijn. +dockerContainerDescription=De naam van de docker container +lxdHostDescription=De host waarop de LXD container staat. Moet lxc geïnstalleerd hebben. +lxdContainerDescription=De naam van de LXD-container +localMachine=Lokale machine +rootScan=Root shell-omgeving +loginEnvironmentScan=Aangepaste inlogomgeving +k8sScan=Kubernetes cluster +options=Opties +dockerRunningScan=Docker-containers uitvoeren +dockerAllScan=Alle docker-containers +wslScan=WSL instanties +sshScan=SSH config verbindingen +requiresElevation=Verhoogd uitvoeren +default=Standaard +wslHost=WSL host +timeout=Time-out +installLocation=Locatie installeren +installLocationDescription=De locatie waar je $NAME$ omgeving is geïnstalleerd +wsl.displayName=Windows Subsysteem voor Linux +wsl.displayDescription=Verbinding maken met een WSL-instantie die op Windows draait +docker.displayName=Docker Container +docker.displayDescription=Verbinding maken met een docker-container +podman.displayName=Podman Container +podman.displayDescription=Verbinding maken met een Podman-container +lxd.displayName=LXD-container +lxd.displayDescription=Verbinding maken met een LXD-container via lxc +container=Container +host=Host +port=Poort +user=Gebruiker +password=Wachtwoord +method=Methode +uri=URL +proxy=Proxy +distribution=Distributie +username=Gebruikersnaam +shellType=Type omhulsel +browseFile=Bestand doorbladeren +openShell=Shell in terminal openen +openCommand=Opdracht uitvoeren in terminal +editFile=Bewerk bestand +description=Beschrijving +keyFile=Identiteitsbestand +keyPassword=Passphrase +key=Sleutel +furtherCustomization=Verder aanpassen +furtherCustomizationDescription=Gebruik voor meer configuratieopties de ssh config bestanden +location=Locatie +browse=Bladeren door +locationDescription=Het bestandspad van je corresponderende privésleutel +configHost=Host +configHostDescription=De host waarop de config zich bevindt +configLocation=Configuratie locatie +configLocationDescription=Het bestandspad van het configuratiebestand +pageant=Verkiezing +gpgAgent=GPG Agent (Pro) +gateway=Gateway +gatewayDescription=De optionele gateway om te gebruiken bij het verbinden. +connectionInformation=Verbindingsinformatie +connectionInformationDescription=Met welk systeem verbinding maken +passwordAuthentication=Wachtwoord verificatie +passwordDescription=Het optionele wachtwoord voor verificatie. +sshConfigString.displayName=Aangepaste SSH-verbinding +sshConfigString.displayDescription=Een volledig aangepaste SSH-verbinding maken +sshConfigStringContent=Configuratie +sshConfigStringContentDescription=SSH opties voor de verbinding in OpenSSH config formaat +vnc.displayName=VNC-verbinding +vnc.displayDescription=Open een VNC-sessie via een SSH-tunnel +binding=Binden +vncPortDescription=De poort waarop de VNC-server luistert +vncUsername=Gebruikersnaam +vncUsernameDescription=De optionele VNC-gebruikersnaam +vncPassword=Wachtwoord +vncPasswordDescription=Het VNC-wachtwoord +x11WslInstance=X11 Voorwaartse WSL-instantie +x11WslInstanceDescription=De lokale Windows Subsystem for Linux distributie om te gebruiken als X11 server bij het gebruik van X11 forwarding in een SSH verbinding. Deze distributie moet een WSL2 distributie zijn.\n\nVereist een herstart om toe te passen. +openAsRoot=Openen als root +openInVsCodeRemote=Openen in VSCode op afstand +openInWSL=Openen in WSL +launch=Start diff --git a/lang/proc/strings/translations_pt.properties b/lang/proc/strings/translations_pt.properties new file mode 100644 index 000000000..56170e803 --- /dev/null +++ b/lang/proc/strings/translations_pt.properties @@ -0,0 +1,297 @@ +showInternalPods=Mostra os pods internos +showAllNamespaces=Mostra todos os namespaces +showInternalContainers=Mostra os contentores internos +refresh=Actualiza +vmwareGui=Inicia a GUI +monitorVm=Monitor VM +addCluster=Adiciona um cluster ... +showNonRunningInstances=Mostra instâncias não em execução +vmwareGuiDescription=Se pretende iniciar uma máquina virtual em segundo plano ou numa janela. +vmwareEncryptionPassword=Palavra-passe de encriptação +vmwareEncryptionPasswordDescription=A palavra-passe opcional utilizada para encriptar a VM. +vmwarePasswordDescription=A palavra-passe necessária para o utilizador convidado. +vmwarePassword=Palavra-passe do utilizador +vmwareUser=Utilizador convidado +runTempContainer=Executa um contentor temporário +vmwareUserDescription=O nome de utilizador do teu principal utilizador convidado +dockerTempRunAlertTitle=Executa um contentor temporário +dockerTempRunAlertHeader=Isto irá executar um processo shell num contentor temporário que será automaticamente removido assim que for parado. +imageName=Nome da imagem +imageNameDescription=O identificador de imagem de contentor a utilizar +containerName=Nome do contentor +containerNameDescription=O nome opcional do contentor personalizado +vm=Máquina virtual +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=O ficheiro de configuração associado. +vmwareScan=Hipervisores de desktop VMware +library=Biblioteca +customPkcs11Library=Biblioteca PKCS#11 personalizada (Pro) +vmwareMachine.displayName=Máquina virtual VMware +vmwareMachine.displayDescription=Liga-te a uma máquina virtual através de SSH +vmwareInstallation.displayName=Instalação do hipervisor de ambiente de trabalho VMware +vmwareInstallation.displayDescription=Interage com as VMs instaladas através do seu CLI +start=Começa +stop=Pára +pause=Pausa +rdpTunnelHost=Anfitrião de túnel +rdpTunnelHostDescription=A conexão SSH opcional para usar como um túnel +rdpFileLocation=Localização do ficheiro +rdpFileLocationDescription=O caminho do ficheiro .rdp +rdpPasswordAuthentication=Autenticação por palavra-passe +rdpPasswordAuthenticationDescription=A palavra-passe a preencher automaticamente se for suportada +rdpFile.displayName=Ficheiro RDP +rdpFile.displayDescription=Liga-se a um sistema através de um ficheiro .rdp existente +requiredSshServerAlertTitle=Configura o servidor SSH +requiredSshServerAlertHeader=Não é possível encontrar um servidor SSH instalado na VM. +requiredSshServerAlertContent=Para se conectar à VM, o XPipe está procurando um servidor SSH em execução, mas nenhum servidor SSH disponível foi detectado para a VM... +computerName=Nome do computador +pssComputerNameDescription=O nome do computador a que te vais ligar. Presume-se que já está incluído nos teus anfitriões de confiança. +credentialUser=Credencial de utilizador +pssCredentialUserDescription=O utilizador para iniciar sessão como. +credentialPassword=Palavra-passe de credencial +pssCredentialPasswordDescription=A palavra-passe do utilizador. +sshConfig=Ficheiros de configuração SSH +autostart=Liga automaticamente no arranque do XPipe +acceptHostKey=Aceita a chave do anfitrião +modifyHostKeyPermissions=Modifica as permissões da chave do anfitrião +attachContainer=Coloca no contentor +openInVsCode=Abre em VSCode +containerLogs=Mostra os registos do contentor +openSftpClient=Abre num cliente SFTP externo +openTermius=Abre em Termius +showInternalInstances=Mostra instâncias internas +editPod=Editar cápsula +acceptHostKeyDescription=Confia na nova chave de anfitrião e continua +modifyHostKeyPermissionsDescription=Tenta remover as permissões do ficheiro original para que o OpenSSH fique satisfeito +psSession.displayName=Sessão remota do PowerShell +psSession.displayDescription=Liga-te através de New-PSSession e Enter-PSSession +sshLocalTunnel.displayName=Túnel SSH local +sshLocalTunnel.displayDescription=Estabelece um túnel SSH para um host remoto +sshRemoteTunnel.displayName=Túnel SSH remoto +sshRemoteTunnel.displayDescription=Estabelece um túnel SSH reverso a partir de um host remoto +sshDynamicTunnel.displayName=Túnel SSH dinâmico +sshDynamicTunnel.displayDescription=Estabelece um proxy SOCKS através de uma ligação SSH +shellEnvironmentGroup.displayName=Ambientes Shell +shellEnvironmentGroup.displayDescription=Ambientes Shell +shellEnvironment.displayName=Ambiente de shell personalizado +shellEnvironment.displayDescription=Cria um ambiente shell init personalizado +shellEnvironment.informationFormat=$TYPE$ ambiente +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ ambiente +environmentConnectionDescription=A ligação de base para criar um ambiente para +environmentScriptDescription=O script de inicialização personalizado opcional a ser executado no shell +environmentSnippets=Trechos de script +commandSnippetsDescription=Os snippets de script predefinidos opcionais a executar primeiro +environmentSnippetsDescription=Os snippets de script predefinidos opcionais a executar na inicialização +shellTypeDescription=O tipo de shell explícito a lançar +originPort=Porta de origem +originAddress=Endereço de origem +remoteAddress=Endereço remoto +remotePort=Porta remota +remoteSourceAddress=Endereço de origem remota +remoteSourcePort=Porta de origem remota +originDestinationPort=Porta de destino de origem +originDestinationAddress=Endereço de destino de origem +origin=Origem +remoteHost=Anfitrião remoto +address=Aborda +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Liga-te a sistemas num ambiente virtual Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Conecta-se a uma máquina virtual em um Proxmox VE via SSH +proxmoxContainer.displayName=Contentor Proxmox +proxmoxContainer.displayDescription=Liga-te a um contentor num Proxmox VE +sshDynamicTunnel.originDescription=O sistema a partir do qual deves abrir a ligação ssh +sshDynamicTunnel.hostDescription=O sistema a utilizar como proxy SOCKS +sshDynamicTunnel.bindingDescription=A que endereços ligar o túnel +sshRemoteTunnel.originDescription=O sistema a partir do qual deves abrir a ligação ssh e abrir o túnel para +sshRemoteTunnel.hostDescription=O sistema a partir do qual se inicia o túnel remoto para a origem +sshRemoteTunnel.bindingDescription=A que endereços ligar o túnel +sshLocalTunnel.originDescription=O sistema a partir do qual se inicia o túnel +sshLocalTunnel.hostDescription=O sistema para abrir o túnel para +sshLocalTunnel.bindingDescription=A que endereços ligar o túnel +sshLocalTunnel.localAddressDescription=O endereço local a associar +sshLocalTunnel.remoteAddressDescription=O endereço remoto a associar +cmd.displayName=Comando de terminal personalizado +cmd.displayDescription=Executa um comando personalizado num sistema no teu terminal +k8sPod.displayName=Pod de Kubernetes +k8sPod.displayDescription=Liga-te a um pod e aos seus contentores através do kubectl +k8sContainer.displayName=Contentor Kubernetes +k8sContainer.displayDescription=Abre um shell para um contentor +k8sCluster.displayName=Cluster Kubernetes +k8sCluster.displayDescription=Liga-te a um cluster e aos seus pods através do kubectl +sshTunnelGroup.displayName=Túneis SSH +sshTunnelGroup.displayCategory=Todos os tipos de túneis SSH +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Acede aos contentores Podman através do cliente CLI +podmanContainers=Contentores Podman +local.displayName=Máquina local +local.displayDescription=O shell da máquina local +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git para Windows +gitForWindows.displayName=Git para Windows +gitForWindows.displayDescription=Aceder ao teu ambiente local do Git For Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Acesso a shells do teu ambiente MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Aceder às shells do teu ambiente Cygwin +namespace=Espaço de nome +gitVaultIdentityStrategy=Identidade SSH do Git +gitVaultIdentityStrategyDescription=Se escolheste utilizar um URL git SSH como remoto e o teu repositório remoto requer uma identidade SSH, define esta opção.\n\nCaso tenhas fornecido um url HTTP, podes ignorar esta opção. +dockerContainers=Contentores Docker +lxdContainers=Contentores LXD +dockerCmd.displayName=cliente CLI do docker +dockerCmd.displayDescription=Aceder a contentores Docker através do cliente docker CLI +lxdCmd.displayName=Cliente CLI do LXD +lxdCmd.displayDescription=Acede aos contentores LXD através do cliente lxc CLI +wslCmd.displayName=cliente wsl +wslCmd.displayDescription=Acede a instâncias WSL através do cliente wsl CLI +k8sCmd.displayName=cliente kubectl +k8sCmd.displayDescription=Aceder a clusters Kubernetes através de kubectl +k8sClusters=Clusters Kubernetes +shells=Conchas disponíveis +startContainer=Iniciar contentor +stopContainer=Pára o contentor +inspectContainer=Inspecciona o contentor +k8sClusterNameDescription=O nome do contexto em que o cluster se encontra. +pod=Pod +podName=Nome do pod +k8sClusterContext=Contexto +k8sClusterContextDescription=O nome do contexto em que o cluster se encontra +k8sClusterNamespace=Espaço de nome +k8sClusterNamespaceDescription=O espaço de nome personalizado ou o espaço de nome predefinido, se estiver vazio +k8sConfigLocation=Ficheiro de configuração +k8sConfigLocationDescription=O ficheiro kubeconfig personalizado ou o ficheiro predefinido se for deixado vazio +inspectPod=Inspeciona o pod +showAllContainers=Mostra contentores não em execução +showAllPods=Mostra pods não em execução +wsl=WSL +docker=Docker +k8sPodHostDescription=O anfitrião no qual o pod está localizado +k8sContainerDescription=O nome do contentor Kubernetes +k8sPodDescription=O nome do pod Kubernetes +podDescription=O pod no qual o contentor está localizado +k8sClusterHostDescription=O host através do qual o cluster deve ser acessado. Deve ter o kubectl instalado e configurado para poder aceder ao cluster. +script=Script de inicialização +connection=Ligação +shellCommand.displayName=Comando de abertura de shell personalizado +shellCommand.displayDescription=Abre uma shell padrão através de um comando personalizado +ssh.displayName=Ligação SSH simples +ssh.displayDescription=Liga-te através de um cliente de linha de comandos SSH +sshConfig.displayName=Ficheiro de configuração SSH +sshConfig.displayDescription=Liga-te a anfitriões definidos num ficheiro de configuração SSH +sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayDescription=Liga-te a um anfitrião definido num ficheiro de configuração SSH +sshConfigHost.password=Palavra-passe +sshConfigHost.passwordDescription=Fornece a palavra-passe opcional para o início de sessão do utilizador. +sshConfigHost.identityPassphrase=Palavra-passe de identidade +sshConfigHost.identityPassphraseDescription=Fornece a frase-passe opcional para a tua chave de identificação. +binary.displayName=Binário +binary.displayDescription=Dados binários +text.displayName=Texto +shellCommand.hostDescription=O anfitrião para executar o comando +shellCommand.commandDescription=O comando que abre uma shell +sshAgent=Agente SSH +none=Não tens +commandDescription=Os comandos a executar num script de shell no anfitrião. +commandHostDescription=O anfitrião para executar o comando +commandDataFlowDescription=Como este comando lida com a entrada e saída +commandElevationDescription=Executa este comando com permissões elevadas +commandShellTypeDescription=A shell a utilizar para este comando +ssh.passwordDescription=A palavra-passe opcional a utilizar na autenticação +keyAuthentication=Autenticação baseada em chaves +keyAuthenticationDescription=O método de autenticação a utilizar se for necessária uma autenticação baseada em chaves. +dontInteractWithSystem=Não interajas com o sistema (Pro) +dontInteractWithSystemDescription=Não tentes identificar o tipo de shell e de sistema operativo +sshForwardX11=Avança X11 +sshForwardX11Description=Ativa o reencaminhamento X11 para a ligação +customAgent=Agente personalizado +identityAgent=Agente de identidade +ssh.proxyDescription=O anfitrião proxy opcional a utilizar quando estabelece a ligação SSH. Tem de ter um cliente ssh instalado. +usage=Usa +wslHostDescription=O host no qual a instância WSL está localizada. Deve ter o wsl instalado. +wslDistributionDescription=O nome da instância WSL +wslUsernameDescription=O nome de utilizador explícito para iniciar sessão. Se não for especificado, será utilizado o nome de utilizador predefinido. +wslPasswordDescription=A palavra-passe do utilizador que pode ser utilizada para comandos sudo. +dockerHostDescription=O anfitrião no qual o contentor do docker está localizado. Deve ter o docker instalado. +dockerContainerDescription=O nome do contentor docker +lxdHostDescription=O host no qual o contêiner LXD está localizado. Deve ter o lxc instalado. +lxdContainerDescription=O nome do contentor LXD +localMachine=Máquina local +rootScan=Ambiente da shell de raiz +loginEnvironmentScan=Ambiente de início de sessão personalizado +k8sScan=Cluster Kubernetes +options=Opções +dockerRunningScan=Executar contentores docker +dockerAllScan=Todos os contentores docker +wslScan=Instâncias WSL +sshScan=Ligações de configuração SSH +requiresElevation=Executa em alta velocidade +default=Por defeito +wslHost=Anfitrião WSL +timeout=Tempo limite +installLocation=Local de instalação +installLocationDescription=A localização onde o teu ambiente $NAME$ está instalado +wsl.displayName=Subsistema Windows para Linux +wsl.displayDescription=Liga-te a uma instância WSL em execução no Windows +docker.displayName=Contentor Docker +docker.displayDescription=Liga-te a um contentor docker +podman.displayName=Contentor Podman +podman.displayDescription=Liga-te a um contentor Podman +lxd.displayName=Contentor LXD +lxd.displayDescription=Liga-te a um contentor LXD através do lxc +container=Contentor +host=Aloja +port=Porta +user=Utilizador +password=Palavra-passe +method=Método +uri=URL +proxy=Proxy +distribution=Distribuição +username=Nome de utilizador +shellType=Tipo de Shell +browseFile=Procurar ficheiro +openShell=Abre a Shell no Terminal +openCommand=Executa o comando no terminal +editFile=Editar ficheiro +description=Descrição +keyFile=Ficheiro de identidade +keyPassword=Frase-chave +key=Chave +furtherCustomization=Personalização adicional +furtherCustomizationDescription=Para mais opções de configuração, utiliza os ficheiros de configuração ssh +location=Localização +browse=Procura +locationDescription=O caminho do ficheiro da tua chave privada correspondente +configHost=Aloja +configHostDescription=O host no qual a configuração está localizada +configLocation=Local de configuração +configLocationDescription=O caminho do ficheiro de configuração +pageant=Concurso +gpgAgent=Agente GPG (Pro) +gateway=Porta de entrada +gatewayDescription=O gateway opcional a utilizar quando estabelece a ligação. +connectionInformation=Informação de ligação +connectionInformationDescription=A que sistema te deves ligar +passwordAuthentication=Autenticação por palavra-passe +passwordDescription=A palavra-passe opcional a utilizar para autenticar. +sshConfigString.displayName=Ligação SSH personalizada +sshConfigString.displayDescription=Cria uma ligação SSH totalmente personalizada +sshConfigStringContent=Configuração +sshConfigStringContentDescription=Opções SSH para a ligação no formato de configuração OpenSSH +vnc.displayName=Ligação VNC +vnc.displayDescription=Abre uma sessão VNC através de um túnel SSH +binding=Encadernação +vncPortDescription=A porta em que o servidor VNC está escutando +vncUsername=Nome de utilizador +vncUsernameDescription=O nome de utilizador opcional do VNC +vncPassword=Palavra-passe +vncPasswordDescription=A palavra-passe VNC +x11WslInstance=Instância X11 Forward WSL +x11WslInstanceDescription=A distribuição local do Subsistema Windows para Linux a utilizar como um servidor X11 quando utiliza o reencaminhamento X11 numa ligação SSH. Esta distribuição deve ser uma distribuição WSL2.\n\nRequer uma reinicialização para ser aplicada. +openAsRoot=Abre como raiz +openInVsCodeRemote=Abre no VSCode remoto +openInWSL=Abre em WSL +launch=Lança diff --git a/lang/proc/strings/translations_ru.properties b/lang/proc/strings/translations_ru.properties new file mode 100644 index 000000000..375166699 --- /dev/null +++ b/lang/proc/strings/translations_ru.properties @@ -0,0 +1,297 @@ +showInternalPods=Показать внутренние капсулы +showAllNamespaces=Показать все пространства имен +showInternalContainers=Показать внутренние контейнеры +refresh=Обновить +vmwareGui=Запуск графического интерфейса +monitorVm=Монитор ВМ +addCluster=Добавь кластер ... +showNonRunningInstances=Показать неработающие экземпляры +vmwareGuiDescription=Запускать ли виртуальную машину в фоновом режиме или в окне. +vmwareEncryptionPassword=Пароль шифрования +vmwareEncryptionPasswordDescription=Необязательный пароль, используемый для шифрования виртуальной машины. +vmwarePasswordDescription=Необходимый пароль для гостевого пользователя. +vmwarePassword=Пароль пользователя +vmwareUser=Гость-пользователь +runTempContainer=Запустить временный контейнер +vmwareUserDescription=Имя пользователя твоего основного гостевого пользователя +dockerTempRunAlertTitle=Запустить временный контейнер +dockerTempRunAlertHeader=Это запустит shell-процесс во временном контейнере, который будет автоматически удален после его остановки. +imageName=Название изображения +imageNameDescription=Идентификатор образа контейнера, который нужно использовать +containerName=Название контейнера +containerNameDescription=Необязательное пользовательское название контейнера +vm=Виртуальная машина +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Связанный с ним файл конфигурации. +vmwareScan=Гипервизоры VMware для настольных компьютеров +library=Библиотека +customPkcs11Library=Пользовательская библиотека PKCS#11 (Pro) +vmwareMachine.displayName=Виртуальная машина VMware +vmwareMachine.displayDescription=Подключение к виртуальной машине через SSH +vmwareInstallation.displayName=Установка гипервизора VMware для настольных компьютеров +vmwareInstallation.displayDescription=Взаимодействуй с установленной виртуальной машиной через ее CLI +start=Начни +stop=Стоп +pause=Пауза +rdpTunnelHost=Туннельный хост +rdpTunnelHostDescription=Дополнительное SSH-соединение, которое будет использоваться в качестве туннеля +rdpFileLocation=Расположение файла +rdpFileLocationDescription=Путь к файлу .rdp +rdpPasswordAuthentication=Проверка подлинности пароля +rdpPasswordAuthenticationDescription=Пароль для автоматического заполнения, если он поддерживается +rdpFile.displayName=Файл RDP +rdpFile.displayDescription=Подключение к системе через существующий файл .rdp +requiredSshServerAlertTitle=Настройка SSH-сервера +requiredSshServerAlertHeader=Невозможно найти установленный SSH-сервер в виртуальной машине. +requiredSshServerAlertContent=Чтобы подключиться к ВМ, XPipe ищет работающий SSH-сервер, но для ВМ не было обнаружено ни одного доступного SSH-сервера. +computerName=Имя компьютера +pssComputerNameDescription=Имя компьютера, к которому нужно подключиться. Предполагается, что оно уже включено в список твоих доверенных хостов. +credentialUser=Учетная запись пользователя +pssCredentialUserDescription=Пользователь, от имени которого нужно войти в систему. +credentialPassword=Пароль +pssCredentialPasswordDescription=Пароль пользователя. +sshConfig=Конфигурационные файлы SSH +autostart=Автоматическое подключение при запуске XPipe +acceptHostKey=Примите ключ хоста +modifyHostKeyPermissions=Изменение разрешений ключа хоста +attachContainer=Прикрепить к контейнеру +openInVsCode=Открыть в VSCode +containerLogs=Показать журналы контейнеров +openSftpClient=Открыть во внешнем SFTP-клиенте +openTermius=Открыть в Термиусе +showInternalInstances=Показать внутренние экземпляры +editPod=Редактировать капсулу +acceptHostKeyDescription=Доверься новому ключу хоста и продолжай +modifyHostKeyPermissionsDescription=Попытка снять разрешения с оригинального файла, чтобы OpenSSH был доволен +psSession.displayName=Удаленный сеанс PowerShell +psSession.displayDescription=Подключение через New-PSSession и Enter-PSSession +sshLocalTunnel.displayName=Локальный SSH-туннель +sshLocalTunnel.displayDescription=Создайте SSH-туннель к удаленному хосту +sshRemoteTunnel.displayName=Удаленный SSH-туннель +sshRemoteTunnel.displayDescription=Создайте обратный SSH-туннель с удаленного хоста +sshDynamicTunnel.displayName=Динамический SSH-туннель +sshDynamicTunnel.displayDescription=Установите SOCKS-прокси через SSH-соединение +shellEnvironmentGroup.displayName=Среды оболочки +shellEnvironmentGroup.displayDescription=Среды оболочки +shellEnvironment.displayName=Пользовательская среда оболочки +shellEnvironment.displayDescription=Создайте настраиваемое окружение shell init +shellEnvironment.informationFormat=$TYPE$ среда +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ среда +environmentConnectionDescription=Базовое соединение для создания среды для +environmentScriptDescription=Необязательный пользовательский скрипт init, запускаемый в оболочке +environmentSnippets=Фрагменты сценария +commandSnippetsDescription=Дополнительные предопределенные фрагменты скриптов, которые нужно запустить первыми +environmentSnippetsDescription=Необязательные предопределенные фрагменты скриптов, запускаемые при инициализации +shellTypeDescription=Явный тип оболочки для запуска +originPort=Порт происхождения +originAddress=Адрес происхождения +remoteAddress=Удаленный адрес +remotePort=Удаленный порт +remoteSourceAddress=Адрес удаленного источника +remoteSourcePort=Порт удаленного источника +originDestinationPort=Порт назначения +originDestinationAddress=Адрес места назначения +origin=Origin +remoteHost=Удаленный хост +address=Адрес +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Подключение к системам в виртуальной среде Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Подключение к виртуальной машине в Proxmox VE через SSH +proxmoxContainer.displayName=Контейнер Proxmox +proxmoxContainer.displayDescription=Подключение к контейнеру в Proxmox VE +sshDynamicTunnel.originDescription=Система, с которой нужно открыть ssh-соединение +sshDynamicTunnel.hostDescription=Система, которую нужно использовать в качестве SOCKS-прокси +sshDynamicTunnel.bindingDescription=К каким адресам привязать туннель +sshRemoteTunnel.originDescription=Система, с которой нужно открыть ssh-соединение и открыть туннель к +sshRemoteTunnel.hostDescription=Система, из которой будет запущен удаленный туннель к источнику +sshRemoteTunnel.bindingDescription=К каким адресам привязать туннель +sshLocalTunnel.originDescription=Система, с которой нужно начинать туннель +sshLocalTunnel.hostDescription=Система, к которой нужно открыть туннель +sshLocalTunnel.bindingDescription=К каким адресам привязать туннель +sshLocalTunnel.localAddressDescription=Локальный адрес для привязки +sshLocalTunnel.remoteAddressDescription=Удаленный адрес для привязки +cmd.displayName=Пользовательская команда терминала +cmd.displayDescription=Запустить пользовательскую команду в системе в терминале +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=Подключись к капсуле и ее контейнерам с помощью kubectl +k8sContainer.displayName=Контейнер Kubernetes +k8sContainer.displayDescription=Открыть оболочку для контейнера +k8sCluster.displayName=Кластер Kubernetes +k8sCluster.displayDescription=Подключись к кластеру и его капсулам с помощью kubectl +sshTunnelGroup.displayName=Туннели SSH +sshTunnelGroup.displayCategory=Все типы SSH-туннелей +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Доступ к контейнерам Podman через CLI-клиент +podmanContainers=Контейнеры Podman +local.displayName=Локальная машина +local.displayDescription=Оболочка локальной машины +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git для Windows +gitForWindows.displayName=Git для Windows +gitForWindows.displayDescription=Получите доступ к локальной среде Git For Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Оболочки доступа в вашей среде MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Доступ к оболочкам вашей среды Cygwin +namespace=Пространство имен +gitVaultIdentityStrategy=Идентификация Git SSH +gitVaultIdentityStrategyDescription=Если ты решил использовать SSH git URL в качестве удаленного и твой удаленный репозиторий требует SSH-идентификации, то установи эту опцию.\n\nВ случае если ты указал HTTP-урл, можешь проигнорировать эту опцию. +dockerContainers=Контейнеры Docker +lxdContainers=Контейнеры LXD +dockerCmd.displayName=клиент docker CLI +dockerCmd.displayDescription=Получи доступ к контейнерам Docker с помощью клиента docker CLI +lxdCmd.displayName=Клиент LXD CLI +lxdCmd.displayDescription=Получи доступ к контейнерам LXD с помощью lxc CLI cient +wslCmd.displayName=wsl-клиент +wslCmd.displayDescription=Получи доступ к экземплярам WSL с помощью циента wsl CLI +k8sCmd.displayName=клиент kubectl +k8sCmd.displayDescription=Получи доступ к кластерам Kubernetes через kubectl +k8sClusters=Кластеры Kubernetes +shells=Доступные оболочки +startContainer=Стартовый контейнер +stopContainer=Контейнер для остановки +inspectContainer=Осмотрите контейнер +k8sClusterNameDescription=Название контекста, в котором находится кластер. +pod=Под +podName=Название капсулы +k8sClusterContext=Контекст +k8sClusterContextDescription=Название контекста, в котором находится кластер +k8sClusterNamespace=Пространство имен +k8sClusterNamespaceDescription=Пользовательское пространство имен или пространство по умолчанию, если оно пустое +k8sConfigLocation=Конфигурационный файл +k8sConfigLocationDescription=Пользовательский файл kubeconfig или файл по умолчанию, если он остался пустым +inspectPod=Осмотреть капсулу +showAllContainers=Показать неработающие контейнеры +showAllPods=Показать неработающие капсулы +wsl=WSL +docker=Docker +k8sPodHostDescription=Хост, на котором находится капсула +k8sContainerDescription=Имя контейнера Kubernetes +k8sPodDescription=Имя капсулы Kubernetes +podDescription=Капсула, на которой находится контейнер +k8sClusterHostDescription=Хост, через который должен осуществляться доступ к кластеру. Должен быть установлен и настроен kubectl, чтобы иметь возможность получить доступ к кластеру. +script=Init Script +connection=Соединение +shellCommand.displayName=Пользовательская команда открытия оболочки +shellCommand.displayDescription=Открыть стандартную оболочку через пользовательскую команду +ssh.displayName=Простое SSH-соединение +ssh.displayDescription=Подключение через клиент командной строки SSH +sshConfig.displayName=Конфигурационный файл SSH +sshConfig.displayDescription=Подключение к хостам, заданным в конфигурационном файле SSH +sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayDescription=Подключиться к хосту, определенному в конфигурационном файле SSH +sshConfigHost.password=Пароль +sshConfigHost.passwordDescription=Укажи необязательный пароль для входа пользователя в систему. +sshConfigHost.identityPassphrase=Пассфраза идентификации +sshConfigHost.identityPassphraseDescription=Укажи необязательную ключевую фразу для своего идентификационного ключа. +binary.displayName=Бинарный +binary.displayDescription=Двоичные данные +text.displayName=Текст +shellCommand.hostDescription=Хост, на котором будет выполняться команда +shellCommand.commandDescription=Команда, которая открывает оболочку +sshAgent=SSH-агент +none=Нет +commandDescription=Команды, которые нужно выполнить в shell-скрипте на хосте. +commandHostDescription=Хост, на котором будет выполняться команда +commandDataFlowDescription=Как эта команда обрабатывает ввод и вывод +commandElevationDescription=Запустите эту команду с повышенными правами +commandShellTypeDescription=Оболочка, которую нужно использовать для этой команды +ssh.passwordDescription=Необязательный пароль, который нужно использовать при аутентификации +keyAuthentication=Аутентификация на основе ключа +keyAuthenticationDescription=Метод аутентификации, который нужно использовать, если требуется аутентификация на основе ключа. +dontInteractWithSystem=Не взаимодействуй с системой (Pro) +dontInteractWithSystemDescription=Не пытайся определить тип оболочки и операционной системы +sshForwardX11=Форвард X11 +sshForwardX11Description=Включает переадресацию X11 для соединения +customAgent=Пользовательский агент +identityAgent=Агент идентификации +ssh.proxyDescription=Необязательный прокси-хост, который будет использоваться при установлении SSH-соединения. Должен быть установлен ssh-клиент. +usage=Использование +wslHostDescription=Хост, на котором находится экземпляр WSL. Должен быть установлен wsl. +wslDistributionDescription=Имя экземпляра WSL +wslUsernameDescription=Явное имя пользователя, под которым нужно войти в систему. Если оно не указано, будет использоваться имя пользователя по умолчанию. +wslPasswordDescription=Пароль пользователя, который можно использовать для команд sudo. +dockerHostDescription=Хост, на котором находится докер-контейнер. Должен быть установлен docker. +dockerContainerDescription=Имя докер-контейнера +lxdHostDescription=Хост, на котором находится контейнер LXD. Должен быть установлен lxc. +lxdContainerDescription=Имя контейнера LXD +localMachine=Локальная машина +rootScan=Корневая среда оболочки +loginEnvironmentScan=Пользовательская среда входа в систему +k8sScan=Кластер Kubernetes +options=Опции +dockerRunningScan=Запуск контейнеров docker +dockerAllScan=Все докер-контейнеры +wslScan=Экземпляры WSL +sshScan=Конфигурационные соединения SSH +requiresElevation=Run Elevated +default=По умолчанию +wslHost=WSL Host +timeout=Таймаут +installLocation=Место установки +installLocationDescription=Место, где установлена твоя среда $NAME$ +wsl.displayName=Подсистема Windows для Linux +wsl.displayDescription=Подключитесь к экземпляру WSL, работающему под Windows +docker.displayName=Докер-контейнер +docker.displayDescription=Подключение к контейнеру докера +podman.displayName=Контейнер Podman +podman.displayDescription=Подключение к контейнеру Podman +lxd.displayName=Контейнер LXD +lxd.displayDescription=Подключение к контейнеру LXD через lxc +container=Контейнер +host=Хост +port=Порт +user=Пользователь +password=Пароль +method=Метод +uri=URL +proxy=Прокси +distribution=Рассылка +username=Имя пользователя +shellType=Тип оболочки +browseFile=Просмотр файла +openShell=Открыть оболочку в терминале +openCommand=Выполнение команды в терминале +editFile=Редактировать файл +description=Описание +keyFile=Файл идентификации +keyPassword=Пассфраза +key=Ключ +furtherCustomization=Дальнейшая настройка +furtherCustomizationDescription=Для получения дополнительных параметров конфигурации используй файлы конфигурации ssh +location=Расположение +browse=Просматривай +locationDescription=Путь к файлу, в котором находится твой соответствующий закрытый ключ +configHost=Хост +configHostDescription=Хост, на котором расположен конфиг +configLocation=Расположение конфигурации +configLocationDescription=Путь к файлу конфигурации +pageant=Pageant +gpgAgent=GPG Agent (Pro) +gateway=Шлюз +gatewayDescription=Дополнительный шлюз, который нужно использовать при подключении. +connectionInformation=Информация о подключении +connectionInformationDescription=К какой системе подключиться +passwordAuthentication=Проверка подлинности пароля +passwordDescription=Необязательный пароль, который будет использоваться для аутентификации. +sshConfigString.displayName=Настроенное SSH-соединение +sshConfigString.displayDescription=Создай полностью настроенное SSH-соединение +sshConfigStringContent=Конфигурация +sshConfigStringContentDescription=Опции SSH для соединения в формате OpenSSH config +vnc.displayName=VNC-соединение +vnc.displayDescription=Открыть сессию VNC через туннель SSH +binding=Переплет +vncPortDescription=Порт, который прослушивает VNC-сервер +vncUsername=Имя пользователя +vncUsernameDescription=Дополнительное имя пользователя VNC +vncPassword=Пароль +vncPasswordDescription=Пароль VNC +x11WslInstance=Экземпляр X11 Forward WSL +x11WslInstanceDescription=Локальный дистрибутив Windows Subsystem for Linux для использования в качестве X11-сервера при использовании X11-переадресации в SSH-соединении. Этот дистрибутив должен быть WSL2.\n\nДля применения требуется перезагрузка. +openAsRoot=Открыть как корень +openInVsCodeRemote=Открыть в VSCode remote +openInWSL=Открыть в WSL +launch=Запустите diff --git a/lang/proc/strings/translations_tr.properties b/lang/proc/strings/translations_tr.properties new file mode 100644 index 000000000..2c0f88a91 --- /dev/null +++ b/lang/proc/strings/translations_tr.properties @@ -0,0 +1,297 @@ +showInternalPods=Dahili bölmeleri göster +showAllNamespaces=Tüm ad alanlarını göster +showInternalContainers=Dahili konteynerleri göster +refresh=Yenile +vmwareGui=GUI'yi Başlat +monitorVm=Sanal Makineyi İzleme +addCluster=Küme ekleyin ... +showNonRunningInstances=Çalışmayan örnekleri göster +vmwareGuiDescription=Bir sanal makinenin arka planda mı yoksa bir pencerede mi başlatılacağı. +vmwareEncryptionPassword=Şifreleme parolası +vmwareEncryptionPasswordDescription=VM'yi şifrelemek için kullanılan isteğe bağlı parola. +vmwarePasswordDescription=Konuk kullanıcı için gerekli parola. +vmwarePassword=Kullanıcı şifresi +vmwareUser=Misafir kullanıcı +runTempContainer=Geçici konteyneri çalıştır +vmwareUserDescription=Birincil konuk kullanıcınızın kullanıcı adı +dockerTempRunAlertTitle=Geçici konteyneri çalıştır +dockerTempRunAlertHeader=Bu, durdurulduğunda otomatik olarak kaldırılacak geçici bir kapsayıcıda bir kabuk işlemi çalıştıracaktır. +imageName=Resim adı +imageNameDescription=Kullanılacak konteyner imaj tanımlayıcısı +containerName=Konteyner adı +containerNameDescription=İsteğe bağlı özel konteyner adı +vm=Sanal makine +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=İlişkili yapılandırma dosyası. +vmwareScan=VMware masaüstü hipervizörleri +library=Kütüphane +customPkcs11Library=Özel PKCS#11 kütüphanesi (Pro) +vmwareMachine.displayName=VMware Sanal Makinesi +vmwareMachine.displayDescription=SSH aracılığıyla bir sanal makineye bağlanma +vmwareInstallation.displayName=VMware masaüstü hipervizör kurulumu +vmwareInstallation.displayDescription=CLI aracılığıyla kurulu VM'lerle etkileşim +start=Başlangıç +stop=Dur +pause=Duraklat +rdpTunnelHost=Tünel ana bilgisayarı +rdpTunnelHostDescription=Tünel olarak kullanılacak isteğe bağlı SSH bağlantısı +rdpFileLocation=Dosya konumu +rdpFileLocationDescription=.rdp dosyasının dosya yolu +rdpPasswordAuthentication=Şifre doğrulama +rdpPasswordAuthenticationDescription=Destekleniyorsa otomatik olarak doldurulacak parola +rdpFile.displayName=RDP Dosyası +rdpFile.displayDescription=Mevcut bir .rdp dosyası üzerinden bir sisteme bağlanma +requiredSshServerAlertTitle=SSH sunucusunu kurun +requiredSshServerAlertHeader=VM'de kurulu bir SSH sunucusu bulunamıyor. +requiredSshServerAlertContent=VM'ye bağlanmak için XPipe çalışan bir SSH sunucusu arıyor ancak VM için kullanılabilir bir SSH sunucusu algılanmadı. +computerName=Bilgisayar Adı +pssComputerNameDescription=Bağlanılacak bilgisayar adı. Bu bilgisayarın zaten güvenilir ana bilgisayarlarınıza dahil olduğu varsayılır. +credentialUser=Kimlik Bilgisi Kullanıcısı +pssCredentialUserDescription=Oturum açılacak kullanıcı. +credentialPassword=Kimlik Bilgisi Şifresi +pssCredentialPasswordDescription=Kullanıcının parolası. +sshConfig=SSH yapılandırma dosyaları +autostart=XPipe başlatıldığında otomatik olarak bağlan +acceptHostKey=Ana bilgisayar anahtarını kabul et +modifyHostKeyPermissions=Ana bilgisayar anahtar izinlerini değiştirme +attachContainer=Konteynere takın +openInVsCode=VSCode'da Aç +containerLogs=Konteyner günlüklerini göster +openSftpClient=Harici SFTP istemcisinde açın +openTermius=Termius'da açık +showInternalInstances=Dahili örnekleri göster +editPod=Düzenleme bölmesi +acceptHostKeyDescription=Yeni ana bilgisayar anahtarına güvenin ve devam edin +modifyHostKeyPermissionsDescription=OpenSSH'nin mutlu olması için orijinal dosyanın izinlerini kaldırmaya çalışın +psSession.displayName=PowerShell Uzak Oturumu +psSession.displayDescription=New-PSSession ve Enter-PSSession aracılığıyla bağlanın +sshLocalTunnel.displayName=Yerel SSH tüneli +sshLocalTunnel.displayDescription=Uzak bir ana bilgisayara SSH tüneli oluşturma +sshRemoteTunnel.displayName=Uzak SSH tüneli +sshRemoteTunnel.displayDescription=Uzak bir ana bilgisayardan ters SSH tüneli oluşturma +sshDynamicTunnel.displayName=Dinamik SSH tüneli +sshDynamicTunnel.displayDescription=SSH bağlantısı aracılığıyla bir SOCKS proxy oluşturma +shellEnvironmentGroup.displayName=Kabuk Ortamları +shellEnvironmentGroup.displayDescription=Kabuk Ortamları +shellEnvironment.displayName=Özel Kabuk Ortamı +shellEnvironment.displayDescription=Özelleştirilmiş bir kabuk başlangıç ortamı oluşturma +shellEnvironment.informationFormat=$TYPE$ çevre +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ çevre +environmentConnectionDescription=Için bir ortam yaratmak için temel bağlantı +environmentScriptDescription=Kabukta çalıştırılacak isteğe bağlı özel init betiği +environmentSnippets=Kod parçacıkları +commandSnippetsDescription=İlk olarak çalıştırılacak isteğe bağlı önceden tanımlanmış kod parçacıkları +environmentSnippetsDescription=Başlatma sırasında çalıştırılacak isteğe bağlı önceden tanımlanmış kod parçacıkları +shellTypeDescription=Başlatılacak açık kabuk türü +originPort=Menşe bağlantı noktası +originAddress=Menşe adresi +remoteAddress=Uzak adres +remotePort=Uzak bağlantı noktası +remoteSourceAddress=Uzak kaynak adresi +remoteSourcePort=Uzak kaynak bağlantı noktası +originDestinationPort=Kaynak hedef bağlantı noktası +originDestinationAddress=Kaynak hedef adresi +origin=Köken +remoteHost=Uzak ana bilgisayar +address=Adres +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Proxmox Sanal Ortamındaki sistemlere bağlanma +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=SSH aracılığıyla Proxmox VE'deki bir sanal makineye bağlanma +proxmoxContainer.displayName=Proxmox Konteyner +proxmoxContainer.displayDescription=Proxmox VE'deki bir konteynere bağlanma +sshDynamicTunnel.originDescription=Ssh bağlantısının açılacağı sistem +sshDynamicTunnel.hostDescription=SOCKS proxy olarak kullanılacak sistem +sshDynamicTunnel.bindingDescription=Tünelin hangi adreslere bağlanacağı +sshRemoteTunnel.originDescription=Ssh bağlantısının açılacağı ve tünelin açılacağı sistem +sshRemoteTunnel.hostDescription=Orijine giden uzak tünelin başlatılacağı sistem +sshRemoteTunnel.bindingDescription=Tünelin hangi adreslere bağlanacağı +sshLocalTunnel.originDescription=Tünelin başlatılacağı sistem +sshLocalTunnel.hostDescription=Tüneli açmak için sistem +sshLocalTunnel.bindingDescription=Tünelin hangi adreslere bağlanacağı +sshLocalTunnel.localAddressDescription=Bağlanacak yerel adres +sshLocalTunnel.remoteAddressDescription=Bağlanacak uzak adres +cmd.displayName=Özel Terminal Komutu +cmd.displayDescription=Terminalinizde bir sistem üzerinde özel bir komut çalıştırın +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=Kubectl aracılığıyla bir pod'a ve kapsayıcılarına bağlanma +k8sContainer.displayName=Kubernetes Konteyner +k8sContainer.displayDescription=Bir konteynere kabuk açma +k8sCluster.displayName=Kubernetes Kümesi +k8sCluster.displayDescription=Bir kümeye ve podlarına kubectl aracılığıyla bağlanma +sshTunnelGroup.displayName=SSH Tünelleri +sshTunnelGroup.displayCategory=Her tür SSH tüneli +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=CLI istemcisi aracılığıyla Podman kapsayıcılarına erişim +podmanContainers=Podman konteynerleri +local.displayName=Yerel makine +local.displayDescription=Yerel makinenin kabuğu +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Windows için Git +gitForWindows.displayName=Windows için Git +gitForWindows.displayDescription=Yerel Git For Windows ortamınıza erişin +msys2.displayName=MSYS2 +msys2.displayDescription=MSYS2 ortamınızın kabuklarına erişim +cygwin.displayName=Cygwin +cygwin.displayDescription=Cygwin ortamınızın kabuklarına erişim +namespace=İsim Alanı +gitVaultIdentityStrategy=Git SSH kimliği +gitVaultIdentityStrategyDescription=Uzak olarak bir SSH git URL'si kullanmayı seçtiyseniz ve uzak deponuz bir SSH kimliği gerektiriyorsa, bu seçeneği ayarlayın.\n\nBir HTTP URL'si sağlamanız durumunda, bu seçeneği göz ardı edebilirsiniz. +dockerContainers=Docker kapsayıcıları +lxdContainers=LXD konteynerleri +dockerCmd.displayName=docker CLI istemcisi +dockerCmd.displayDescription=Docker konteynerlerine docker CLI istemcisi aracılığıyla erişin +lxdCmd.displayName=LXD CLI istemcisi +lxdCmd.displayDescription=LXD konteynerlerine lxc CLI cient aracılığıyla erişin +wslCmd.displayName=wsl istemcisi +wslCmd.displayDescription=WSL örneklerine wsl CLI cient aracılığıyla erişin +k8sCmd.displayName=kubectl istemcisi +k8sCmd.displayDescription=Kubectl aracılığıyla Kubernetes kümelerine erişim +k8sClusters=Kubernetes kümeleri +shells=Mevcut kabuklar +startContainer=Konteyneri başlat +stopContainer=Konteyneri durdur +inspectContainer=Konteyneri inceleyin +k8sClusterNameDescription=Kümenin içinde bulunduğu bağlamın adı. +pod=Pod +podName=Bölme adı +k8sClusterContext=Bağlam +k8sClusterContextDescription=Kümenin içinde bulunduğu bağlamın adı +k8sClusterNamespace=İsim Alanı +k8sClusterNamespaceDescription=Özel ad alanı veya boşsa varsayılan ad alanı +k8sConfigLocation=Yapılandırma dosyası +k8sConfigLocationDescription=Özel kubeconfig dosyası veya boş bırakılırsa varsayılan dosya +inspectPod=Kapsülü inceleyin +showAllContainers=Çalışmayan kapsayıcıları göster +showAllPods=Çalışmayan podları göster +wsl=WSL +docker=Docker +k8sPodHostDescription=Pod'un bulunduğu ana bilgisayar +k8sContainerDescription=Kubernetes konteynerinin adı +k8sPodDescription=Kubernetes podunun adı +podDescription=Konteynerin üzerinde bulunduğu bölme +k8sClusterHostDescription=Kümeye erişilmesi gereken ana bilgisayar. Kümeye erişebilmek için kubectl yüklü ve yapılandırılmış olmalıdır. +script=Başlangıç Komut Dosyası +connection=Bağlantı +shellCommand.displayName=Özel Kabuk Açıcı Komutu +shellCommand.displayDescription=Özel bir komut aracılığıyla standart bir kabuk açma +ssh.displayName=Basit SSH Bağlantısı +ssh.displayDescription=Bir SSH komut satırı istemcisi aracılığıyla bağlanma +sshConfig.displayName=SSH Yapılandırma Dosyası +sshConfig.displayDescription=SSH yapılandırma dosyasında tanımlanan ana bilgisayarlara bağlanma +sshConfigHost.displayName=SSH Yapılandırma Dosyası Ana Bilgisayar +sshConfigHost.displayDescription=SSH yapılandırma dosyasında tanımlanan bir ana bilgisayara bağlanma +sshConfigHost.password=Şifre +sshConfigHost.passwordDescription=Kullanıcı girişi için isteğe bağlı parolayı girin. +sshConfigHost.identityPassphrase=Kimlik parolası +sshConfigHost.identityPassphraseDescription=Kimlik anahtarınız için isteğe bağlı parolayı girin. +binary.displayName=İkili +binary.displayDescription=İkili veri +text.displayName=Metin +shellCommand.hostDescription=Komutun çalıştırılacağı ana bilgisayar +shellCommand.commandDescription=Bir kabuk açacak komut +sshAgent=SSH-Agent +none=Hiçbiri +commandDescription=Ana bilgisayarda bir kabuk komut dosyasında yürütülecek komutlar. +commandHostDescription=Komutun çalıştırılacağı ana bilgisayar +commandDataFlowDescription=Bu komut girdi ve çıktıyı nasıl işler? +commandElevationDescription=Bu komutu yükseltilmiş izinlerle çalıştırın +commandShellTypeDescription=Bu komut için kullanılacak kabuk +ssh.passwordDescription=Kimlik doğrulama sırasında kullanılacak isteğe bağlı parola +keyAuthentication=Anahtar tabanlı kimlik doğrulama +keyAuthenticationDescription=Anahtar tabanlı kimlik doğrulama gerekiyorsa kullanılacak kimlik doğrulama yöntemi. +dontInteractWithSystem=Sistemle etkileşime girme (Pro) +dontInteractWithSystemDescription=Kabuk ve işletim sistemi türünü tanımlamaya çalışmayın +sshForwardX11=İleri X11 +sshForwardX11Description=Bağlantı için X11 yönlendirmesini etkinleştirir +customAgent=Özel Temsilci +identityAgent=Kimlik temsilcisi +ssh.proxyDescription=SSH bağlantısı kurulurken kullanılacak isteğe bağlı proxy ana bilgisayarı. Bir ssh istemcisinin kurulu olması gerekir. +usage=Kullanım +wslHostDescription=WSL örneğinin üzerinde bulunduğu ana bilgisayar. Wsl yüklü olmalıdır. +wslDistributionDescription=WSL örneğinin adı +wslUsernameDescription=Oturum açmak için açık kullanıcı adı. Belirtilmezse, varsayılan kullanıcı adı kullanılacaktır. +wslPasswordDescription=Kullanıcının sudo komutları için kullanılabilecek parolası. +dockerHostDescription=Docker konteynerinin üzerinde bulunduğu ana bilgisayar. Docker yüklü olmalıdır. +dockerContainerDescription=Docker konteynerinin adı +lxdHostDescription=LXD konteynerinin üzerinde bulunduğu ana bilgisayar. Lxc yüklü olmalıdır. +lxdContainerDescription=LXD konteynerinin adı +localMachine=Yerel Makine +rootScan=Kök kabuk ortamı +loginEnvironmentScan=Özel oturum açma ortamı +k8sScan=Kubernetes kümesi +options=Seçenekler +dockerRunningScan=Docker konteynerlerini çalıştırma +dockerAllScan=Tüm docker konteynerleri +wslScan=WSL örnekleri +sshScan=SSH yapılandırma bağlantıları +requiresElevation=Yükseltilmiş Koşu +default=Varsayılan +wslHost=WSL Ev Sahibi +timeout=Zaman Aşımı +installLocation=Kurulum yeri +installLocationDescription=$NAME$ ortamınızın kurulu olduğu konum +wsl.displayName=Linux için Windows Alt Sistemi +wsl.displayDescription=Windows üzerinde çalışan bir WSL örneğine bağlanma +docker.displayName=Docker Konteyner +docker.displayDescription=Bir docker konteynerine bağlanma +podman.displayName=Podman Konteyner +podman.displayDescription=Bir Podman konteynerine bağlanma +lxd.displayName=LXD Konteyner +lxd.displayDescription=Lxc aracılığıyla bir LXD konteynerine bağlanma +container=Konteyner +host=Ev sahibi +port=Liman +user=Kullanıcı +password=Şifre +method=Yöntem +uri=URL +proxy=Proxy +distribution=Dağıtım +username=Kullanıcı Adı +shellType=Kabuk Tipi +browseFile=Dosyaya Gözat +openShell=Terminal'de Kabuk Açma +openCommand=Terminal'de Komut Çalıştırma +editFile=Dosya Düzenle +description=Açıklama +keyFile=Kimlik Dosyası +keyPassword=Parola +key=Anahtar +furtherCustomization=Daha fazla özelleştirme +furtherCustomizationDescription=Daha fazla yapılandırma seçeneği için ssh yapılandırma dosyalarını kullanın +location=Konum +browse=Gözat +locationDescription=İlgili özel anahtarınızın dosya yolu +configHost=Ev sahibi +configHostDescription=Yapılandırmanın üzerinde bulunduğu ana bilgisayar +configLocation=Konfigürasyon konumu +configLocationDescription=Yapılandırma dosyasının dosya yolu +pageant=Pageant +gpgAgent=GPG Agent (Pro) +gateway=Ağ Geçidi +gatewayDescription=Bağlanırken kullanılacak isteğe bağlı ağ geçidi. +connectionInformation=Bağlantı bilgileri +connectionInformationDescription=Hangi sisteme bağlanılacağı +passwordAuthentication=Şifre doğrulama +passwordDescription=Kimlik doğrulamak için kullanılacak isteğe bağlı parola. +sshConfigString.displayName=Özelleştirilmiş SSH Bağlantısı +sshConfigString.displayDescription=Tamamen özelleştirilmiş bir SSH bağlantısı oluşturma +sshConfigStringContent=Konfigürasyon +sshConfigStringContentDescription=OpenSSH yapılandırma biçiminde bağlantı için SSH seçenekleri +vnc.displayName=VNC bağlantısı +vnc.displayDescription=SSH tüneli üzerinden bir VNC oturumu açma +binding=Bağlayıcı +vncPortDescription=VNC sunucusunun dinlediği bağlantı noktası +vncUsername=Kullanıcı Adı +vncUsernameDescription=İsteğe bağlı VNC kullanıcı adı +vncPassword=Şifre +vncPasswordDescription=VNC şifresi +x11WslInstance=X11 İleri WSL örneği +x11WslInstanceDescription=Bir SSH bağlantısında X11 iletimi kullanılırken X11 sunucusu olarak kullanılacak yerel Linux için Windows Alt Sistemi dağıtımı. Bu dağıtım bir WSL2 dağıtımı olmalıdır.\n\nUygulamak için yeniden başlatma gerekir. +openAsRoot=Kök olarak aç +openInVsCodeRemote=VSCode remote'da açın +openInWSL=WSL'de Açık +launch=Fırlatma diff --git a/lang/proc/strings/translations_zh.properties b/lang/proc/strings/translations_zh.properties new file mode 100644 index 000000000..7653d4473 --- /dev/null +++ b/lang/proc/strings/translations_zh.properties @@ -0,0 +1,297 @@ +showInternalPods=显示内部 pod +showAllNamespaces=显示所有命名空间 +showInternalContainers=显示内部容器 +refresh=刷新 +vmwareGui=启动图形用户界面 +monitorVm=监控虚拟机 +addCluster=添加集群 ... +showNonRunningInstances=显示非运行实例 +vmwareGuiDescription=是在后台启动虚拟机,还是在窗口中启动。 +vmwareEncryptionPassword=加密密码 +vmwareEncryptionPasswordDescription=用于加密虚拟机的可选密码。 +vmwarePasswordDescription=访客用户所需的密码。 +vmwarePassword=用户密码 +vmwareUser=访客用户 +runTempContainer=运行临时容器 +vmwareUserDescription=主要访客用户的用户名 +dockerTempRunAlertTitle=运行临时容器 +dockerTempRunAlertHeader=这将在临时容器中运行一个 shell 进程,一旦停止,该进程将自动删除。 +imageName=图像名称 +imageNameDescription=要使用的容器图像标识符 +containerName=容器名称 +containerNameDescription=可选的自定义容器名称 +vm=虚拟机 +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=相关的配置文件。 +vmwareScan=VMware 桌面管理程序 +library=图书馆 +customPkcs11Library=自定义 PKCS#11 库(专业版) +vmwareMachine.displayName=VMware 虚拟机 +vmwareMachine.displayDescription=通过 SSH 连接虚拟机 +vmwareInstallation.displayName=安装 VMware 桌面管理程序 +vmwareInstallation.displayDescription=通过 CLI 与已安装的虚拟机交互 +start=开始 +stop=停止 +pause=暂停 +rdpTunnelHost=隧道主机 +rdpTunnelHostDescription=用作隧道的可选 SSH 连接 +rdpFileLocation=文件位置 +rdpFileLocationDescription=.rdp 文件的文件路径 +rdpPasswordAuthentication=密码验证 +rdpPasswordAuthenticationDescription=如果支持自动填写密码 +rdpFile.displayName=RDP 文件 +rdpFile.displayDescription=通过现有 .rdp 文件连接系统 +requiredSshServerAlertTitle=设置 SSH 服务器 +requiredSshServerAlertHeader=无法在虚拟机中找到已安装的 SSH 服务器。 +requiredSshServerAlertContent=为了连接到虚拟机,XPipe 正在寻找运行中的 SSH 服务器,但没有检测到虚拟机的可用 SSH 服务器。 +computerName=计算机名称 +pssComputerNameDescription=要连接的计算机名称。假定它已包含在受信任主机中。 +credentialUser=凭证用户 +pssCredentialUserDescription=要登录的用户。 +credentialPassword=凭证密码 +pssCredentialPasswordDescription=用户的密码。 +sshConfig=SSH 配置文件 +autostart=在 XPipe 启动时自动连接 +acceptHostKey=接受主机密钥 +modifyHostKeyPermissions=修改主机密钥权限 +attachContainer=附加到容器 +openInVsCode=在 VSCode 中打开 +containerLogs=显示容器日志 +openSftpClient=在外部 SFTP 客户端中打开 +openTermius=在 Termius 中打开 +showInternalInstances=显示内部实例 +editPod=编辑舱 +acceptHostKeyDescription=信任新主机密钥并继续 +modifyHostKeyPermissionsDescription=尝试删除原始文件的权限,使 OpenSSH 满意 +psSession.displayName=PowerShell 远程会话 +psSession.displayDescription=通过 New-PSSession 和 Enter-PSSession 连接 +sshLocalTunnel.displayName=本地 SSH 通道 +sshLocalTunnel.displayDescription=建立连接远程主机的 SSH 通道 +sshRemoteTunnel.displayName=远程 SSH 通道 +sshRemoteTunnel.displayDescription=从远程主机建立反向 SSH 通道 +sshDynamicTunnel.displayName=动态 SSH 通道 +sshDynamicTunnel.displayDescription=通过 SSH 连接建立 SOCKS 代理 +shellEnvironmentGroup.displayName=外壳环境 +shellEnvironmentGroup.displayDescription=外壳环境 +shellEnvironment.displayName=自定义外壳环境 +shellEnvironment.displayDescription=创建自定义的 shell 启动环境 +shellEnvironment.informationFormat=$TYPE$ 环境 +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ 环境 +environmentConnectionDescription=创建环境的基础连接 +environmentScriptDescription=在 shell 中运行的可选自定义启动脚本 +environmentSnippets=脚本片段 +commandSnippetsDescription=首先运行的可选预定义脚本片段 +environmentSnippetsDescription=初始化时运行的可选预定义脚本片段 +shellTypeDescription=要启动的显式 shell 类型 +originPort=原点端口 +originAddress=来源地址 +remoteAddress=远程地址 +remotePort=远程端口 +remoteSourceAddress=远程源地址 +remoteSourcePort=远程源端口 +originDestinationPort=出发地目的地端口 +originDestinationAddress=出发地目的地地址 +origin=起源 +remoteHost=远程主机 +address=地址 +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=连接 Proxmox 虚拟环境中的系统 +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=通过 SSH 连接到 Proxmox VE 中的虚拟机 +proxmoxContainer.displayName=Proxmox 容器 +proxmoxContainer.displayDescription=连接到 Proxmox VE 中的容器 +sshDynamicTunnel.originDescription=打开 ssh 连接的系统 +sshDynamicTunnel.hostDescription=用作 SOCKS 代理的系统 +sshDynamicTunnel.bindingDescription=将隧道绑定到哪些地址 +sshRemoteTunnel.originDescription=从哪个系统打开 ssh 连接并打开连接到哪个系统的隧道 +sshRemoteTunnel.hostDescription=从哪个系统启动到原点的远程隧道 +sshRemoteTunnel.bindingDescription=将隧道绑定到哪些地址 +sshLocalTunnel.originDescription=从何处开始隧道的系统 +sshLocalTunnel.hostDescription=打开隧道的系统 +sshLocalTunnel.bindingDescription=将隧道绑定到哪些地址 +sshLocalTunnel.localAddressDescription=绑定的本地地址 +sshLocalTunnel.remoteAddressDescription=要绑定的远程地址 +cmd.displayName=自定义终端命令 +cmd.displayDescription=在终端上运行系统自定义命令 +k8sPod.displayName=Kubernetes Pod +k8sPod.displayDescription=通过 kubectl 连接 pod 及其容器 +k8sContainer.displayName=Kubernetes 容器 +k8sContainer.displayDescription=为容器打开外壳 +k8sCluster.displayName=Kubernetes 集群 +k8sCluster.displayDescription=通过 kubectl 连接到集群及其 pod +sshTunnelGroup.displayName=SSH 隧道 +sshTunnelGroup.displayCategory=所有类型的 SSH 隧道 +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=通过 CLI 客户端访问 Podman 容器 +podmanContainers=Podman 容器 +local.displayName=本地机器 +local.displayDescription=本地计算机的 shell +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Windows 版 Git +gitForWindows.displayName=Windows 版 Git +gitForWindows.displayDescription=访问本地 Git for Windows 环境 +msys2.displayName=MSYS2 +msys2.displayDescription=MSYS2 环境的访问外壳 +cygwin.displayName=Cygwin +cygwin.displayDescription=访问 Cygwin 环境的 shell +namespace=名称空间 +gitVaultIdentityStrategy=Git SSH 身份 +gitVaultIdentityStrategyDescription=如果选择使用 SSH git URL 作为远程,且远程仓库需要 SSH 身份,则设置此选项。\n\n如果您提供的是 HTTP 网址,则可以忽略此选项。 +dockerContainers=Docker 容器 +lxdContainers=LXD 容器 +dockerCmd.displayName=docker CLI 客户端 +dockerCmd.displayDescription=通过 docker CLI 客户端访问 Docker 容器 +lxdCmd.displayName=LXD CLI 客户端 +lxdCmd.displayDescription=通过 lxc CLI 方便地访问 LXD 容器 +wslCmd.displayName=wsl 客户端 +wslCmd.displayDescription=通过 wsl CLI 方便地访问 WSL 实例 +k8sCmd.displayName=kubectl 客户端 +k8sCmd.displayDescription=通过 kubectl 访问 Kubernetes 集群 +k8sClusters=Kubernetes 集群 +shells=可用外壳 +startContainer=启动容器 +stopContainer=停止容器 +inspectContainer=检查容器 +k8sClusterNameDescription=群组所处上下文的名称。 +pod=花苞 +podName=舱名 +k8sClusterContext=语境 +k8sClusterContextDescription=群组所处上下文的名称 +k8sClusterNamespace=名称空间 +k8sClusterNamespaceDescription=自定义命名空间或默认命名空间(如果为空 +k8sConfigLocation=配置文件 +k8sConfigLocationDescription=自定义的 kubeconfig 文件或默认文件(如果留空)。 +inspectPod=检查舱 +showAllContainers=显示未运行的容器 +showAllPods=显示未运行的 pod +wsl=WSL +docker=装载机 +k8sPodHostDescription=pod 所在主机 +k8sContainerDescription=Kubernetes 容器的名称 +k8sPodDescription=Kubernetes pod 的名称 +podDescription=容器所在的 pod +k8sClusterHostDescription=访问群集的主机。必须安装并配置 kubectl 才能访问群集。 +script=初始脚本 +connection=连接 +shellCommand.displayName=自定义外壳打开器命令 +shellCommand.displayDescription=通过自定义命令打开标准 shell +ssh.displayName=简单 SSH 连接 +ssh.displayDescription=通过 SSH 命令行客户端连接 +sshConfig.displayName=SSH 配置文件 +sshConfig.displayDescription=连接 SSH 配置文件中定义的主机 +sshConfigHost.displayName=SSH 配置文件主机 +sshConfigHost.displayDescription=连接到 SSH 配置文件中定义的主机 +sshConfigHost.password=密码 +sshConfigHost.passwordDescription=为用户登录提供可选密码。 +sshConfigHost.identityPassphrase=身份密码 +sshConfigHost.identityPassphraseDescription=提供身份密钥的可选口令。 +binary.displayName=二进制 +binary.displayDescription=二进制数据 +text.displayName=文本 +shellCommand.hostDescription=执行命令的主机 +shellCommand.commandDescription=打开 shell 的命令 +sshAgent=SSH 代理 +none=无 +commandDescription=在主机上执行 shell 脚本的命令。 +commandHostDescription=运行命令的主机 +commandDataFlowDescription=该命令如何处理输入和输出 +commandElevationDescription=以提升的权限运行此命令 +commandShellTypeDescription=该命令使用的 shell +ssh.passwordDescription=验证时使用的可选密码 +keyAuthentication=基于密钥的身份验证 +keyAuthenticationDescription=如果需要基于密钥的身份验证,应使用的身份验证方法。 +dontInteractWithSystem=不与系统交互(专业版) +dontInteractWithSystemDescription=不要试图识别外壳和操作系统类型 +sshForwardX11=转发 X11 +sshForwardX11Description=为连接启用 X11 转发 +customAgent=自定义代理 +identityAgent=身份代理 +ssh.proxyDescription=建立 SSH 连接时使用的可选代理主机。必须已安装 ssh 客户端。 +usage=使用方法 +wslHostDescription=WSL 实例所在的主机。必须已安装 wsl。 +wslDistributionDescription=WSL 实例的名称 +wslUsernameDescription=要登录的明确用户名。如果未指定,将使用默认用户名。 +wslPasswordDescription=用户密码,可用于执行 sudo 命令。 +dockerHostDescription=docker 容器所在的主机。必须已安装 docker。 +dockerContainerDescription=docker 容器的名称 +lxdHostDescription=LXD 容器所在的主机。必须已安装 lxc。 +lxdContainerDescription=LXD 容器的名称 +localMachine=本地机器 +rootScan=根 shell 环境 +loginEnvironmentScan=自定义登录环境 +k8sScan=Kubernetes 集群 +options=选项 +dockerRunningScan=运行 docker 容器 +dockerAllScan=所有 docker 容器 +wslScan=WSL 实例 +sshScan=SSH 配置连接 +requiresElevation=提升运行 +default=默认值 +wslHost=WSL 主机 +timeout=超时 +installLocation=安装位置 +installLocationDescription=$NAME$ 环境的安装位置 +wsl.displayName=Linux 下的 Windows 子系统 +wsl.displayDescription=连接到在 Windows 上运行的 WSL 实例 +docker.displayName=Docker 容器 +docker.displayDescription=连接到 docker 容器 +podman.displayName=Podman 容器 +podman.displayDescription=连接到 Podman 容器 +lxd.displayName=LXD 容器 +lxd.displayDescription=通过 lxc 连接到 LXD 容器 +container=容器 +host=主机 +port=端口 +user=用户 +password=密码 +method=方法 +uri=网址 +proxy=代理 +distribution=分发 +username=用户名 +shellType=外壳类型 +browseFile=浏览文件 +openShell=在终端中打开 Shell +openCommand=在终端中执行命令 +editFile=编辑文件 +description=说明 +keyFile=身份文件 +keyPassword=密码 +key=关键字 +furtherCustomization=进一步定制 +furtherCustomizationDescription=有关更多配置选项,请使用 ssh 配置文件 +location=地点 +browse=浏览 +locationDescription=相应私钥的文件路径 +configHost=主机 +configHostDescription=配置所在的主机 +configLocation=配置位置 +configLocationDescription=配置文件的文件路径 +pageant=页面 +gpgAgent=GPG 代理(专业版) +gateway=网关 +gatewayDescription=连接时使用的可选网关。 +connectionInformation=连接信息 +connectionInformationDescription=连接哪个系统 +passwordAuthentication=密码验证 +passwordDescription=用于验证的可选密码。 +sshConfigString.displayName=定制 SSH 连接 +sshConfigString.displayDescription=创建完全自定义的 SSH 连接 +sshConfigStringContent=配置 +sshConfigStringContentDescription=OpenSSH 配置格式的 SSH 连接选项 +vnc.displayName=VNC 连接 +vnc.displayDescription=通过 SSH 通道打开 VNC 会话 +binding=绑定 +vncPortDescription=VNC 服务器监听的端口 +vncUsername=用户名 +vncUsernameDescription=可选的 VNC 用户名 +vncPassword=密码 +vncPasswordDescription=VNC 密码 +x11WslInstance=X11 Forward WSL 实例 +x11WslInstanceDescription=在 SSH 连接中使用 X11 转发时,用作 X11 服务器的本地 Windows Subsystem for Linux 发行版。该发行版必须是 WSL2 发行版。\n\n需要重新启动才能应用。 +openAsRoot=以根用户身份打开 +openInVsCodeRemote=在 VSCode 远程中打开 +openInWSL=在 WSL 中打开 +launch=启动 diff --git a/lang/proc/texts/elevation_de.md b/lang/proc/texts/elevation_de.md new file mode 100644 index 000000000..61dd15bac --- /dev/null +++ b/lang/proc/texts/elevation_de.md @@ -0,0 +1,11 @@ +## Elevation + +Der Prozess der Berechtigungserweiterung ist betriebssystemspezifisch. + +### Linux & macOS + +Jeder erweiterte Befehl wird mit `sudo` ausgeführt. Das optionale `sudo` Passwort wird bei Bedarf über XPipe abgefragt. Du kannst in den Einstellungen festlegen, ob du dein Passwort jedes Mal eingeben willst, wenn es gebraucht wird, oder ob du es für die aktuelle Sitzung zwischenspeichern willst. + +### Windows + +Unter Windows ist es nicht möglich, die Berechtigungen eines untergeordneten Prozesses zu erhöhen, wenn der übergeordnete Prozess nicht ebenfalls mit erhöhten Berechtigungen ausgeführt wird. Wenn XPipe also nicht als Administrator ausgeführt wird, kannst du lokal keine Berechtigungserweiterung nutzen. Bei Fernverbindungen muss das verbundene Benutzerkonto mit Administratorrechten ausgestattet sein. \ No newline at end of file diff --git a/lang/proc/texts/elevation_en.md b/lang/proc/texts/elevation_en.md new file mode 100644 index 000000000..a2e5326b5 --- /dev/null +++ b/lang/proc/texts/elevation_en.md @@ -0,0 +1,11 @@ +## Elevation + +The process of permissions elevation is operating system specific. + +### Linux & macOS + +Any elevated command is executed with `sudo`. The optional `sudo` password is queried via XPipe when needed. You have the ability to adjust the elevation behavior in the settings to control whether you want to enter your password every time it is needed or if you want to cache it for the current session. + +### Windows + +On Windows, it is not possible to elevate the permissions of a child process if the parent process is not running with elevated permissions as well. Therefore, if XPipe is not run as an administrator, you will be unable to use any elevation locally. For remote connections, the connected user account has to be given administrator privileges. \ No newline at end of file diff --git a/lang/proc/texts/elevation_es.md b/lang/proc/texts/elevation_es.md new file mode 100644 index 000000000..337a7dc0b --- /dev/null +++ b/lang/proc/texts/elevation_es.md @@ -0,0 +1,11 @@ +## Elevación + +El proceso de elevación de permisos es específico del sistema operativo. + +### Linux y macOS + +Cualquier comando elevado se ejecuta con `sudo`. La contraseña opcional `sudo` se consulta a través de XPipe cuando es necesario. Tienes la posibilidad de ajustar el comportamiento de elevación en la configuración para controlar si quieres introducir tu contraseña cada vez que se necesite o si quieres guardarla en caché para la sesión actual. + +### Windows + +En Windows, no es posible elevar los permisos de un proceso hijo si el proceso padre no se está ejecutando también con permisos elevados. Por lo tanto, si XPipe no se ejecuta como administrador, no podrás utilizar ninguna elevación localmente. Para las conexiones remotas, la cuenta de usuario conectada debe tener privilegios de administrador. \ No newline at end of file diff --git a/lang/proc/texts/elevation_fr.md b/lang/proc/texts/elevation_fr.md new file mode 100644 index 000000000..c2a08fe1f --- /dev/null +++ b/lang/proc/texts/elevation_fr.md @@ -0,0 +1,11 @@ +## Élévation + +Le processus d'élévation des permissions est spécifique au système d'exploitation. + +### Linux et macOS + +Toute commande élevée est exécutée avec `sudo`. Le mot de passe facultatif `sudo` est interrogé via XPipe lorsque cela est nécessaire. Tu as la possibilité d'ajuster le comportement d'élévation dans les paramètres pour contrôler si tu veux saisir ton mot de passe à chaque fois qu'il est nécessaire ou si tu veux le mettre en cache pour la session en cours. + +### Windows + +Sous Windows, il n'est pas possible d'élever les permissions d'un processus enfant si le processus parent ne s'exécute pas également avec des permissions élevées. Par conséquent, si XPipe n'est pas exécuté en tant qu'administrateur, tu ne pourras pas utiliser d'élévation localement. Pour les connexions à distance, le compte d'utilisateur connecté doit avoir des privilèges d'administrateur. \ No newline at end of file diff --git a/lang/proc/texts/elevation_it.md b/lang/proc/texts/elevation_it.md new file mode 100644 index 000000000..d9daf4fe8 --- /dev/null +++ b/lang/proc/texts/elevation_it.md @@ -0,0 +1,11 @@ +## Elevazione + +Il processo di elevazione dei permessi è specifico del sistema operativo. + +### Linux e macOS + +Qualsiasi comando elevato viene eseguito con `sudo`. La password opzionale `sudo` viene interrogata tramite XPipe quando necessario. Hai la possibilità di regolare il comportamento di elevazione nelle impostazioni per controllare se vuoi inserire la password ogni volta che è necessaria o se vuoi memorizzarla per la sessione corrente. + +### Windows + +In Windows, non è possibile elevare i permessi di un processo figlio se anche il processo padre non è in esecuzione con permessi elevati. Pertanto, se XPipe non viene eseguito come amministratore, non potrai utilizzare l'elevazione a livello locale. Per le connessioni remote, l'account utente collegato deve avere i privilegi di amministratore. \ No newline at end of file diff --git a/lang/proc/texts/elevation_ja.md b/lang/proc/texts/elevation_ja.md new file mode 100644 index 000000000..e94800263 --- /dev/null +++ b/lang/proc/texts/elevation_ja.md @@ -0,0 +1,11 @@ +## 標高 + +パーミッションの昇格プロセスはオペレーティングシステムに依存する。 + +### Linux & macOS + +すべての昇格コマンドは`sudo`で実行される。オプションの`sudo`パスワードは、必要に応じてXPipe経由で照会される。パスワードが必要になるたびにパスワードを入力するか、現在のセッションのためにパスワードをキャッシュするかを制御するために、設定で昇格の動作を調整する機能がある。 + +### ウィンドウズ + +Windowsでは、親プロセスが昇格されたパーミッションで実行されていない場合、子プロセスのパーミッションを昇格することはできない。したがって、XPipeが管理者として実行されていない場合、ローカルで昇格を使用することはできない。リモート接続の場合は、接続先のユーザーアカウントに管理者権限を与える必要がある。 \ No newline at end of file diff --git a/lang/proc/texts/elevation_nl.md b/lang/proc/texts/elevation_nl.md new file mode 100644 index 000000000..045a9ae6a --- /dev/null +++ b/lang/proc/texts/elevation_nl.md @@ -0,0 +1,11 @@ +## Hoogte + +Het proces van permissieverhoging is besturingssysteemspecifiek. + +### Linux en macOS + +Elk verhoogd commando wordt uitgevoerd met `sudo`. Het optionele `sudo` wachtwoord wordt indien nodig opgevraagd via XPipe. Je hebt de mogelijkheid om het verheffingsgedrag aan te passen in de instellingen om te bepalen of je je wachtwoord elke keer wilt invoeren als het nodig is of dat je het wilt cachen voor de huidige sessie. + +### Windows + +In Windows is het niet mogelijk om de rechten van een kindproces te verhogen als het ouderproces niet ook met verhoogde rechten draait. Als XPipe dus niet als beheerder wordt uitgevoerd, kun je lokaal geen verheffing gebruiken. Voor verbindingen op afstand moet de verbonden gebruikersaccount beheerdersrechten krijgen. \ No newline at end of file diff --git a/lang/proc/texts/elevation_pt.md b/lang/proc/texts/elevation_pt.md new file mode 100644 index 000000000..81ade317c --- /dev/null +++ b/lang/proc/texts/elevation_pt.md @@ -0,0 +1,11 @@ +## Elevação + +O processo de elevação de permissões é específico do sistema operativo. + +### Linux e macOS + +Qualquer comando elevado é executado com `sudo`. A senha opcional `sudo` é consultada via XPipe quando necessário. Tens a capacidade de ajustar o comportamento de elevação nas definições para controlar se queres introduzir a tua palavra-passe sempre que for necessária ou se a queres guardar em cache para a sessão atual. + +### Windows + +No Windows, não é possível elevar as permissões de um processo filho se o processo pai não estiver a ser executado com permissões elevadas também. Portanto, se o XPipe não for executado como administrador, não poderás utilizar qualquer elevação localmente. Para ligações remotas, a conta de utilizador ligada tem de ter privilégios de administrador. \ No newline at end of file diff --git a/lang/proc/texts/elevation_ru.md b/lang/proc/texts/elevation_ru.md new file mode 100644 index 000000000..6146383c6 --- /dev/null +++ b/lang/proc/texts/elevation_ru.md @@ -0,0 +1,11 @@ +## Elevation + +Процесс повышения прав доступа зависит от операционной системы. + +### Linux & macOS + +Любая команда с повышенными правами выполняется с `sudo`. Дополнительный пароль `sudo` при необходимости запрашивается через XPipe. В настройках у тебя есть возможность регулировать поведение возвышения, чтобы контролировать, хочешь ли ты вводить пароль каждый раз, когда он требуется, или же хочешь кэшировать его для текущей сессии. + +### Windows + +В Windows невозможно повысить права дочернего процесса, если родительский процесс не запущен с повышенными правами. Поэтому, если XPipe не запущен от имени администратора, ты не сможешь использовать повышение прав локально. Для удаленных подключений подключаемая учетная запись пользователя должна иметь права администратора. \ No newline at end of file diff --git a/lang/proc/texts/elevation_tr.md b/lang/proc/texts/elevation_tr.md new file mode 100644 index 000000000..a34ea9c6c --- /dev/null +++ b/lang/proc/texts/elevation_tr.md @@ -0,0 +1,11 @@ +## Ykseklik + +?zinlerin ykseltilmesi sreci i?letim sistemine zgdr. + +### Linux ve macOS + +Herhangi bir ykseltilmi? komut `sudo` ile yrtlr. ?ste?e ba?l? `sudo` parolas? gerekti?inde XPipe arac?l???yla sorgulan?r. Parolan?za her ihtiya duyuldu?unda girmek isteyip istemedi?inizi veya mevcut oturum iin nbelle?e almak isteyip istemedi?inizi kontrol etmek iin ayarlarda ykseltme davran???n? ayarlama olana??na sahipsiniz. + +### Windows + +Windows'ta, st sre de ykseltilmi? izinlerle al??m?yorsa, bir alt srecin izinlerini ykseltmek mmkn de?ildir. Bu nedenle, XPipe ynetici olarak al??t?r?lmazsa, yerel olarak herhangi bir ykseltme kullanamazs?n?z. Uzak ba?lant?lar iin, ba?l? kullan?c? hesab?na ynetici ayr?cal?klar? verilmelidir. \ No newline at end of file diff --git a/lang/proc/texts/elevation_zh.md b/lang/proc/texts/elevation_zh.md new file mode 100644 index 000000000..44ce9cf72 --- /dev/null +++ b/lang/proc/texts/elevation_zh.md @@ -0,0 +1,11 @@ +## 升高 + +权限提升过程与操作系统有关。 + +### Linux 和 MacOS + +任何提升权限的命令都使用 `sudo` 执行。需要时,会通过 XPipe 查询可选的 `sudo` 密码。您可以在设置中调整提升行为,以控制是每次需要时都输入密码,还是为当前会话缓存密码。 + +### 窗口 + +在 Windows 中,如果父进程在运行时没有提升权限,则无法提升子进程的权限。因此,如果 XPipe 不是以管理员身份运行,就无法在本地使用任何权限提升功能。对于远程连接,所连接的用户账户必须具有管理员权限。 \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_de.md b/lang/proc/texts/environmentScript_de.md new file mode 100644 index 000000000..fd0e27226 --- /dev/null +++ b/lang/proc/texts/environmentScript_de.md @@ -0,0 +1,9 @@ +## Init-Skript + +Die optionalen Befehle, die ausgeführt werden, nachdem die Init-Dateien und -Profile der Shell ausgeführt worden sind. + +Du kannst dies wie ein normales Shell-Skript behandeln, d.h. du kannst die gesamte Syntax verwenden, die die Shell in Skripten unterstützt. Alle Befehle, die du ausführst, werden von der Shell übernommen und verändern die Umgebung. Wenn du also zum Beispiel eine Variable setzt, hast du in dieser Shell-Sitzung Zugriff auf diese Variable. + +### Blockierende Befehle + +Beachte, dass blockierende Befehle, die Benutzereingaben erfordern, den Shell-Prozess einfrieren können, wenn XPipe ihn zuerst intern im Hintergrund startet. Um dies zu vermeiden, rufe diese blockierenden Befehle nur auf, wenn die Variable `TERM` nicht auf `dumb` gesetzt ist. XPipe setzt die Variable `TERM=dumb` automatisch, wenn es die Shell-Sitzung im Hintergrund vorbereitet und setzt dann `TERM=xterm-256color`, wenn es das Terminal tatsächlich öffnet. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_en.md b/lang/proc/texts/environmentScript_en.md new file mode 100644 index 000000000..55fc836fb --- /dev/null +++ b/lang/proc/texts/environmentScript_en.md @@ -0,0 +1,9 @@ +## Init script + +The optional commands to run after the shell's init files and profiles have been executed. + +You can treat this as a normal shell script, i.e. make use of all the syntax that the shell supports in scripts. All commands you execute are sourced by the shell and modify the environment. So if you for example set a variable, you will have access to this variable in this shell session. + +### Blocking commands + +Note that blocking commands that require user input can freeze the shell process when XPipe starts it up internally first in the background. To avoid this, only call these blocking commands if the variable `TERM` is not set to `dumb`. XPipe automatically sets the variable `TERM=dumb` when it is preparing the shell session in the background and then sets `TERM=xterm-256color` when actually opening the terminal. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_es.md b/lang/proc/texts/environmentScript_es.md new file mode 100644 index 000000000..bf0fc0c5d --- /dev/null +++ b/lang/proc/texts/environmentScript_es.md @@ -0,0 +1,9 @@ +## Guión de inicio + +Los comandos opcionales que se ejecutarán después de que se hayan ejecutado los archivos y perfiles init del intérprete de comandos. + +Puedes tratarlo como un script de shell normal, es decir, hacer uso de toda la sintaxis que el shell admite en los scripts. Todos los comandos que ejecutes tienen su origen en el shell y modifican el entorno. Así que si, por ejemplo, estableces una variable, tendrás acceso a esta variable en esta sesión de shell. + +### Comandos de bloqueo + +Ten en cuenta que los comandos de bloqueo que requieren la entrada del usuario pueden congelar el proceso del shell cuando XPipe lo inicie internamente primero en segundo plano. Para evitarlo, sólo llama a estos comandos de bloqueo si la variable `TERM` no está establecida a `tonto`. XPipe establece automáticamente la variable `TERM=dumb` cuando prepara la sesión shell en segundo plano y luego establece `TERM=xterm-256color` cuando abre realmente el terminal. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_fr.md b/lang/proc/texts/environmentScript_fr.md new file mode 100644 index 000000000..119fd8174 --- /dev/null +++ b/lang/proc/texts/environmentScript_fr.md @@ -0,0 +1,9 @@ +## Script d'initialisation + +Les commandes facultatives à exécuter après que les fichiers et profils init de l'interpréteur de commandes ont été exécutés. + +Tu peux traiter ce script comme un script shell normal, c'est-à-dire utiliser toute la syntaxe que le shell prend en charge dans les scripts. Toutes les commandes que tu exécutes sont générées par l'interpréteur de commandes et modifient l'environnement. Ainsi, si tu définis par exemple une variable, tu auras accès à cette variable dans cette session de l'interpréteur de commandes. + +### Commandes bloquantes + +Note que les commandes de blocage qui nécessitent une entrée de la part de l'utilisateur peuvent geler le processus de l'interpréteur de commandes lorsque XPipe le démarre d'abord en interne en arrière-plan. Pour éviter cela, n'appelle ces commandes bloquantes que si la variable `TERM` n'est pas définie sur `dumb`. XPipe définit automatiquement la variable `TERM=dumb` lorsqu'il prépare la session shell en arrière-plan, puis définit `TERM=xterm-256color` lors de l'ouverture effective du terminal. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_it.md b/lang/proc/texts/environmentScript_it.md new file mode 100644 index 000000000..d1596585a --- /dev/null +++ b/lang/proc/texts/environmentScript_it.md @@ -0,0 +1,9 @@ +## Script di avvio + +I comandi opzionali da eseguire dopo l'esecuzione dei file e dei profili di init della shell. + +Puoi trattarlo come un normale script di shell, cioè utilizzare tutta la sintassi che la shell supporta negli script. Tutti i comandi che esegui sono originati dalla shell e modificano l'ambiente. Quindi, se ad esempio imposti una variabile, avrai accesso a questa variabile in questa sessione di shell. + +### Comandi bloccanti + +Nota che i comandi bloccanti che richiedono l'input dell'utente possono bloccare il processo di shell quando XPipe lo avvia internamente in background. Per evitare ciò, chiama questi comandi bloccanti solo se la variabile `TERM` non è impostata su `dumb`. XPipe imposta automaticamente la variabile `TERM=dumb` quando prepara la sessione di shell in background e poi imposta `TERM=xterm-256color` quando apre effettivamente il terminale. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_ja.md b/lang/proc/texts/environmentScript_ja.md new file mode 100644 index 000000000..27ff8b550 --- /dev/null +++ b/lang/proc/texts/environmentScript_ja.md @@ -0,0 +1,9 @@ +## イニシャルスクリプト + +シェルのinitファイルとプロファイルが実行された後に実行するオプションのコマンド。 + +これを通常のシェルスクリプトとして扱うことができる。つまり、シェルがスクリプトでサポートするすべての構文を利用することができる。実行するコマンドはすべてシェルがソースとなり、環境を変更する。例えば変数を設定すれば、このシェルセッションでその変数にアクセスできる。 + +### コマンドをブロックする + +ユーザー入力を必要とするブロックコマンドは、XPipeがバックグラウンドで最初に内部的に起動したときにシェルプロセスをフリーズさせる可能性があることに注意すること。これを避けるには、変数 `TERM` が `dumb` に設定されていない場合にのみ、これらのブロックコマンドを呼び出すこと。XPipeはバックグラウンドでシェルセッションを準備するときに自動的に変数`TERM=dumb`を設定し、実際にターミナルを開くときに`TERM=xterm-256color`を設定する。 \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_nl.md b/lang/proc/texts/environmentScript_nl.md new file mode 100644 index 000000000..632130767 --- /dev/null +++ b/lang/proc/texts/environmentScript_nl.md @@ -0,0 +1,9 @@ +## Init script + +De optionele commando's om uit te voeren nadat de init bestanden en profielen van de shell zijn uitgevoerd. + +Je kunt dit behandelen als een normaal shellscript, dus gebruik maken van alle syntaxis die de shell ondersteunt in scripts. Alle commando's die je uitvoert zijn afkomstig van de shell en wijzigen de omgeving. Dus als je bijvoorbeeld een variabele instelt, heb je toegang tot deze variabele in deze shellsessie. + +### Blokkerende commando's + +Merk op dat blokkeringscommando's die gebruikersinvoer vereisen het shell proces kunnen bevriezen als XPipe het eerst intern op de achtergrond opstart. Om dit te voorkomen, roep je deze blokkerende commando's alleen aan als de variabele `TERM` niet is ingesteld op `dumb`. XPipe stelt automatisch de variabele `TERM=dumb` in wanneer het de shellsessie op de achtergrond voorbereidt en stelt vervolgens `TERM=xterm-256color` in wanneer het daadwerkelijk de terminal opent. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_pt.md b/lang/proc/texts/environmentScript_pt.md new file mode 100644 index 000000000..a48129b1d --- /dev/null +++ b/lang/proc/texts/environmentScript_pt.md @@ -0,0 +1,9 @@ +## Script de inicialização + +Os comandos opcionais a serem executados após os arquivos e perfis de inicialização do shell terem sido executados. + +Podes tratar isto como um script de shell normal, i.e. fazer uso de toda a sintaxe que a shell suporta em scripts. Todos os comandos que executas são originados pela shell e modificam o ambiente. Assim, se por exemplo definires uma variável, terás acesso a esta variável nesta sessão da shell. + +### Comandos de bloqueio + +Nota que os comandos de bloqueio que requerem a entrada do utilizador podem congelar o processo da shell quando o XPipe o inicia internamente primeiro em segundo plano. Para evitar isso, só chama esses comandos de bloqueio se a variável `TERM` não estiver definida como `dumb`. O XPipe define automaticamente a variável `TERM=dumb` quando está preparando a sessão do shell em segundo plano e, em seguida, define `TERM=xterm-256color` quando realmente abre o terminal. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_ru.md b/lang/proc/texts/environmentScript_ru.md new file mode 100644 index 000000000..4ba629047 --- /dev/null +++ b/lang/proc/texts/environmentScript_ru.md @@ -0,0 +1,9 @@ +## Начальный скрипт + +Необязательные команды, которые нужно запустить после выполнения инит-файлов и профилей оболочки. + +Ты можешь относиться к этому как к обычному скрипту оболочки, то есть использовать весь синтаксис, который оболочка поддерживает в скриптах. Все команды, которые ты выполняешь, исходят от оболочки и изменяют окружение. Так что если ты, например, установишь переменную, то будешь иметь доступ к ней в этой сессии оболочки. + +### Блокирующие команды + +Обрати внимание, что блокирующие команды, требующие пользовательского ввода, могут заморозить процесс оболочки, когда XPipe запустит его сначала внутри, а затем в фоновом режиме. Чтобы избежать этого, вызывай эти блокирующие команды только в том случае, если переменная `TERM` не установлена в `dumb`. XPipe автоматически устанавливает переменную `TERM=dumb` при подготовке сеанса оболочки в фоновом режиме, а затем устанавливает `TERM=xterm-256color` при фактическом открытии терминала. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_tr.md b/lang/proc/texts/environmentScript_tr.md new file mode 100644 index 000000000..e6fa5aec0 --- /dev/null +++ b/lang/proc/texts/environmentScript_tr.md @@ -0,0 +1,9 @@ +## Ba?lang? beti?i + +Kabu?un ba?lang? dosyalar? ve profilleri yrtldkten sonra al??t?r?lacak iste?e ba?l? komutlar. + +Buna normal bir kabuk beti?i gibi davranabilirsiniz, yani kabu?un betiklerde destekledi?i tm szdizimini kullanabilirsiniz. al??t?rd???n?z tm komutlar kabuk taraf?ndan kaynaklan?r ve ortam? de?i?tirir. Dolay?s?yla, rne?in bir de?i?ken ayarlarsan?z, bu kabuk oturumunda bu de?i?kene eri?iminiz olacakt?r. + +### Engelleme komutlar? + +Kullan?c? giri?i gerektiren engelleme komutlar?n?n, XPipe arka planda ilk olarak dahili olarak ba?lat?ld???nda kabuk srecini dondurabilece?ini unutmay?n. Bunu nlemek iin, bu engelleme komutlar?n? yaln?zca `TERM` de?i?keni `dumb` olarak ayarlanmam??sa a??r?n. XPipe arka planda kabuk oturumunu haz?rlarken `TERM=dumb` de?i?kenini otomatik olarak ayarlar ve daha sonra terminali gerekten aarken `TERM=xterm-256color` de?i?kenini ayarlar. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_zh.md b/lang/proc/texts/environmentScript_zh.md new file mode 100644 index 000000000..db2cee49a --- /dev/null +++ b/lang/proc/texts/environmentScript_zh.md @@ -0,0 +1,9 @@ +## 初始脚本 + +在执行 shell 的初始文件和配置文件后运行的可选命令。 + +你可以将其视为普通的 shell 脚本,即使用 shell 在脚本中支持的所有语法。你执行的所有命令都会被 shell 源化并修改环境。因此,如果你设置了一个变量,你就可以在这个 shell 会话中访问这个变量。 + +### 阻止命令 + +请注意,当 XPipe 首先在后台内部启动 shell 进程时,需要用户输入的阻塞命令可能会冻结 shell 进程。为避免这种情况,只有当变量 `TERM` 未设置为 `dumb` 时,才调用这些阻塞命令。XPipe 在后台准备 shell 会话时会自动设置变量 `TERM=dumb` ,然后在实际打开终端时设置 `TERM=xterm-256color` 。 \ No newline at end of file diff --git a/lang/proc/texts/proxmoxPassword_de.md b/lang/proc/texts/proxmoxPassword_de.md new file mode 100644 index 000000000..c6a0d68f8 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_de.md @@ -0,0 +1,3 @@ +## Passwort + +Wenn du auf deiner VM eine komplexere SSH-Authentifizierung als ein einfaches Passwort verwendest, kannst du das System einfach als normale SSH-Verbindung in XPipe hinzufügen. Wenn es von außen nicht zugänglich ist, kannst du das übergeordnete PVE-System als SSH-Gateway einrichten. diff --git a/lang/proc/texts/proxmoxPassword_en.md b/lang/proc/texts/proxmoxPassword_en.md new file mode 100644 index 000000000..871a63849 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_en.md @@ -0,0 +1,3 @@ +## Password + +If you are using a more complex SSH authentication on your VM rather than a simple password, you can just add the system as a normal SSH connection in XPipe. If it is not accessible from the outside, you can set the parent PVE system as an SSH gateway. diff --git a/lang/proc/texts/proxmoxPassword_es.md b/lang/proc/texts/proxmoxPassword_es.md new file mode 100644 index 000000000..a52ffae05 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_es.md @@ -0,0 +1,3 @@ +## Contraseña + +Si utilizas una autenticación SSH más compleja en tu máquina virtual en lugar de una simple contraseña, puedes añadir el sistema como una conexión SSH normal en XPipe. Si no es accesible desde el exterior, puedes configurar el sistema PVE padre como pasarela SSH. diff --git a/lang/proc/texts/proxmoxPassword_fr.md b/lang/proc/texts/proxmoxPassword_fr.md new file mode 100644 index 000000000..22aa59950 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_fr.md @@ -0,0 +1,3 @@ +## Mot de passe + +Si tu utilises une authentification SSH plus complexe sur ta VM plutôt qu'un simple mot de passe, tu peux simplement ajouter le système comme une connexion SSH normale dans XPipe. S'il n'est pas accessible de l'extérieur, tu peux définir le système PVE parent comme une passerelle SSH. diff --git a/lang/proc/texts/proxmoxPassword_it.md b/lang/proc/texts/proxmoxPassword_it.md new file mode 100644 index 000000000..54c95ced2 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_it.md @@ -0,0 +1,3 @@ +## Password + +Se stai utilizzando un'autenticazione SSH più complessa sulla tua VM piuttosto che una semplice password, puoi aggiungere il sistema come una normale connessione SSH in XPipe. Se non è accessibile dall'esterno, puoi impostare il sistema PVE principale come gateway SSH. diff --git a/lang/proc/texts/proxmoxPassword_ja.md b/lang/proc/texts/proxmoxPassword_ja.md new file mode 100644 index 000000000..9e318f4bb --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_ja.md @@ -0,0 +1,3 @@ +## パスワード + +単純なパスワードではなく、より複雑なSSH認証をVMで使用する場合は、XPipeでシステムを通常のSSH接続として追加すればよい。外部からアクセスできない場合は、親PVEシステムをSSHゲートウェイとして設定できる。 diff --git a/lang/proc/texts/proxmoxPassword_nl.md b/lang/proc/texts/proxmoxPassword_nl.md new file mode 100644 index 000000000..189aeabd1 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_nl.md @@ -0,0 +1,3 @@ +## Wachtwoord + +Als je een complexere SSH-authenticatie gebruikt op je VM in plaats van een eenvoudig wachtwoord, kun je het systeem gewoon toevoegen als een normale SSH-verbinding in XPipe. Als het niet van buitenaf toegankelijk is, kun je het ouder PVE systeem instellen als een SSH gateway. diff --git a/lang/proc/texts/proxmoxPassword_pt.md b/lang/proc/texts/proxmoxPassword_pt.md new file mode 100644 index 000000000..450d9d7df --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_pt.md @@ -0,0 +1,3 @@ +## Senha + +Se estiveres a usar uma autenticação SSH mais complexa na tua VM em vez de uma simples senha, podes simplesmente adicionar o sistema como uma conexão SSH normal no XPipe. Se não é acessível a partir do exterior, podes definir o sistema PVE pai como um gateway SSH. diff --git a/lang/proc/texts/proxmoxPassword_ru.md b/lang/proc/texts/proxmoxPassword_ru.md new file mode 100644 index 000000000..eba944ef4 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_ru.md @@ -0,0 +1,3 @@ +## Пароль + +Если ты используешь на своей ВМ более сложную SSH-аутентификацию, а не простой пароль, ты можешь просто добавить систему как обычное SSH-соединение в XPipe. Если она недоступна извне, ты можешь установить родительскую PVE-систему в качестве SSH-шлюза. diff --git a/lang/proc/texts/proxmoxPassword_tr.md b/lang/proc/texts/proxmoxPassword_tr.md new file mode 100644 index 000000000..656cc28f4 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_tr.md @@ -0,0 +1,3 @@ +## ?ifre + +Sanal makinenizde basit bir parola yerine daha karma??k bir SSH kimlik do?rulamas? kullan?yorsan?z, sistemi XPipe'a normal bir SSH ba?lant?s? olarak ekleyebilirsiniz. D??ar?dan eri?ilemiyorsa, ana PVE sistemini bir SSH a? geidi olarak ayarlayabilirsiniz. diff --git a/lang/proc/texts/proxmoxPassword_zh.md b/lang/proc/texts/proxmoxPassword_zh.md new file mode 100644 index 000000000..028572db1 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_zh.md @@ -0,0 +1,3 @@ +## 密码 + +如果您在虚拟机上使用的是更复杂的 SSH 验证而非简单的密码,您只需在 XPipe 中将系统添加为普通 SSH 连接即可。如果无法从外部访问,可以将父 PVE 系统设置为 SSH 网关。 diff --git a/lang/proc/texts/proxmoxUsername_de.md b/lang/proc/texts/proxmoxUsername_de.md new file mode 100644 index 000000000..2c65d8a86 --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_de.md @@ -0,0 +1,5 @@ +## Benutzername + +Der Benutzername, mit dem du dich anmeldest. XPipe versucht, sich über SSH mit den angegebenen Anmeldedaten zu verbinden. + +Wenn kein SSH-Server läuft, wird versucht, den installierten SSH-Server zu starten. Beachte, dass du dieses Verhalten im Menü Sicherheitseinstellungen deaktivieren kannst. diff --git a/lang/proc/texts/proxmoxUsername_en.md b/lang/proc/texts/proxmoxUsername_en.md new file mode 100644 index 000000000..e3bbed86a --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_en.md @@ -0,0 +1,5 @@ +## Username + +The username to log in as. XPipe will attempt to connect via SSH using the provided credentials. + +If no SSH server is running it will attempt to start the installed SSH server. Note that you can disable this behavior in the security settings menu. diff --git a/lang/proc/texts/proxmoxUsername_es.md b/lang/proc/texts/proxmoxUsername_es.md new file mode 100644 index 000000000..72155eed9 --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_es.md @@ -0,0 +1,5 @@ +## Nombre de usuario + +El nombre de usuario con el que iniciar sesión. XPipe intentará conectarse vía SSH utilizando las credenciales proporcionadas. + +Si no hay ningún servidor SSH en ejecución, intentará iniciar el servidor SSH instalado. Ten en cuenta que puedes desactivar este comportamiento en el menú de configuración de seguridad. diff --git a/lang/proc/texts/proxmoxUsername_fr.md b/lang/proc/texts/proxmoxUsername_fr.md new file mode 100644 index 000000000..664982e6d --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_fr.md @@ -0,0 +1,5 @@ +## Nom d'utilisateur + +Le nom d'utilisateur sous lequel se connecter. XPipe tentera de se connecter via SSH en utilisant les informations d'identification fournies. + +Si aucun serveur SSH n'est en cours d'exécution, il tentera de démarrer le serveur SSH installé. Note que tu peux désactiver ce comportement dans le menu des paramètres de sécurité. diff --git a/lang/proc/texts/proxmoxUsername_it.md b/lang/proc/texts/proxmoxUsername_it.md new file mode 100644 index 000000000..63dd60aae --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_it.md @@ -0,0 +1,5 @@ +## Nome utente + +Il nome utente con cui accedere. XPipe tenterà di connettersi via SSH utilizzando le credenziali fornite. + +Se non è in esecuzione alcun server SSH, tenterà di avviare il server SSH installato. È possibile disabilitare questo comportamento nel menu delle impostazioni di sicurezza. diff --git a/lang/proc/texts/proxmoxUsername_ja.md b/lang/proc/texts/proxmoxUsername_ja.md new file mode 100644 index 000000000..26ccd9bf6 --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_ja.md @@ -0,0 +1,5 @@ +## ユーザー名 + +ログインするユーザー名。XPipe は与えられた認証情報を使って SSH 接続を試みる。 + +SSHサーバーが起動していない場合は、インストールされているSSHサーバーを起動しようとする。セキュリティ設定メニューでこの動作を無効にすることができる。 diff --git a/lang/proc/texts/proxmoxUsername_nl.md b/lang/proc/texts/proxmoxUsername_nl.md new file mode 100644 index 000000000..d1d4c39f0 --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_nl.md @@ -0,0 +1,5 @@ +## Gebruikersnaam + +De gebruikersnaam om mee in te loggen. XPipe zal proberen verbinding te maken via SSH met de opgegeven gegevens. + +Als er geen SSH-server draait, wordt geprobeerd de geïnstalleerde SSH-server te starten. Merk op dat je dit gedrag kunt uitschakelen in het menu Beveiligingsinstellingen. diff --git a/lang/proc/texts/proxmoxUsername_pt.md b/lang/proc/texts/proxmoxUsername_pt.md new file mode 100644 index 000000000..97f35d80b --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_pt.md @@ -0,0 +1,5 @@ +## Nome de utilizador + +O nome de utilizador para iniciar sessão. XPipe tentará conectar-se via SSH usando as credenciais fornecidas. + +Se nenhum servidor SSH estiver em execução, tenta iniciar o servidor SSH instalado. Nota que podes desativar este comportamento no menu de definições de segurança. diff --git a/lang/proc/texts/proxmoxUsername_ru.md b/lang/proc/texts/proxmoxUsername_ru.md new file mode 100644 index 000000000..96cfb5658 --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_ru.md @@ -0,0 +1,5 @@ +## Имя пользователя + +Имя пользователя, под которым нужно войти в систему. XPipe попытается подключиться по SSH, используя предоставленные учетные данные. + +Если SSH-сервер не запущен, он попытается запустить установленный SSH-сервер. Обрати внимание, что ты можешь отключить это поведение в меню настроек безопасности. diff --git a/lang/proc/texts/proxmoxUsername_tr.md b/lang/proc/texts/proxmoxUsername_tr.md new file mode 100644 index 000000000..e62659a7c --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_tr.md @@ -0,0 +1,5 @@ +## Kullan?c? ad? + +Oturum a?lacak kullan?c? ad?. XPipe, sa?lanan kimlik bilgilerini kullanarak SSH zerinden ba?lanmay? deneyecektir. + +E?er hibir SSH sunucusu al??m?yorsa, kurulu SSH sunucusunu ba?latmay? deneyecektir. Bu davran??? gvenlik ayarlar? mensnden devre d??? b?rakabilece?inizi unutmay?n. diff --git a/lang/proc/texts/proxmoxUsername_zh.md b/lang/proc/texts/proxmoxUsername_zh.md new file mode 100644 index 000000000..07ff26bdb --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_zh.md @@ -0,0 +1,5 @@ +## 用户名 + +要登录的用户名。XPipe 将尝试使用所提供的凭据通过 SSH 进行连接。 + +如果没有运行 SSH 服务器,它将尝试启动已安装的 SSH 服务器。请注意,您可以在安全设置菜单中禁用这一行为。 diff --git a/lang/proc/texts/rdpPasswordAuthentication_de.md b/lang/proc/texts/rdpPasswordAuthentication_de.md new file mode 100644 index 000000000..4123eb7a2 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_de.md @@ -0,0 +1,3 @@ +## RDP Passwort-Authentifizierung + +Nicht jeder verfügbare RDP-Client unterstützt die automatische Bereitstellung von Passwörtern. Wenn dein derzeit ausgewählter Client diese Funktion nicht unterstützt, musst du das Passwort bei der Verbindung trotzdem manuell eingeben. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_en.md b/lang/proc/texts/rdpPasswordAuthentication_en.md new file mode 100644 index 000000000..dc0a52e0a --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_en.md @@ -0,0 +1,3 @@ +## RDP Password Authentication + +Not every available RDP client supports automatically supplying passwords. If your currently selected client does not support this feature, you will still have to enter the password manually when connecting. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_es.md b/lang/proc/texts/rdpPasswordAuthentication_es.md new file mode 100644 index 000000000..3c798f4a8 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_es.md @@ -0,0 +1,3 @@ +## Autenticación por contraseña RDP + +No todos los clientes RDP disponibles admiten el suministro automático de contraseñas. Si el cliente que has seleccionado no admite esta función, tendrás que introducir la contraseña manualmente al conectarte. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_fr.md b/lang/proc/texts/rdpPasswordAuthentication_fr.md new file mode 100644 index 000000000..cc9ee01b9 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_fr.md @@ -0,0 +1,3 @@ +## Authentification par mot de passe RDP + +Tous les clients RDP disponibles ne prennent pas en charge la fourniture automatique de mots de passe. Si le client que tu as sélectionné ne prend pas en charge cette fonction, tu devras toujours saisir le mot de passe manuellement lors de la connexion. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_it.md b/lang/proc/texts/rdpPasswordAuthentication_it.md new file mode 100644 index 000000000..120dae31f --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_it.md @@ -0,0 +1,3 @@ +## Autenticazione RDP con password + +Non tutti i client RDP disponibili supportano l'inserimento automatico della password. Se il client selezionato non supporta questa funzione, dovrai comunque inserire la password manualmente al momento della connessione. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_ja.md b/lang/proc/texts/rdpPasswordAuthentication_ja.md new file mode 100644 index 000000000..64b80c82b --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_ja.md @@ -0,0 +1,3 @@ +## RDPパスワード認証 + +すべてのRDPクライアントがパスワードの自動入力に対応しているわけではない。現在選択されているクライアントがこの機能をサポートしていない場合、 接続時にパスワードを手動で入力する必要がある。 \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_nl.md b/lang/proc/texts/rdpPasswordAuthentication_nl.md new file mode 100644 index 000000000..4e6b76b24 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_nl.md @@ -0,0 +1,3 @@ +## RDP wachtwoordverificatie + +Niet elke beschikbare RDP client ondersteunt het automatisch verstrekken van wachtwoorden. Als de momenteel geselecteerde client deze functie niet ondersteunt, moet je het wachtwoord nog steeds handmatig invoeren als je verbinding maakt. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_pt.md b/lang/proc/texts/rdpPasswordAuthentication_pt.md new file mode 100644 index 000000000..2d9552fd8 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_pt.md @@ -0,0 +1,3 @@ +## Autenticação de palavra-passe RDP + +Nem todos os clientes RDP disponíveis suportam o fornecimento automático de palavras-passe. Se o cliente atualmente selecionado não suportar esta funcionalidade, terás de introduzir a palavra-passe manualmente quando te ligares. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_ru.md b/lang/proc/texts/rdpPasswordAuthentication_ru.md new file mode 100644 index 000000000..edc5830c9 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_ru.md @@ -0,0 +1,3 @@ +## Аутентификация пароля RDP + +Не все доступные RDP-клиенты поддерживают автоматическое предоставление паролей. Если выбранный тобой клиент не поддерживает эту функцию, то при подключении тебе все равно придется вводить пароль вручную. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_tr.md b/lang/proc/texts/rdpPasswordAuthentication_tr.md new file mode 100644 index 000000000..673f8c98a --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_tr.md @@ -0,0 +1,3 @@ +## RDP Parola Kimlik Do?rulamas? + +Mevcut her RDP istemcisi otomatik olarak parola sa?lamay? desteklemez. Seili istemciniz bu zelli?i desteklemiyorsa, ba?lan?rken parolay? manuel olarak girmeniz gerekecektir. \ No newline at end of file diff --git a/lang/proc/texts/rdpPasswordAuthentication_zh.md b/lang/proc/texts/rdpPasswordAuthentication_zh.md new file mode 100644 index 000000000..054cd474b --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_zh.md @@ -0,0 +1,3 @@ +## RDP 密码验证 + +并非每个可用的 RDP 客户端都支持自动提供密码。如果您当前选择的客户端不支持此功能,您仍需在连接时手动输入密码。 \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_de.md b/lang/proc/texts/rdpTunnelHost_de.md new file mode 100644 index 000000000..b879dbb7c --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_de.md @@ -0,0 +1,5 @@ +## RDP Tunnel Host + +Du kannst dich mit einem entfernten RDP-Host über einen SSH-Tunnel verbinden. Dadurch kannst du die fortgeschrittenen SSH-Authentifizierungsfunktionen mit RDP sofort nutzen. + +Wenn du diese Option wählst, wird die Hostadresse in der RDP-Datei durch den gewählten Hostnamen der SSH-Verbindung ersetzt. Bei der ersten Verbindung wird ein SSH-Tunnel aufgebaut und der RDP-Client verbindet sich stattdessen über localhost mit der getunnelten Verbindung. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_en.md b/lang/proc/texts/rdpTunnelHost_en.md new file mode 100644 index 000000000..ac56ca932 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_en.md @@ -0,0 +1,5 @@ +## RDP Tunnel Host + +You can choose to connect to a remote RDP host via an SSH tunnel. This gives you the ability to use the more advanced SSH authentication features with RDP out of the box. + +When this option is used, the host address in the RDP file will be replaced by the chosen hostname of the SSH connection. Upon first connection, an SSH tunnel will be established and the RDP client will connect to the tunneled connection via localhost instead. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_es.md b/lang/proc/texts/rdpTunnelHost_es.md new file mode 100644 index 000000000..88dddc981 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_es.md @@ -0,0 +1,5 @@ +## Anfitrión del Túnel RDP + +Puedes elegir conectarte a un host RDP remoto a través de un túnel SSH. Esto te permite utilizar las funciones más avanzadas de autenticación SSH con RDP de forma inmediata. + +Cuando se utiliza esta opción, la dirección del host en el archivo RDP se sustituirá por el nombre de host elegido de la conexión SSH. En la primera conexión, se establecerá un túnel SSH y el cliente RDP se conectará a la conexión tunelizada a través de localhost en su lugar. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_fr.md b/lang/proc/texts/rdpTunnelHost_fr.md new file mode 100644 index 000000000..112f6674b --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_fr.md @@ -0,0 +1,5 @@ +## Hôte du tunnel RDP + +Tu peux choisir de te connecter à un hôte RDP distant via un tunnel SSH. Cela te permet d'utiliser les fonctions d'authentification SSH les plus avancées avec RDP. + +Lorsque cette option est utilisée, l'adresse de l'hôte dans le fichier RDP sera remplacée par le nom d'hôte choisi pour la connexion SSH. Lors de la première connexion, un tunnel SSH sera établi et le client RDP se connectera à la connexion via localhost. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_it.md b/lang/proc/texts/rdpTunnelHost_it.md new file mode 100644 index 000000000..495976ea7 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_it.md @@ -0,0 +1,5 @@ +## Host del tunnel RDP + +Puoi scegliere di connetterti a un host RDP remoto tramite un tunnel SSH. Questo ti permette di utilizzare le funzioni di autenticazione SSH più avanzate con RDP. + +Quando si utilizza questa opzione, l'indirizzo dell'host nel file RDP sarà sostituito dal nome dell'host scelto per la connessione SSH. Alla prima connessione, verrà creato un tunnel SSH e il client RDP si connetterà alla connessione tramite localhost. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_ja.md b/lang/proc/texts/rdpTunnelHost_ja.md new file mode 100644 index 000000000..60f702036 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_ja.md @@ -0,0 +1,5 @@ +## RDPトンネルホスト + +SSHトンネル経由でリモートのRDPホストに接続することができる。これにより、RDPでより高度なSSH認証機能をそのまま使うことができる。 + +このオプションを使用すると、RDPファイル内のホストアドレスが、選択したSSH接続のホスト名に置き換えられる。最初の接続時にSSHトンネルが確立され、RDPクライアントは代わりにlocalhost経由でトンネル接続に接続する。 \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_nl.md b/lang/proc/texts/rdpTunnelHost_nl.md new file mode 100644 index 000000000..4bbe3aecf --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_nl.md @@ -0,0 +1,5 @@ +## RDP-tunnel host + +Je kunt ervoor kiezen om verbinding te maken met een RDP host op afstand via een SSH tunnel. Dit geeft je de mogelijkheid om de meer geavanceerde SSH authenticatie mogelijkheden met RDP out of the box te gebruiken. + +Wanneer deze optie wordt gebruikt, wordt het hostadres in het RDP bestand vervangen door de gekozen hostnaam van de SSH verbinding. Bij de eerste verbinding zal er een SSH tunnel worden gemaakt en de RDP client zal in plaats daarvan verbinding maken met de getunnelde verbinding via localhost. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_pt.md b/lang/proc/texts/rdpTunnelHost_pt.md new file mode 100644 index 000000000..0b9847677 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_pt.md @@ -0,0 +1,5 @@ +## Anfitrião do túnel RDP + +Podes optar por te ligares a um anfitrião RDP remoto através de um túnel SSH. Isto dá-te a capacidade de usar as funcionalidades mais avançadas de autenticação SSH com o RDP fora da caixa. + +Quando esta opção é usada, o endereço do host no arquivo RDP será substituído pelo nome do host escolhido para a conexão SSH. Na primeira conexão, um túnel SSH será estabelecido e o cliente RDP se conectará à conexão com túnel via localhost. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_ru.md b/lang/proc/texts/rdpTunnelHost_ru.md new file mode 100644 index 000000000..b0dd3f2e0 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_ru.md @@ -0,0 +1,5 @@ +## RDP Tunnel Host + +Ты можешь выбрать подключение к удаленному RDP-хосту через SSH-туннель. Это даст тебе возможность использовать более продвинутые функции аутентификации SSH в RDP из коробки. + +При использовании этой опции адрес хоста в файле RDP будет заменен на выбранное имя хоста SSH-соединения. При первом подключении будет создан SSH-туннель, и RDP-клиент будет подключаться к туннелированному соединению через localhost вместо него. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_tr.md b/lang/proc/texts/rdpTunnelHost_tr.md new file mode 100644 index 000000000..9d2224571 --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_tr.md @@ -0,0 +1,5 @@ +## RDP Tnel Ana Bilgisayar? + +Uzak bir RDP ana bilgisayar?na bir SSH tneli zerinden ba?lanmay? seebilirsiniz. Bu size daha geli?mi? SSH kimlik do?rulama zelliklerini kutudan ?kar ?kmaz RDP ile kullanma olana?? verir. + +Bu seenek kullan?ld???nda, RDP dosyas?ndaki ana bilgisayar adresi SSH ba?lant?s?n?n seilen ana bilgisayar ad? ile de?i?tirilecektir. ?lk ba?lant?da bir SSH tneli kurulacak ve RDP istemcisi tnelli ba?lant?ya localhost zerinden ba?lanacakt?r. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_zh.md b/lang/proc/texts/rdpTunnelHost_zh.md new file mode 100644 index 000000000..29146dc1d --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_zh.md @@ -0,0 +1,5 @@ +## RDP 隧道主机 + +你可以选择通过 SSH 通道连接到远程 RDP 主机。这样就能在 RDP 中使用更高级的 SSH 身份验证功能。 + +使用该选项时,RDP 文件中的主机地址将被所选的 SSH 连接主机名取代。首次连接时,将建立 SSH 隧道,RDP 客户端将通过 localhost 连接到隧道连接。 \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_de.md b/lang/proc/texts/runTempContainer_de.md new file mode 100644 index 000000000..3673bba1c --- /dev/null +++ b/lang/proc/texts/runTempContainer_de.md @@ -0,0 +1,5 @@ +## Temporäre Container + +Hiermit wird ein temporärer Container mit dem angegebenen Image gestartet, der automatisch entfernt wird, sobald er gestoppt wird. Der Container läuft auch dann weiter, wenn im Container-Image kein Befehl angegeben ist, der ausgeführt werden soll. + +Das kann nützlich sein, wenn du schnell eine bestimmte Umgebung mit einem bestimmten Container-Image einrichten willst. Du kannst den Container dann wie gewohnt in XPipe betreten, deine Operationen durchführen und den Container stoppen, sobald er nicht mehr benötigt wird. Er wird dann automatisch entfernt. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_en.md b/lang/proc/texts/runTempContainer_en.md new file mode 100644 index 000000000..52dc0a62f --- /dev/null +++ b/lang/proc/texts/runTempContainer_en.md @@ -0,0 +1,5 @@ +## Temporary containers + +This will run a temporary container using the specified image that will get automatically removed once it is stopped. The container will keep running even if the container image does not have any command specified that will run. + +This can be useful if you quickly want to set up a certain environment by using a certain container image. You can then enter the container as normal in XPipe, perform your operations, and stop the container once it's no longer needed. It is then removed automatically. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_es.md b/lang/proc/texts/runTempContainer_es.md new file mode 100644 index 000000000..e1d016c8f --- /dev/null +++ b/lang/proc/texts/runTempContainer_es.md @@ -0,0 +1,5 @@ +## Contenedores temporales + +Esto ejecutará un contenedor temporal utilizando la imagen especificada que se eliminará automáticamente cuando se detenga. El contenedor seguirá ejecutándose aunque la imagen del contenedor no tenga ningún comando especificado que se vaya a ejecutar. + +Esto puede ser útil si quieres configurar rápidamente un determinado entorno utilizando una determinada imagen de contenedor. A continuación, puedes entrar en el contenedor de forma normal en XPipe, realizar tus operaciones y detener el contenedor cuando ya no sea necesario. Entonces se elimina automáticamente. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_fr.md b/lang/proc/texts/runTempContainer_fr.md new file mode 100644 index 000000000..eba564912 --- /dev/null +++ b/lang/proc/texts/runTempContainer_fr.md @@ -0,0 +1,5 @@ +## Conteneurs temporaires + +Cette commande lance un conteneur temporaire à l'aide de l'image spécifiée, qui sera automatiquement supprimé une fois arrêté. Le conteneur continuera à fonctionner même si l'image du conteneur n'a pas de commande spécifiée qui s'exécutera. + +Cela peut être utile si tu veux rapidement mettre en place un certain environnement en utilisant une certaine image de conteneur. Tu peux alors entrer dans le conteneur comme d'habitude dans XPipe, effectuer tes opérations, et arrêter le conteneur une fois qu'il n'est plus nécessaire. Il est alors supprimé automatiquement. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_it.md b/lang/proc/texts/runTempContainer_it.md new file mode 100644 index 000000000..633efe949 --- /dev/null +++ b/lang/proc/texts/runTempContainer_it.md @@ -0,0 +1,5 @@ +## Contenitori temporanei + +Esegue un contenitore temporaneo utilizzando l'immagine specificata che verrà rimosso automaticamente una volta arrestato. Il contenitore continuerà a essere eseguito anche se l'immagine del contenitore non contiene alcun comando da eseguire. + +Questo può essere utile se vuoi configurare rapidamente un certo ambiente utilizzando una certa immagine del contenitore. Puoi quindi entrare nel contenitore come di consueto in XPipe, eseguire le tue operazioni e arrestare il contenitore quando non è più necessario. In questo modo verrà rimosso automaticamente. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_ja.md b/lang/proc/texts/runTempContainer_ja.md new file mode 100644 index 000000000..eed5a0592 --- /dev/null +++ b/lang/proc/texts/runTempContainer_ja.md @@ -0,0 +1,5 @@ +## 一時的なコンテナ + +指定したイメージを使って一時的なコンテナを実行し、停止すると自動的に削除される。コンテナイメージに実行するコマンドが指定されていなくても、コンテナは実行され続ける。 + +これは、特定のコンテナ・イメージを使って特定の環境を素早くセットアップしたい場合に便利である。その後、XPipeで通常通りコンテナに入り、操作を実行し、不要になったらコンテナを停止することができる。コンテナは自動的に削除される。 \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_nl.md b/lang/proc/texts/runTempContainer_nl.md new file mode 100644 index 000000000..321912fbd --- /dev/null +++ b/lang/proc/texts/runTempContainer_nl.md @@ -0,0 +1,5 @@ +## Tijdelijke containers + +Hiermee wordt een tijdelijke container gestart met de gespecificeerde image die automatisch wordt verwijderd zodra hij wordt gestopt. De container blijft draaien, zelfs als de container image geen commando heeft dat wordt uitgevoerd. + +Dit kan handig zijn als je snel een bepaalde omgeving wilt opzetten door een bepaalde container image te gebruiken. Je kunt dan de container zoals normaal in XPipe binnengaan, je bewerkingen uitvoeren en de container stoppen zodra hij niet meer nodig is. Hij wordt dan automatisch verwijderd. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_pt.md b/lang/proc/texts/runTempContainer_pt.md new file mode 100644 index 000000000..fb957d86c --- /dev/null +++ b/lang/proc/texts/runTempContainer_pt.md @@ -0,0 +1,5 @@ +## Contentores temporários + +Executa um contêiner temporário usando a imagem especificada que será removida automaticamente quando for interrompida. O container continuará rodando mesmo que a imagem do container não tenha nenhum comando especificado que será executado. + +Isto pode ser útil se quiseres configurar rapidamente um determinado ambiente utilizando uma determinada imagem de contentor. Podes então entrar no contentor normalmente no XPipe, efetuar as tuas operações e parar o contentor quando já não for necessário. Em seguida, remove-o automaticamente. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_ru.md b/lang/proc/texts/runTempContainer_ru.md new file mode 100644 index 000000000..e427e347e --- /dev/null +++ b/lang/proc/texts/runTempContainer_ru.md @@ -0,0 +1,5 @@ +## Временные контейнеры + +Эта команда запустит временный контейнер с указанным образом, который будет автоматически удален после его остановки. Контейнер продолжит работать, даже если в образе контейнера не будет указано ни одной команды, которая бы выполнялась. + +Это может быть полезно, если ты хочешь быстро настроить определенное окружение, используя определенный образ контейнера. Тогда ты можешь войти в контейнер как обычно в XPipe, выполнить свои операции и остановить контейнер, когда он больше не нужен. Тогда он будет удален автоматически. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_tr.md b/lang/proc/texts/runTempContainer_tr.md new file mode 100644 index 000000000..7c8dca88a --- /dev/null +++ b/lang/proc/texts/runTempContainer_tr.md @@ -0,0 +1,5 @@ +## Geici konteynerler + +Bu, durduruldu?unda otomatik olarak kald?r?lacak olan belirtilen imaj? kullanarak geici bir konteyner al??t?racakt?r. Konteyner imaj?nda al??acak herhangi bir komut belirtilmemi? olsa bile konteyner al??maya devam edecektir. + +Bu, belirli bir konteyner imaj?n? kullanarak belirli bir ortam? h?zl? bir ?ekilde kurmak istedi?inizde yararl? olabilir. Daha sonra XPipe'da konteynere normal ?ekilde girebilir, i?lemlerinizi gerekle?tirebilir ve art?k ihtiya duyulmad???nda konteyneri durdurabilirsiniz. Daha sonra otomatik olarak kald?r?l?r. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_zh.md b/lang/proc/texts/runTempContainer_zh.md new file mode 100644 index 000000000..14fb28f5e --- /dev/null +++ b/lang/proc/texts/runTempContainer_zh.md @@ -0,0 +1,5 @@ +## 临时容器 + +这将使用指定的映像运行一个临时容器,一旦停止,该容器将自动移除。即使容器映像中没有指定要运行的命令,容器也会继续运行。 + +如果您想使用某个容器映像快速设置某个环境,这将非常有用。然后,您可以像在 XPipe 中一样正常进入容器,执行您的操作,并在不再需要时停止容器。容器会自动移除。 \ No newline at end of file diff --git a/lang/proc/texts/shellCommand_de.md b/lang/proc/texts/shellCommand_de.md new file mode 100644 index 000000000..eed4ef211 --- /dev/null +++ b/lang/proc/texts/shellCommand_de.md @@ -0,0 +1,30 @@ +## Benutzerdefinierte Shell-Verbindungen + +Öffnet eine Shell mit dem benutzerdefinierten Befehl, indem es den angegebenen Befehl auf dem ausgewählten Hostsystem ausführt. Diese Shell kann entweder lokal oder remote sein. + +Beachte, dass diese Funktion erwartet, dass die Shell von einem Standardtyp wie `cmd`, `bash`, etc. ist. Wenn du andere Arten von Shells und Befehlen in einem Terminal öffnen willst, kannst du stattdessen den benutzerdefinierten Terminalbefehlstyp verwenden. Wenn du Standardshells verwendest, kannst du diese Verbindung auch im Dateibrowser öffnen. + +### Interaktive Eingabeaufforderungen + +Der Shell-Prozess kann eine Zeitüberschreitung verursachen oder sich aufhängen, wenn eine unerwartete +eingabeaufforderung, wie z. B. eine Passwortabfrage. Deshalb solltest du immer darauf achten, dass es keine interaktiven Eingabeaufforderungen gibt. + +Ein Befehl wie `ssh user@host` funktioniert hier zum Beispiel problemlos, solange kein Passwort verlangt wird. + +### Benutzerdefinierte lokale Shells + +In vielen Fällen ist es sinnvoll, eine Shell mit bestimmten Optionen zu starten, die normalerweise standardmäßig deaktiviert sind, damit einige Skripte und Befehle richtig funktionieren. Zum Beispiel: + +- [Verzögerte Erweiterung in + cmd](https://ss64.com/nt/delayedexpansion.html) +- [Powershell-Ausführung + richtlinien](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3) +- [Bash POSIX + Modus](https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html) +- Und jede andere mögliche Startoption für eine Shell deiner Wahl + +Dies kannst du erreichen, indem du benutzerdefinierte Shell-Befehle erstellst, zum Beispiel mit den folgenden Befehlen: + +- `cmd /v` +- `powershell -ExecutionMode Bypass` +- `bash --posix` \ No newline at end of file diff --git a/lang/proc/texts/shellCommand_en.md b/lang/proc/texts/shellCommand_en.md new file mode 100644 index 000000000..cd19fcc8c --- /dev/null +++ b/lang/proc/texts/shellCommand_en.md @@ -0,0 +1,30 @@ +## Custom shell connections + +Opens a shell using the custom command by executing the given command on the selected host system. This shell can either be local or remote. + +Note that this functionality expects the shell to be of a standard type such as `cmd`, `bash`, etc. If you want to open any other types of shells and commands in a terminal, you can use the custom terminal command type instead. Using standard shells allows you to also open this connection in the file browser. + +### Interactive prompts + +The shell process might time out or hang in case there is an unexpected required +input prompt, like a password prompt. Therefore, you should always make sure that there are no interactive input prompts. + +For example, a command like `ssh user@host` will work fine here as long there is no password required. + +### Custom local shells + +In many cases, it is useful to launch a shell with certain options that are usually disabled by default in order to make some scripts and commands work properly. For example: + +- [Delayed Expansion in + cmd](https://ss64.com/nt/delayedexpansion.html) +- [Powershell execution + policies](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3) +- [Bash POSIX + Mode](https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html) +- And any other possible launch option for a shell of your choice + +This can be achieved by creating custom shell commands with for example the following commands: + +- `cmd /v` +- `powershell -ExecutionMode Bypass` +- `bash --posix` \ No newline at end of file diff --git a/lang/proc/texts/shellCommand_es.md b/lang/proc/texts/shellCommand_es.md new file mode 100644 index 000000000..1427539ce --- /dev/null +++ b/lang/proc/texts/shellCommand_es.md @@ -0,0 +1,30 @@ +## Conexiones shell personalizadas + +Abre un shell utilizando el comando personalizado ejecutando el comando dado en el sistema anfitrión seleccionado. Este shell puede ser local o remoto. + +Ten en cuenta que esta funcionalidad espera que el intérprete de comandos sea de tipo estándar, como `cmd`, `bash`, etc. Si quieres abrir cualquier otro tipo de shell y comandos en un terminal, puedes utilizar en su lugar el tipo de comando terminal personalizado. Si utilizas shells estándar, también podrás abrir esta conexión en el explorador de archivos. + +### Avisos interactivos + +El proceso del intérprete de comandos puede agotarse o bloquearse en caso de que se solicite una entrada inesperada, como una contraseña +inesperada, como una solicitud de contraseña. Por lo tanto, debes asegurarte siempre de que no hay peticiones de entrada interactivas. + +Por ejemplo, un comando como `ssh usuario@host` funcionará bien siempre que no se solicite una contraseña. + +### Shell local personalizado + +En muchos casos, es útil lanzar un intérprete de comandos con determinadas opciones que suelen estar desactivadas por defecto para que algunos scripts y comandos funcionen correctamente. Por ejemplo + +- [Expansión retardada en + cmd](https://ss64.com/nt/delayedexpansion.html) +- [Ejecución de Powershell + políticas](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3) +- [Bash POSIX + Modo](https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html) +- Y cualquier otra opción de lanzamiento posible para un intérprete de comandos de tu elección + +Esto se puede conseguir creando comandos de shell personalizados con, por ejemplo, los siguientes comandos: + +- cmd /vpowershell -ModoEjecución Bypassbash --posixcmd /vpowershell -ExecutionMode Bypassbash --posix`. + +Beachte, dass dies der *private* Schlüssel sein sollte, nicht der öffentliche. +Wenn du das verwechselst, wird dir ssh nur kryptische Fehlermeldungen geben. + +### GPG Agent + +Wenn deine Identitäten zum Beispiel auf einer Smartcard gespeichert sind, kannst du sie dem SSH-Client über den `gpg-agent` zur Verfügung stellen. +Diese Option aktiviert automatisch die SSH-Unterstützung des Agenten, falls sie noch nicht aktiviert ist, und startet den GPG-Agent-Daemon mit den richtigen Einstellungen neu. + +### Yubikey PIV + +Wenn deine Identitäten mit der PIV-Chipkartenfunktion des Yubikey gespeichert sind, kannst du sie mit +kannst du sie mit der YKCS11-Bibliothek von Yubico abrufen, die im Lieferumfang des Yubico PIV Tools enthalten ist. + +Beachte, dass du eine aktuelle Version von OpenSSH benötigst, um diese Funktion nutzen zu können. + +### Benutzerdefinierter Agent + +Du kannst auch einen benutzerdefinierten Agenten verwenden, indem du hier entweder den Socket-Speicherort oder den benannten Pipe-Speicherort angibst. +Er wird dann über die Option `IdentityAgent` übergeben. + +### Benutzerdefinierte PKCS#11-Bibliothek + +Hiermit wird der OpenSSH-Client angewiesen, die angegebene Shared-Library-Datei zu laden, die die Authentifizierung übernimmt. + +Beachte, dass du einen aktuellen Build von OpenSSH brauchst, um diese Funktion zu nutzen. diff --git a/lang/proc/texts/sshKey_en.md b/lang/proc/texts/sshKey_en.md new file mode 100644 index 000000000..a70daef48 --- /dev/null +++ b/lang/proc/texts/sshKey_en.md @@ -0,0 +1,55 @@ +### None + +Disables `publickey` authentication. + +### SSH-Agent + +In case your identities are stored in the SSH-Agent, the ssh executable can use them if the agent is started. +XPipe will automatically start the agent process if it is not running yet. + +### Pageant (Windows) + +In case you are using pageant on Windows, XPipe will check whether pageant is running first. +Due to the nature of pageant, it is your responsibility to have it +running as you manually have to specify all keys you would like to add every time. +If it is running, XPipe will pass the proper named pipe via +`-oIdentityAgent=...` to ssh, you don't have to include any custom config files. + +Note that there are some implementation bugs in the OpenSSH client that can cause issues +if your username contains spaces or is too long, so try to use the latest version. + +### Pageant (Linux & macOS) + +In case your identities are stored in the pageant agent, the ssh executable can use them if the agent is started. +XPipe will automatically start the agent process if it is not running yet. + +### Identity file + +You can also specify an identity file with an optional passphrase. +This option is the equivalent of `ssh -i `. + +Note that this should be the *private* key, not the public one. +If you mix that up, ssh will only give you cryptic error messages. + +### GPG Agent + +If your identities are stored for example on a smartcard, you can choose to provide them to the SSH client via the `gpg-agent`. +This option will automatically enable SSH support of the agent if not enabled yet and restart the GPG agent daemon with the correct settings. + +### Yubikey PIV + +If your identities are stored with the PIV smart card function of the Yubikey, you can retreive +them with Yubico's YKCS11 library, which comes bundled with Yubico PIV Tool. + +Note that you need an up-to-date build of OpenSSH in order to use this feature. + +### Custom agent + +You can also use a custom agent by providing either the socket location or named pipe location here. +This will pass it via the `IdentityAgent` option. + +### Custom PKCS#11 library + +This will instruct the OpenSSH client to load the specified shared library file, which will handle the authentication. + +Note that you need an up-to-date build of OpenSSH in order to use this feature. diff --git a/lang/proc/texts/sshKey_es.md b/lang/proc/texts/sshKey_es.md new file mode 100644 index 000000000..4d11e09ec --- /dev/null +++ b/lang/proc/texts/sshKey_es.md @@ -0,0 +1,55 @@ +### Ninguno + +Desactiva la autenticación de `clave pública`. + +### SSH-Agente + +En caso de que tus identidades estén almacenadas en el SSH-Agent, el ejecutable ssh puede utilizarlas si se inicia el agente. +XPipe iniciará automáticamente el proceso del agente si aún no se está ejecutando. + +### Pageant (Windows) + +En caso de que estés utilizando pageant en Windows, XPipe comprobará primero si pageant se está ejecutando. +Debido a la naturaleza de pageant, es tu responsabilidad tenerlo +ya que tienes que especificar manualmente todas las claves que quieras añadir cada vez. +Si se está ejecutando, XPipe pasará la tubería con el nombre adecuado a través de +`-oIdentityAgent=...` a ssh, no tienes que incluir ningún archivo de configuración personalizado. + +Ten en cuenta que hay algunos errores de implementación en el cliente OpenSSH que pueden causar problemas +si tu nombre de usuario contiene espacios o es demasiado largo, así que intenta utilizar la última versión. + +### Pageant (Linux y macOS) + +En caso de que tus identidades estén almacenadas en el agente pageant, el ejecutable ssh puede utilizarlas si se inicia el agente. +XPipe iniciará automáticamente el proceso del agente si aún no se está ejecutando. + +### Archivo de identidad + +También puedes especificar un archivo de identidad con una frase de contraseña opcional. +Esta opción equivale a `ssh -i `. + +Ten en cuenta que ésta debe ser la clave *privada*, no la pública. +Si te confundes, ssh sólo te dará crípticos mensajes de error. + +### Agente GPG + +Si tus identidades están almacenadas, por ejemplo, en una tarjeta inteligente, puedes optar por proporcionárselas al cliente SSH a través del `agente GPG`. +Esta opción habilitará automáticamente el soporte SSH del agente si aún no está habilitado y reiniciará el demonio del agente GPG con la configuración correcta. + +### Yubikey PIV + +Si tus identidades están almacenadas con la función de tarjeta inteligente PIV del Yubikey, puedes recuperarlas +con la biblioteca YKCS11 de Yubico, que viene incluida con Yubico PIV Tool. + +Ten en cuenta que necesitas una versión actualizada de OpenSSH para utilizar esta función. + +### Agente personalizado + +También puedes utilizar un agente personalizado proporcionando aquí la ubicación del socket o la ubicación de la tubería con nombre. +Esto lo pasará a través de la opción `IdentityAgent`. + +### Biblioteca PKCS#11 personalizada + +Esto indicará al cliente OpenSSH que cargue el archivo de biblioteca compartida especificado, que se encargará de la autenticación. + +Ten en cuenta que necesitas una versión actualizada de OpenSSH para utilizar esta función. diff --git a/lang/proc/texts/sshKey_fr.md b/lang/proc/texts/sshKey_fr.md new file mode 100644 index 000000000..7eaff9229 --- /dev/null +++ b/lang/proc/texts/sshKey_fr.md @@ -0,0 +1,55 @@ +### Aucun + +Désactive l'authentification par `publickey`. + +### SSH-Agent + +Dans le cas où tes identités sont stockées dans le SSH-Agent, l'exécutable ssh peut les utiliser si l'agent est démarré. +XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. + +### Pageant (Windows) + +Si tu utilises pageant sous Windows, XPipe vérifiera d'abord si pageant est en cours d'exécution. +En raison de la nature de pageant, il est de ta responsabilité de le faire fonctionner +tu dois en effet spécifier manuellement toutes les clés que tu souhaites ajouter à chaque fois. +S'il fonctionne, XPipe passera le bon tuyau nommé via +`-oIdentityAgent=...` à ssh, tu n'as pas besoin d'inclure de fichiers de configuration personnalisés. + +Note qu'il y a quelques bogues d'implémentation dans le client OpenSSH qui peuvent causer des problèmes +si ton nom d'utilisateur contient des espaces ou est trop long, alors essaie d'utiliser la dernière version. + +### Pageant (Linux & macOS) + +Dans le cas où tes identités sont stockées dans l'agent pageant, l'exécutable ssh peut les utiliser si l'agent est démarré. +XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. + +### Fichier d'identité + +Tu peux également spécifier un fichier d'identité avec une phrase de passe optionnelle. +Cette option est l'équivalent de `ssh -i `. + +Note qu'il doit s'agir de la clé *privée*, et non de la clé publique. +Si tu confonds les deux, ssh ne te donnera que des messages d'erreur énigmatiques. + +### Agent GPG + +Si tes identités sont stockées par exemple sur une carte à puce, tu peux choisir de les fournir au client SSH via le `gpg-agent`. +Cette option activera automatiquement la prise en charge SSH de l'agent si elle n'est pas encore activée et redémarrera le démon de l'agent GPG avec les bons paramètres. + +### Yubikey PIV + +Si tes identités sont stockées avec la fonction de carte à puce PIV du Yubikey, tu peux les récupérer à l'aide du logiciel Yubico +les récupérer avec la bibliothèque YKCS11 de Yubico, qui est fournie avec Yubico PIV Tool. + +Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. + +### Agent personnalisé + +Tu peux également utiliser un agent personnalisé en indiquant ici l'emplacement de la prise ou l'emplacement du tuyau nommé. +Ceci sera transmis via l'option `IdentityAgent`. + +### Bibliothèque PKCS#11 personnalisée + +Ceci demandera au client OpenSSH de charger le fichier de bibliothèque partagée spécifié, qui gérera l'authentification. + +Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. diff --git a/lang/proc/texts/sshKey_it.md b/lang/proc/texts/sshKey_it.md new file mode 100644 index 000000000..8a8154ac0 --- /dev/null +++ b/lang/proc/texts/sshKey_it.md @@ -0,0 +1,55 @@ +### Nessuno + +Disabilita l'autenticazione a `chiave pubblica`. + +### Agente SSH + +Se le tue identità sono memorizzate nell'agente SSH, l'eseguibile ssh può utilizzarle se l'agente viene avviato. +XPipe avvierà automaticamente il processo dell'agente se non è ancora in esecuzione. + +### Pageant (Windows) + +Nel caso in cui si utilizzi pageant su Windows, XPipe verificherà innanzitutto se pageant è in esecuzione. +A causa della natura di pageant, è tua responsabilità averlo in esecuzione +è tua responsabilità che sia in funzione, in quanto dovrai specificare manualmente tutte le chiavi che desideri aggiungere ogni volta. +Se è in funzione, XPipe passerà la pipe con il nome appropriato tramite +`-oIdentityAgent=...` a ssh, non è necessario includere alcun file di configurazione personalizzato. + +Si noti che ci sono alcuni bug di implementazione nel client OpenSSH che possono causare dei problemi +se il nome utente contiene spazi o è troppo lungo, quindi cerca di utilizzare la versione più recente. + +### Pageant (Linux e macOS) + +Se le tue identità sono memorizzate nell'agente pageant, l'eseguibile ssh può utilizzarle se l'agente viene avviato. +XPipe avvierà automaticamente il processo dell'agente se non è ancora in esecuzione. + +### File di identità + +Puoi anche specificare un file di identità con una passphrase opzionale. +Questa opzione è l'equivalente di `ssh -i `. + +Nota che questa deve essere la chiave *privata*, non quella pubblica. +Se fai confusione, ssh ti darà solo messaggi di errore criptici. + +### Agente GPG + +Se le tue identità sono memorizzate, ad esempio, su una smartcard, puoi scegliere di fornirle al client SSH tramite il `gpg-agent`. +Questa opzione abiliterà automaticamente il supporto SSH dell'agente se non ancora abilitato e riavvierà il demone dell'agente GPG con le impostazioni corrette. + +### Yubikey PIV + +Se le tue identità sono memorizzate con la funzione smart card PIV di Yubikey, puoi recuperarle con il programma Yubico +con la libreria YKCS11 di Yubico, fornita con Yubico PIV Tool. + +Per poter utilizzare questa funzione, è necessario disporre di una versione aggiornata di OpenSSH. + +### Agente personalizzato + +Puoi anche utilizzare un agente personalizzato fornendo qui la posizione del socket o della named pipe. +Questo verrà passato attraverso l'opzione `IdentityAgent`. + +### Libreria PKCS#11 personalizzata + +Indica al client OpenSSH di caricare il file di libreria condiviso specificato, che gestirà l'autenticazione. + +Si noti che per utilizzare questa funzione è necessaria una versione aggiornata di OpenSSH. diff --git a/lang/proc/texts/sshKey_ja.md b/lang/proc/texts/sshKey_ja.md new file mode 100644 index 000000000..b68270bfb --- /dev/null +++ b/lang/proc/texts/sshKey_ja.md @@ -0,0 +1,55 @@ +### なし + +`publickey`認証を無効にする。 + +### SSH エージェント + +IDがSSH-Agentに保存されている場合、エージェントが起動するとssh実行ファイルはIDを使用できる。 +XPipeはエージェントプロセスがまだ実行されていない場合、自動的に開始する。 + +### ページェント (Windows) + +Windowsでページャントを使用している場合、XPipeはまずページャントが起動しているかどうかを確認する。 +ページャントの性質上、ページャントを実行させるのはユーザーの責任である。 +ページェントが実行されている場合、XPipeは最初にページェントが実行されているかどうかを確認する。 +ページェントが実行されていれば、XPipeは適切な名前のパイプを +`-oIdentityAgent=...`を介してsshに適切な名前のパイプを渡す。 + +OpenSSH クライアントには、いくつかの実装上のバグがあり、 それが問題を引き起こす可能性があることに注意してほしい。 +の実装にバグがあることに注意してほしい。 + +### Pageant (Linux & macOS) + +IDがPageantエージェントに保存されている場合、エージェントが起動されるとssh実行ファイルはIDを使用することができる。 +XPipeはエージェントプロセスがまだ起動していない場合、自動的に起動する。 + +### アイデンティティファイル + +オプションのパスフレーズとともに ID ファイルを指定することもできる。 +このオプションは、`ssh -i ` と同等である。 + +これは公開鍵ではなく、*秘密*鍵であることに注意すること。 +これを間違えると、sshは不可解なエラーメッセージを出すだけである。 + +### GPGエージェント + +IDが例えばスマートカードに保存されている場合、`gpg-agent` を使ってSSHクライアントに提供することができる。 +このオプションは、まだ有効になっていない場合、エージェントのSSHサポートを自動的に有効にし、正しい設定でGPGエージェントデーモンを再起動する。 + +### Yubikey PIV + +IDがYubikeyのPIVスマートカード機能で保存されている場合、YubicoのYubikey PIVを使用してIDを取得できる。 +Yubico PIV ToolにバンドルされているYubicoのYKCS11ライブラリを使用する。 + +この機能を使うにはOpenSSHの最新ビルドが必要なので注意。 + +### カスタムエージェント + +ソケットの場所か名前付きパイプの場所をここに指定することで、カスタムエージェントを使うこともできる。 +これは `IdentityAgent` オプションを介して渡される。 + +### カスタム PKCS#11 ライブラリ + +これは OpenSSH クライアントに、認証を処理する指定された共有ライブラリファイルをロードするように指示する。 + +この機能を使うには、OpenSSH の最新ビルドが必要であることに注意。 diff --git a/lang/proc/texts/sshKey_nl.md b/lang/proc/texts/sshKey_nl.md new file mode 100644 index 000000000..a6dfd65fa --- /dev/null +++ b/lang/proc/texts/sshKey_nl.md @@ -0,0 +1,55 @@ +### Geen + +Schakelt `publickey` authenticatie uit. + +### SSH-agent + +Als je identiteiten zijn opgeslagen in de SSH-Agent, kan het ssh-programma deze gebruiken als de agent wordt gestart. +XPipe zal automatisch het agent proces starten als het nog niet draait. + +### Pageant (Windows) + +Als je pageant onder Windows gebruikt, zal XPipe eerst controleren of pageant wordt uitgevoerd. +Vanwege de aard van pageant, is het jouw verantwoordelijkheid om het +actief is, omdat je elke keer handmatig alle sleutels moet opgeven die je wilt toevoegen. +Als het actief is, zal XPipe de juiste pijp met naam doorgeven via +`-oIdentityAgent=...` naar ssh, je hoeft geen aangepaste configuratiebestanden op te nemen. + +Merk op dat er enkele implementatie bugs in de OpenSSH client zitten die problemen kunnen veroorzaken +als je gebruikersnaam spaties bevat of te lang is, dus probeer de laatste versie te gebruiken. + +### Pageant (Linux & macOS) + +Als je identiteiten zijn opgeslagen in de pageant agent, kan de ssh executable ze gebruiken als de agent wordt gestart. +XPipe zal automatisch het agent proces starten als het nog niet draait. + +### Identiteitsbestand + +Je kunt ook een identiteitsbestand opgeven met een optionele wachtwoordzin. +Deze optie is het equivalent van `ssh -i `. + +Merk op dat dit de *private* sleutel moet zijn, niet de publieke. +Als je dat verwisselt, zal ssh je alleen maar cryptische foutmeldingen geven. + +### GPG-agent + +Als je identiteiten bijvoorbeeld zijn opgeslagen op een smartcard, dan kun je ervoor kiezen om deze aan de SSH-client te verstrekken via de `gpg-agent`. +Deze optie schakelt automatisch SSH-ondersteuning van de agent in als die nog niet is ingeschakeld en herstart de GPG-agent daemon met de juiste instellingen. + +### Yubikey PIV + +Als je identiteiten zijn opgeslagen met de PIV smartcardfunctie van de Yubikey, dan kun je ze ophalen +ophalen met Yubico's YKCS11 bibliotheek, die wordt meegeleverd met Yubico PIV Tool. + +Merk op dat je een up-to-date build van OpenSSH nodig hebt om deze functie te kunnen gebruiken. + +### Aangepaste agent + +Je kunt ook een aangepaste agent gebruiken door hier de socketlocatie of named pipe locatie op te geven. +Deze wordt doorgegeven via de `IdentityAgent` optie. + +### Aangepaste PKCS#11 bibliotheek + +Dit zal de OpenSSH client instrueren om het gespecificeerde shared library bestand te laden, dat de authenticatie zal afhandelen. + +Merk op dat je een actuele build van OpenSSH nodig hebt om deze functie te gebruiken. diff --git a/lang/proc/texts/sshKey_pt.md b/lang/proc/texts/sshKey_pt.md new file mode 100644 index 000000000..31326323b --- /dev/null +++ b/lang/proc/texts/sshKey_pt.md @@ -0,0 +1,55 @@ +### Não tens nada + +Desativa a autenticação `publickey`. + +### SSH-Agent + +Caso as tuas identidades estejam armazenadas no SSH-Agent, o executável ssh pode usá-las se o agente for iniciado. +O XPipe iniciará automaticamente o processo do agente se ele ainda não estiver em execução. + +### Pageant (Windows) + +Caso estejas a utilizar o pageant no Windows, o XPipe irá verificar se o pageant está a ser executado primeiro. +Devido à natureza do pageant, é da tua responsabilidade tê-lo +a responsabilidade de o ter em execução, uma vez que tens de especificar manualmente todas as chaves que gostarias de adicionar de cada vez. +Se estiver em execução, o XPipe passará o pipe nomeado apropriado via +`-oIdentityAgent=...` para o ssh, não tens de incluir quaisquer ficheiros de configuração personalizados. + +Nota que existem alguns bugs de implementação no cliente OpenSSH que podem causar problemas +se o seu nome de usuário contiver espaços ou for muito longo, então tenta usar a versão mais recente. + +### Pageant (Linux & macOS) + +Caso as tuas identidades estejam armazenadas no agente pageant, o executável ssh pode usá-las se o agente for iniciado. +O XPipe iniciará automaticamente o processo do agente se ele ainda não estiver em execução. + +### Arquivo de identidade + +Também podes especificar um ficheiro de identidade com uma frase-chave opcional. +Esta opção é o equivalente a `ssh -i `. + +Nota que esta deve ser a chave *privada*, não a pública. +Se misturares isso, o ssh apenas te dará mensagens de erro crípticas. + +### Agente GPG + +Se as tuas identidades estão armazenadas, por exemplo, num smartcard, podes escolher fornecê-las ao cliente SSH através do `gpg-agent`. +Esta opção habilitará automaticamente o suporte SSH do agente se ainda não estiver habilitado e reiniciará o daemon do agente GPG com as configurações corretas. + +### Yubikey PIV + +Se as tuas identidades estão armazenadas com a função de cartão inteligente PIV do Yubikey, podes recuperá-las +podes recuperá-las com a biblioteca YKCS11 do Yubico, que vem junto com a ferramenta Yubico PIV. + +Nota que necessita de uma versão actualizada do OpenSSH para poder utilizar esta função. + +### Agente personalizado + +Também podes usar um agente personalizado fornecendo a localização do socket ou a localização do pipe nomeado aqui. +Isto irá passá-lo através da opção `IdentityAgent`. + +### Biblioteca PKCS#11 personalizada + +Isso instrui o cliente OpenSSH a carregar o arquivo de biblioteca compartilhada especificado, que irá lidar com a autenticação. + +Nota que precisas de uma versão actualizada do OpenSSH para usar esta funcionalidade. diff --git a/lang/proc/texts/sshKey_ru.md b/lang/proc/texts/sshKey_ru.md new file mode 100644 index 000000000..608edd5c7 --- /dev/null +++ b/lang/proc/texts/sshKey_ru.md @@ -0,0 +1,55 @@ +### None + +Отключает аутентификацию `publickey`. + +### SSH-Agent + +Если твои идентификаторы хранятся в SSH-агенте, то исполняемый файл ssh может использовать их, если агент запущен. +XPipe автоматически запустит процесс агента, если он еще не запущен. + +### Pageant (Windows) + +Если ты используешь pageant в Windows, XPipe сначала проверит, запущен ли pageant. +Из-за особенностей работы pageant ты должен убедиться в том, что он запущен +так как тебе придется каждый раз вручную указывать все ключи, которые ты хочешь добавить. +Если он запущен, XPipe передаст соответствующую именованную трубу через +`-oIdentityAgent=...` в ssh, тебе не придется включать никаких пользовательских конфигурационных файлов. + +Обрати внимание, что в клиенте OpenSSH есть некоторые ошибки в реализации, которые могут вызвать проблемы +если твое имя пользователя содержит пробелы или слишком длинное, поэтому старайся использовать последнюю версию. + +### Pageant (Linux & macOS) + +Если твои идентификаторы хранятся в агенте Pageant, то исполняемый файл ssh может использовать их, если агент запущен. +XPipe автоматически запустит процесс агента, если он еще не запущен. + +### Файл идентификатора + +Ты также можешь указать файл идентификации с необязательной кодовой фразой. +Эта опция эквивалентна `ssh -i `. + +Обрати внимание, что это должен быть *приватный* ключ, а не открытый. +Если ты перепутаешь, то ssh будет выдавать тебе только загадочные сообщения об ошибках. + +### GPG Agent + +Если твои идентификационные данные хранятся, например, на смарт-карте, ты можешь предоставить их SSH-клиенту через `gpg-agent`. +Эта опция автоматически включит поддержку SSH агентом, если она еще не включена, и перезапустит демон GPG-агента с правильными настройками. + +### Yubikey PIV + +Если твои личные данные хранятся в смарт-карте PIV, встроенной в Yubikey, ты можешь получить их +их с помощью библиотеки YKCS11 от Yubico, которая поставляется в комплекте с Yubico PIV Tool. + +Обрати внимание, что для использования этой функции тебе нужна актуальная сборка OpenSSH. + +### Пользовательский агент + +Ты также можешь использовать пользовательский агент, указав здесь либо расположение сокета, либо расположение именованной трубы. +Это передаст его через опцию `IdentityAgent`. + +### Пользовательская библиотека PKCS#11 + +Это даст указание клиенту OpenSSH загрузить указанный файл общей библиотеки, который будет обрабатывать аутентификацию. + +Учти, что для использования этой функции тебе понадобится актуальная сборка OpenSSH. diff --git a/lang/proc/texts/sshKey_tr.md b/lang/proc/texts/sshKey_tr.md new file mode 100644 index 000000000..6d914367c --- /dev/null +++ b/lang/proc/texts/sshKey_tr.md @@ -0,0 +1,55 @@ +### Yok + +`publickey` kimlik do?rulamas?n? devre d??? b?rak?r. + +### SSH-Agent + +Kimliklerinizin SSH-Agent'ta depolanmas? durumunda, ssh yrtlebilir dosyas?, agent ba?lat?ld???nda bunlar? kullanabilir. +XPipe, henz al??m?yorsa arac? srecini otomatik olarak ba?latacakt?r. + +### Pageant (Windows) + +Windows zerinde pageant kullan?yorsan?z, XPipe nce pageant'?n al???p al??mad???n? kontrol edecektir. +Pageant'?n do?as? gere?i, pageant'a sahip olmak sizin sorumlulu?unuzdad?r +her seferinde eklemek istedi?iniz tm anahtarlar? manuel olarak belirtmeniz gerekti?inden al???yor. +E?er al???yorsa, XPipe uygun adland?r?lm?? boruyu +`-oIdentityAgent=...` ssh iin, herhangi bir zel yap?land?rma dosyas? eklemeniz gerekmez. + +OpenSSH istemcisinde sorunlara neden olabilecek baz? uygulama hatalar? oldu?unu unutmay?n +kullan?c? ad?n?z bo?luk ieriyorsa veya ok uzunsa, en son srm kullanmaya al???n. + +### Pageant (Linux ve macOS) + +Kimliklerinizin pageant arac?s?nda saklanmas? durumunda, arac? ba?lat?l?rsa ssh yrtlebilir dosyas? bunlar? kullanabilir. +XPipe, henz al??m?yorsa arac? srecini otomatik olarak ba?latacakt?r. + +### Kimlik dosyas? + +?ste?e ba?l? bir parola ile bir kimlik dosyas? da belirtebilirsiniz. +Bu seenek `ssh -i ` seene?ine e?de?erdir. + +Bunun genel de?il *zel* anahtar olmas? gerekti?ini unutmay?n. +E?er bunu kar??t?r?rsan?z, ssh size sadece ?ifreli hata mesajlar? verecektir. + +### GPG Agent + +Kimlikleriniz rne?in bir ak?ll? kartta saklan?yorsa, bunlar? SSH istemcisine `gpg-agent` arac?l???yla sa?lamay? seebilirsiniz. +Bu seenek, henz etkinle?tirilmemi?se arac?n?n SSH deste?ini otomatik olarak etkinle?tirecek ve GPG arac? arka plan program?n? do?ru ayarlarla yeniden ba?latacakt?r. + +### Yubikey PIV + +Kimlikleriniz Yubikey'in PIV ak?ll? kart i?levi ile saklan?yorsa, ?unlar? geri alabilirsiniz +yubico PIV Arac? ile birlikte gelen Yubico'nun YKCS11 ktphanesi ile. + +Bu zelli?i kullanabilmek iin gncel bir OpenSSH yap?s?na ihtiyac?n?z oldu?unu unutmay?n. + +### zel ajan + +Burada soket konumunu veya adland?r?lm?? boru konumunu sa?layarak zel bir arac? da kullanabilirsiniz. +Bu, `IdentityAgent` seene?i arac?l???yla aktar?lacakt?r. + +### zel PKCS#11 ktphanesi + +Bu, OpenSSH istemcisine kimlik do?rulamas?n? gerekle?tirecek olan belirtilen payla??lan ktphane dosyas?n? yklemesi talimat?n? verecektir. + +Bu zelli?i kullanabilmek iin gncel bir OpenSSH yap?s?na ihtiyac?n?z oldu?unu unutmay?n. diff --git a/lang/proc/texts/sshKey_zh.md b/lang/proc/texts/sshKey_zh.md new file mode 100644 index 000000000..4fee323c6 --- /dev/null +++ b/lang/proc/texts/sshKey_zh.md @@ -0,0 +1,55 @@ +### 无 + +禁用 ` 公钥`身份验证。 + +### SSH-代理 + +如果您的身份信息存储在 SSH-Agent 中,则 ssh 可执行文件可在代理启动时使用这些身份信息。 +如果代理进程尚未运行,XPipe 将自动启动该进程。 + +### Pageant(Windows) + +如果您在 Windows 上使用 Pageant,XPipe 会首先检查 Pageant 是否正在运行。 +由于 Pageant 的性质,您有责任让它运行。 +因为您每次都必须手动指定要添加的所有密钥。 +如果正在运行,XPipe 将通过 +<代码>-oIdentityAgent=...传递给 ssh,您不必包含任何自定义配置文件。 + +请注意,OpenSSH 客户端中存在一些执行错误,可能会导致以下问题 +如果用户名包含空格或过长,可能会导致问题,因此请尽量使用最新版本。 + +### Pageant(Linux 和 macOS) + +如果您的身份信息存储在 pageant 代理中,则 ssh 可执行文件可以在代理启动时使用这些身份信息。 +如果代理进程尚未运行,XPipe 将自动启动该进程。 + +### 身份文件 + +您还可以指定一个身份文件,并指定一个可选的口令。 +该选项等同于 `ssh -i ` 。 + +请注意,这应该是 *private* 密钥,而不是公钥。 +如果弄混了,ssh 只会给出令人费解的错误信息。 + +#### GPG 代理 + +如果你的身份信息存储在智能卡中,你可以选择通过 `gpg-agent` 将其提供给 SSH 客户端。 +如果尚未启用,该选项将自动启用代理的 SSH 支持,并以正确的设置重启 GPG 代理守护进程。 + +### Yubikey PIV + +如果你的身份信息是用 Yubikey 的 PIV 智能卡功能存储的,你可以用 Yubico 的 Yubikey PIV 卡找回它们。 +Yubico PIV 工具捆绑的 YKCS11 库。 + +请注意,要使用这一功能,你需要最新的 OpenSSH 版本。 + +### 自定义代理 + +您也可以在此处提供套接字位置或命名管道位置,从而使用自定义代理。 +这将通过 `IdentityAgent` 选项传递。 + +### 自定义 PKCS#11 库 + +这将指示 OpenSSH 客户端加载指定的共享库文件,以处理身份验证。 + +请注意,您需要最新版本的 OpenSSH 才能使用此功能。 diff --git a/lang/proc/texts/sshLocalTunnelBinding_de.md b/lang/proc/texts/sshLocalTunnelBinding_de.md new file mode 100644 index 000000000..cc3556e7f --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_de.md @@ -0,0 +1,5 @@ +## Bindung + +Die Bindungsinformationen, die du angibst, werden direkt an den `ssh`-Client wie folgt übergeben: `-L [origin_address:]origin_port:remote_address:remote_port`. + +Standardmäßig wird der Ursprung an die Loopback-Schnittstelle gebunden, wenn nicht anders angegeben. Du kannst auch beliebige Adressplatzhalter verwenden, z.B. indem du die Adresse auf `0.0.0.0` setzt, um an alle Netzwerkschnittstellen zu binden, die über IPv4 erreichbar sind. Wenn du die Adresse komplett weglässt, wird der Platzhalter `*` verwendet, der Verbindungen zu allen Netzwerkschnittstellen erlaubt. Beachte, dass manche Netzwerkschnittstellen-Notation nicht von allen Betriebssystemen unterstützt wird. Windows-Server zum Beispiel unterstützen den Platzhalter `*` nicht. diff --git a/lang/proc/texts/sshLocalTunnelBinding_en.md b/lang/proc/texts/sshLocalTunnelBinding_en.md new file mode 100644 index 000000000..f2b5046fc --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_en.md @@ -0,0 +1,5 @@ +## Binding + +The binding information you provide is passed straight to the `ssh` client as follows: `-L [origin_address:]origin_port:remote_address:remote_port`. + +By default, the origin will bind to the loopback interface if not specified otherwise. You can also make use of any address wildcards, e.g. setting the address to `0.0.0.0` in order to bind to all network interfaces accessible via IPv4. When you completely omit the address, the wildcard `*`, which allows connections on all network interfaces, will be used. Note that some network interfaces notation might not be supported on all operating systems. Windows servers for example don't support the wildcard `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_es.md b/lang/proc/texts/sshLocalTunnelBinding_es.md new file mode 100644 index 000000000..82813f591 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_es.md @@ -0,0 +1,5 @@ +## Vinculación + +La información de enlace que proporciones se pasa directamente al cliente `ssh` de la siguiente forma: `-L [direccion_origen:]puerto_origen:direccion_remota:puerto_remoto`. + +Por defecto, el origen se enlazará a la interfaz loopback si no se especifica lo contrario. También puedes utilizar cualquier comodín de dirección, por ejemplo, establecer la dirección en `0.0.0.0` para enlazar con todas las interfaces de red accesibles a través de IPv4. Si omites completamente la dirección, se utilizará el comodín `*`, que permite conexiones en todas las interfaces de red. Ten en cuenta que algunas notaciones de interfaces de red pueden no ser compatibles con todos los sistemas operativos. Los servidores Windows, por ejemplo, no admiten el comodín `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_fr.md b/lang/proc/texts/sshLocalTunnelBinding_fr.md new file mode 100644 index 000000000..85035959f --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_fr.md @@ -0,0 +1,5 @@ +## Reliure + +Les informations de liaison que tu fournis sont transmises directement au client `ssh` de la manière suivante : `-L [origin_address :]origin_port:remote_address:remote_port`. + +Par défaut, l'origine se lie à l'interface de bouclage si elle n'est pas spécifiée autrement. Tu peux également utiliser des caractères génériques, par exemple en fixant l'adresse à `0.0.0.0` afin de lier toutes les interfaces réseau accessibles via IPv4. Lorsque tu omets complètement l'adresse, le caractère générique `*`, qui autorise les connexions sur toutes les interfaces réseau, sera utilisé. Note que certaines notations d'interfaces réseau peuvent ne pas être prises en charge par tous les systèmes d'exploitation. Les serveurs Windows, par exemple, ne prennent pas en charge le caractère générique `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_it.md b/lang/proc/texts/sshLocalTunnelBinding_it.md new file mode 100644 index 000000000..ec50383de --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_it.md @@ -0,0 +1,5 @@ +## Binding + +Le informazioni sul binding che fornisci vengono passate direttamente al client `ssh` come segue: `-L [indirizzo_origine:]porta_origine:indirizzo_remoto:porta_remoto`. + +Per impostazione predefinita, l'origine si legherà all'interfaccia di loopback se non specificato altrimenti. Puoi anche utilizzare i caratteri jolly degli indirizzi, ad esempio impostando l'indirizzo a `0.0.0.0` per effettuare il binding a tutte le interfacce di rete accessibili tramite IPv4. Se ometti completamente l'indirizzo, verrà utilizzato il carattere jolly `*`, che consente le connessioni su tutte le interfacce di rete. Nota che alcune notazioni sulle interfacce di rete potrebbero non essere supportate da tutti i sistemi operativi. I server Windows, ad esempio, non supportano il carattere jolly `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_ja.md b/lang/proc/texts/sshLocalTunnelBinding_ja.md new file mode 100644 index 000000000..c5df031c5 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_ja.md @@ -0,0 +1,5 @@ +## バインディング + +`-L[origin_address:]origin_port:remote_address:remote_port`。 + +デフォルトでは、特に指定がない場合、オリジンはループバックインターフェースにバインドされる。また、IPv4でアクセス可能なすべてのネットワークインターフェイスにバインドするために、アドレスを`0.0.0.0に設定するなど、アドレスのワイルドカードを利用することもできる。アドレスを完全に省略すると、ワイルドカード*`が使用され、すべてのネットワーク・インターフェイスでの接続が許可される。一部のネットワークインターフェイス表記は、すべてのオペレーティングシステムでサポートされていない可能性があることに注意すること。例えばWindowsサーバーはワイルドカード`*`をサポートしていない。 diff --git a/lang/proc/texts/sshLocalTunnelBinding_nl.md b/lang/proc/texts/sshLocalTunnelBinding_nl.md new file mode 100644 index 000000000..884d6f0ec --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_nl.md @@ -0,0 +1,5 @@ +## Binden + +De bindingsinformatie die je opgeeft wordt direct doorgegeven aan de `ssh` client als volgt: `-L [origin_address:]origin_port:remote_address:remote_port`. + +Standaard bindt de origin aan de loopback interface als deze niet anders is opgegeven. Je kunt ook gebruik maken van wildcards voor adressen, bijvoorbeeld door het adres in te stellen op `0.0.0.0` om te binden aan alle netwerkinterfaces die toegankelijk zijn via IPv4. Als je het adres helemaal weglaat, wordt het jokerteken `*` gebruikt, dat verbindingen op alle netwerkinterfaces toestaat. Merk op dat sommige notaties voor netwerkinterfaces mogelijk niet op alle besturingssystemen worden ondersteund. Windows servers bijvoorbeeld ondersteunen het jokerteken `*` niet. diff --git a/lang/proc/texts/sshLocalTunnelBinding_pt.md b/lang/proc/texts/sshLocalTunnelBinding_pt.md new file mode 100644 index 000000000..1b8d10737 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_pt.md @@ -0,0 +1,5 @@ +## Vinculação + +A informação de ligação que forneces é passada diretamente para o cliente `ssh` da seguinte forma: `-L [origin_address:]origin_port:remote_address:remote_port`. + +Por padrão, a origem será vinculada à interface de loopback se não for especificado de outra forma. Também podes utilizar quaisquer wildcards de endereço, e.g. definir o endereço para `0.0.0.0` de modo a ligar-se a todas as interfaces de rede acessíveis via IPv4. Quando omites completamente o endereço, será utilizado o wildcard `*`, que permite ligações em todas as interfaces de rede. Nota que algumas notações de interfaces de rede podem não ser suportadas em todos os sistemas operativos. Os servidores Windows, por exemplo, não suportam o curinga `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_ru.md b/lang/proc/texts/sshLocalTunnelBinding_ru.md new file mode 100644 index 000000000..d67d704e5 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_ru.md @@ -0,0 +1,5 @@ +## Связка + +Информация о привязке, которую ты предоставляешь, передается прямо в `ssh` клиент следующим образом: `-L [origin_address:]origin_port:remote_address:remote_port`. + +По умолчанию origin будет привязываться к интерфейсу loopback, если не указано иное. Ты также можешь использовать любые подстановочные знаки адреса, например, задать адрес `0.0.0.0`, чтобы привязаться ко всем сетевым интерфейсам, доступным по IPv4. Если ты полностью опустишь адрес, будет использован подстановочный знак `*`, который разрешает соединения на всех сетевых интерфейсах. Обрати внимание, что некоторые обозначения сетевых интерфейсов могут поддерживаться не всеми операционными системами. Например, серверы Windows не поддерживают подстановочный знак `*`. diff --git a/lang/proc/texts/sshLocalTunnelBinding_tr.md b/lang/proc/texts/sshLocalTunnelBinding_tr.md new file mode 100644 index 000000000..f0f4c9886 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_tr.md @@ -0,0 +1,5 @@ +## Ba?lama + +Sa?lad???n?z ba?lama bilgileri do?rudan `ssh` istemcisine ?u ?ekilde iletilir: `-L [origin_address:]origin_port:remote_address:remote_port`. + +Varsay?lan olarak, aksi belirtilmedi?i takdirde kaynak geri dng arayzne ba?lanacakt?r. Ayr?ca, IPv4 zerinden eri?ilebilen tm a? arayzlerine ba?lanmak iin adresi `0.0.0.0` olarak ayarlamak gibi herhangi bir adres joker karakterinden de yararlanabilirsiniz. Adresi tamamen atlad???n?zda, tm a? arayzlerinde ba?lant?lara izin veren `*` joker karakteri kullan?lacakt?r. Baz? a? arayzleri gsterimlerinin tm i?letim sistemlerinde desteklenmeyebilece?ini unutmay?n. rne?in Windows sunucular? `*` joker karakterini desteklemez. diff --git a/lang/proc/texts/sshLocalTunnelBinding_zh.md b/lang/proc/texts/sshLocalTunnelBinding_zh.md new file mode 100644 index 000000000..c0c6595fc --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_zh.md @@ -0,0 +1,5 @@ +## 绑定 + +您提供的绑定信息将以如下方式直接传递给 `ssh` 客户端:`-L [origin_address:]origin_port:remote_address:remote_port`. + +默认情况下,如果没有另行指定,origin 将绑定到环回接口。您也可以使用任何地址通配符,例如,将地址设置为 `0.0.0.0` 以绑定到通过 IPv4 访问的所有网络接口。如果完全省略地址,则将使用允许连接所有网络接口的通配符 `*`。请注意,有些网络接口符号可能不被所有操作系统支持。例如,Windows 服务器不支持通配符 `*`。 diff --git a/lang/proc/texts/sshLocalTunnelOrigin_de.md b/lang/proc/texts/sshLocalTunnelOrigin_de.md new file mode 100644 index 000000000..684ba0b8a --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_de.md @@ -0,0 +1,7 @@ +## Tunnelherkunft + +XPipe ist völlig flexibel, wenn es darum geht, wo ein Befehl ausgeführt werden soll. +Deshalb kannst du einen Tunnel nicht nur auf deinem lokalen Rechner, sondern auch auf jedem anderen System starten. + +Der Befehl zum Öffnen des Tunnels wird auf dem System ausgeführt, das du hier angibst. Du musst also einen `ssh`-Client auf diesem System installiert haben. +Wenn der Ursprung nicht der lokale Rechner ist, hält XPipe im Hintergrund eine Verbindung zu diesem entfernten System offen, um den Tunnel zu verwalten. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_en.md b/lang/proc/texts/sshLocalTunnelOrigin_en.md new file mode 100644 index 000000000..61b81e8d2 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_en.md @@ -0,0 +1,7 @@ +## Tunnel Origin + +XPipe is fully flexible with regards on where to execute a command. +Therefore, you can establish a tunnel starting on any remote system in addition to your local machine. + +The tunnel opener command will be executed on the system you specify here, so you need to have an `ssh` client installed on that system. +If the origin is not the local machine, XPipe will keep a connection open to that remote system in the background to manage the tunnel. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_es.md b/lang/proc/texts/sshLocalTunnelOrigin_es.md new file mode 100644 index 000000000..e5dd30158 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_es.md @@ -0,0 +1,7 @@ +## Origen del túnel + +XPipe es totalmente flexible respecto a dónde ejecutar un comando. +Por tanto, puedes establecer un túnel que se inicie en cualquier sistema remoto, además de en tu máquina local. + +El comando de apertura del túnel se ejecutará en el sistema que especifiques aquí, por lo que necesitas tener un cliente `ssh` instalado en ese sistema. +Si el origen no es la máquina local, XPipe mantendrá una conexión abierta a ese sistema remoto en segundo plano para gestionar el túnel. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_fr.md b/lang/proc/texts/sshLocalTunnelOrigin_fr.md new file mode 100644 index 000000000..abfda4c61 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_fr.md @@ -0,0 +1,7 @@ +## Origine du tunnel + +XPipe est totalement flexible en ce qui concerne le lieu d'exécution d'une commande. +Tu peux donc établir un tunnel à partir de n'importe quel système distant en plus de ta machine locale. + +La commande d'ouverture du tunnel sera exécutée sur le système que tu spécifies ici, tu dois donc avoir un client `ssh` installé sur ce système. +Si l'origine n'est pas la machine locale, XPipe gardera une connexion ouverte vers ce système distant en arrière-plan pour gérer le tunnel. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_it.md b/lang/proc/texts/sshLocalTunnelOrigin_it.md new file mode 100644 index 000000000..0f2fd2f86 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_it.md @@ -0,0 +1,7 @@ +## Origine del tunnel + +XPipe è completamente flessibile per quanto riguarda il luogo di esecuzione di un comando. +Pertanto, puoi stabilire un tunnel a partire da qualsiasi sistema remoto oltre che dal tuo computer locale. + +Il comando di apertura del tunnel verrà eseguito sul sistema che specifichi qui, quindi devi avere un client `ssh` installato su quel sistema. +Se l'origine non è il computer locale, XPipe manterrà aperta una connessione al sistema remoto in background per gestire il tunnel. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_ja.md b/lang/proc/texts/sshLocalTunnelOrigin_ja.md new file mode 100644 index 000000000..4f195b1a5 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_ja.md @@ -0,0 +1,7 @@ +## トンネル起点 + +XPipeは、コマンドを実行する場所に関して完全に柔軟である。 +そのため、ローカルマシンだけでなく、リモートシステム上でもトンネルを確立することができる。 + +トンネルオープナーコマンドはここで指定したシステム上で実行されるので、そのシステムに`ssh`クライアントがインストールされている必要がある。 +オリジンがローカルマシンでない場合、XPipeはトンネルを管理するために、バックグラウンドでリモートシステムへの接続を開いておく。 \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_nl.md b/lang/proc/texts/sshLocalTunnelOrigin_nl.md new file mode 100644 index 000000000..1745eda5a --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_nl.md @@ -0,0 +1,7 @@ +## Tunnel oorsprong + +XPipe is volledig flexibel met betrekking tot waar een commando wordt uitgevoerd. +Daarom kun je een tunnel starten op elk systeem op afstand naast je lokale machine. + +Het tunnelopener commando wordt uitgevoerd op het systeem dat je hier opgeeft, dus je moet een `ssh` client op dat systeem geïnstalleerd hebben. +Als de oorsprong niet de lokale machine is, dan houdt XPipe op de achtergrond een verbinding open met dat systeem op afstand om de tunnel te beheren. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_pt.md b/lang/proc/texts/sshLocalTunnelOrigin_pt.md new file mode 100644 index 000000000..7c6518ca1 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_pt.md @@ -0,0 +1,7 @@ +## Origem do túnel + +XPipe é totalmente flexível no que diz respeito a onde executar um comando. +Portanto, podes estabelecer um túnel a partir de qualquer sistema remoto, para além da tua máquina local. + +O comando de abertura do túnel será executado no sistema que especificares aqui, por isso precisas de ter um cliente `ssh` instalado nesse sistema. +Se a origem não for a máquina local, o XPipe manterá uma conexão aberta com esse sistema remoto em segundo plano para gerenciar o túnel. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_ru.md b/lang/proc/texts/sshLocalTunnelOrigin_ru.md new file mode 100644 index 000000000..7182773e3 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_ru.md @@ -0,0 +1,7 @@ +## Tunnel Origin + +XPipe обладает полной гибкостью в отношении того, где выполнять команду. +Поэтому ты можешь создать туннель, начинающийся не только на твоей локальной машине, но и на любой удаленной системе. + +Команда открытия туннеля будет выполнена на той системе, которую ты укажешь здесь, поэтому на ней должен быть установлен `ssh` клиент. +Если отправной точкой является не локальная машина, XPipe будет держать открытым соединение с этой удаленной системой в фоновом режиме, чтобы управлять туннелем. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_tr.md b/lang/proc/texts/sshLocalTunnelOrigin_tr.md new file mode 100644 index 000000000..79c80fcf4 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_tr.md @@ -0,0 +1,7 @@ +## Tnel Kkeni + +XPipe bir komutun nerede al??t?r?laca?? konusunda tamamen esnektir. +Bu nedenle, yerel makinenize ek olarak herhangi bir uzak sistemde ba?layan bir tnel kurabilirsiniz. + +Tnel a?c? komutu burada belirtti?iniz sistemde al??t?r?lacakt?r, bu nedenle bu sistemde bir `ssh` istemcisinin kurulu olmas? gerekir. +Kaynak yerel makine de?ilse, XPipe tneli ynetmek iin arka planda bu uzak sistemle bir ba?lant?y? a?k tutacakt?r. \ No newline at end of file diff --git a/lang/proc/texts/sshLocalTunnelOrigin_zh.md b/lang/proc/texts/sshLocalTunnelOrigin_zh.md new file mode 100644 index 000000000..816d2b842 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_zh.md @@ -0,0 +1,7 @@ +## 隧道起源 + +XPipe在执行命令的位置上非常灵活。 +因此,除了本地机器外,您还可以在任何远程系统上建立隧道。 + +隧道开启命令将在您指定的系统上执行,因此您需要在该系统上安装 `ssh` 客户端。 +如果原点不是本地计算机,XPipe 将在后台保持与该远程系统的连接,以管理隧道。 \ No newline at end of file diff --git a/lang/proc/texts/sshOptions_de.md b/lang/proc/texts/sshOptions_de.md new file mode 100644 index 000000000..f09be17e0 --- /dev/null +++ b/lang/proc/texts/sshOptions_de.md @@ -0,0 +1,27 @@ +## SSH-Konfigurationen + +Hier kannst du alle SSH-Optionen angeben, die an die Verbindung übergeben werden sollen. +Während einige Optionen für einen erfolgreichen Verbindungsaufbau erforderlich sind, wie `HostName`, +sind viele andere Optionen rein optional. + +Um einen Überblick über alle möglichen Optionen zu bekommen, kannst du [`man ssh_config`](https://linux.die.net/man/5/ssh_config) verwenden oder diesen [guide](https://www.ssh.com/academy/ssh/config) lesen. +Die genaue Anzahl der unterstützten Optionen hängt ausschließlich von deinem installierten SSH-Client ab. + +### Formatierung + +Der Inhalt hier entspricht einem Host-Abschnitt in einer SSH-Konfigurationsdatei. +Beachte, dass du den `Host`-Schlüssel nicht explizit definieren musst, da dies automatisch gemacht wird. + +Wenn du mehr als einen Host-Abschnitt definieren willst, z. B. bei abhängigen Verbindungen wie einem Proxy-Jump-Host, der von einem anderen Config-Host abhängt, kannst du hier auch mehrere Host-Einträge definieren. XPipe wird dann den ersten Host-Eintrag starten. + +Du musst keine Formatierung mit Leerzeichen oder Einrückung vornehmen, das ist für die Funktion nicht erforderlich. + +Beachte, dass du darauf achten musst, alle Werte in Anführungszeichen zu setzen, wenn sie Leerzeichen enthalten, sonst werden sie falsch übergeben. + +### Identitätsdateien + +Beachte, dass du hier auch eine `IdentityFile` Option angeben kannst. +Wenn diese Option hier angegeben wird, werden alle anderen Optionen für die schlüsselbasierte Authentifizierung weiter unten ignoriert. + +Wenn du dich für eine Identitätsdatei entscheidest, die im XPipe-Git-Vault verwaltet wird, kannst du das ebenfalls tun. +XPipe erkennt gemeinsam genutzte Identitätsdateien und passt den Dateipfad automatisch auf jedem System an, auf dem du den Git-Depot geklont hast. diff --git a/lang/proc/texts/sshOptions_en.md b/lang/proc/texts/sshOptions_en.md new file mode 100644 index 000000000..245e3326b --- /dev/null +++ b/lang/proc/texts/sshOptions_en.md @@ -0,0 +1,27 @@ +## SSH configurations + +Here you can specify any SSH options that should be passed to the connection. +While some options are essentially required to successfully establish a connection, such as `HostName`, +many other options are purely optional. + +To get an overview over all possible options, you can use [`man ssh_config`](https://linux.die.net/man/5/ssh_config) or read this [guide](https://www.ssh.com/academy/ssh/config). +The exact amount of supported options purely depends on your installed SSH client. + +### Formatting + +The content here is equivalent to one host section in an SSH config file. +Note that you don't have to explicitly define the `Host` key, as that will be done automatically. + +If you intend to define more than one host section, e.g. with dependent connections such as a proxy jump host that depends on another config host, you can define multiple host entries in here as well. XPipe will then launch the first host entry. + +You don't have to perform any formatting with whitespace or indentation, this is not needed for it to function. + +Note that you must take care of quoting any values if they contain spaces, otherwise they will be passed incorrectly. + +### Identity files + +Note that you can also specify an `IdentityFile` option in here. +If this option is specified in here, any otherwise specified key-based authentication option later down below will be ignored. + +If you choose to refer to an identity file that is managed in the XPipe git vault, you can do so as well. +XPipe will detect shared identity files and automatically adapt the file path on every system you cloned the git vault on. diff --git a/lang/proc/texts/sshOptions_es.md b/lang/proc/texts/sshOptions_es.md new file mode 100644 index 000000000..a6eeb083c --- /dev/null +++ b/lang/proc/texts/sshOptions_es.md @@ -0,0 +1,27 @@ +## Configuraciones SSH + +Aquí puedes especificar cualquier opción SSH que deba pasarse a la conexión. +Aunque algunas opciones son esencialmente necesarias para establecer con éxito una conexión, como HostName