pax_global_header00006660000000000000000000000064151426442660014524gustar00rootroot0000000000000052 comment=2644d8852d1163b3d87c2d353653fe69fd77ae80 backintime-1.6.1/000077500000000000000000000000001514264426600136375ustar00rootroot00000000000000backintime-1.6.1/.codespellrc000066400000000000000000000033531514264426600161430ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2023 Christian Buhtz # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory # go to # and . [codespell] # Folders and files to skip skip = .codespellrc,*.po,Makefile,*.desktop,.git,__pycache__,*.pyc,#*#,languages.py,_build,TRANSLATIONS,./doc/manual/html,mkdocs.yml,configure,.pytest_cache # Print N lines of surrounding context context = 1 # Check hidden files also (empty means True) check-hidden= # Print number of errors as last line on stderr (empty means True) count= # Dictionaries to use (default: "clear,rare"). Current: all. builtin = clear,rare,informal,usage,code,names,en-GB_to_en-US # Allowed (ignored) words ignore-words-list=master,whitelist,manuel,dum,assertIn,OIS,deque,ARCHIV # Allowed (ignored) words in URLs and URIs uri-ignore-words-list=mitre,Archiv # Good to know about allowed/ignored words: # Codespell acts a bit unusual when it comes to case-sensitivity. # By default the word "Manuel" is an error and codespell recommends to # modify it into "Manual". To allow this German name "Manuel" we have to # add "manual" (lower case!) to the "ignore-words-list". The upper-case # version do not work. # See: https://github.com/codespell-project/codespell/issues/3210 # Simulate "# noqa" and ignore all lines with "# codespell-ignore" at the end. # Credits: https://github.com/codespell-project/codespell/issues/1212#issuecomment-1721152455 ignore-regex=.*# codespell-ignore$ backintime-1.6.1/.github/000077500000000000000000000000001514264426600151775ustar00rootroot00000000000000backintime-1.6.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001514264426600173625ustar00rootroot00000000000000backintime-1.6.1/.github/ISSUE_TEMPLATE/bug.yml000066400000000000000000000020761514264426600206670ustar00rootroot00000000000000name: Bug report description: Submit a bug report body: - type: markdown attributes: value: | 👉 Ask **support questions** in the GNU/Linux community or on our [mailing list](https://mail.python.org/mailman3/lists/bit-dev.python.org). Please respect the limited resources of the maintenance team. 👉 Provide the output of the console command `backintime --diagnostics`, to help us diagnose the problem quickly. 👉 Please specify as precisely as you can the package or installation source where you got _Back In Time_ from. 👉 As an **alternative** feel free to use our [mailing list](https://mail.python.org/mailman3/lists/bit-dev.python.org) for any topic related to _Back In Time_. - type: textarea attributes: label: "Describe the problem, feature or ask a question:" description: "Please remember that this project is maintained by volunteers in their free time – human beings just like you – so we kindly ask for your understanding and constructive feedback as we work to address reported issues." backintime-1.6.1/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000341514264426600213470ustar00rootroot00000000000000blank_issues_enabled: false backintime-1.6.1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000003101514264426600207720ustar00rootroot00000000000000AI-generated content is strictly prohibited. Accounts submitting such material will be reported for abuse to Microsoft GitHub . Consider adding a CHANGELOG entry. Run "codespell" to check for typos. backintime-1.6.1/.github/REUSE.toml000066400000000000000000000011721514264426600167600ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or go to # and . # See https://reuse.software/faq/#bulk-license version = 1 [[annotations]] path = ["*.md", "**/*.yml"] SPDX-License-Identifier = "CC0-1.0" SPDX-FileCopyrightText = "© 2022 Back In Time" backintime-1.6.1/.gitignore000066400000000000000000000023361514264426600156330ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See folder LICENSES or # go to # and . # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # editor backup and temp files *~ *.sic *.swp \#*\# .\#* # packaging *.deb debian/debhelper-build-stamp debian/*.debhelper debian/*.debhelper.log debian/*.substvars debian/files debian/backintime-common debian/backintime-gnome debian/backintime-kde debian/backintime-kde4 debian/backintime-notify debian/backintime-qt # compressed files *.gz # Compiled translations *.mo # Makefile common/Makefile qt/Makefile # coveralls.io status .coverage # coverage result files (raw data and reports) # .coverage # already ignored, see above **/htmlcov/** # sphinx doc build common/doc-dev/_build/doctrees common/doc-dev/_build/html # MkDocs doc/manual/html/ # PyCharm IDE project settings .idea # Linter configuration .flake8 backintime-1.6.1/.readthedocs.yaml000066400000000000000000000026421514264426600170720ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2016 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or # go to # and . # # This is the configuration file for the Read the Docs service. # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details. # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-22.04 tools: python: "3" jobs: # Workaround: See PR #1554 for details. # When migrating to use a pyprojects.toml file switch from this # workaround to the use of "python: install: extra_requirements..." # See also: https://docs.readthedocs.io/en/stable/config-file/v2.html#packages post_create_environment: - python -m pip install sphinx_rtd_theme # Build documentation in the docs/ directory with Sphinx sphinx: configuration: common/doc-dev/conf.py # fail_on_warning: true # We recommend specifying your dependencies to enable reproducible builds: # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html # python: # install: # - method: pip # path: . # extra_requirements: # - foo backintime-1.6.1/.travis.yml000066400000000000000000000046131514264426600157540ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # # TravisCI (https://travis-ci.org) configuration file os: linux # Support End of "Focal" (20.04 LTS) was April 2025 # dist: focal # Support End of "Jammy" (22.04 LTS) is April 2027 # dist: jammy # Support End of "noble" (24.04 LTS) is April 2029 dist: noble language: python arch: - amd64 python: - "3.11" - "3.12" - "3.13" - "3.14" addons: # add localhost to known_hosts to prevent ssh unknown host prompt during unit tests ssh_known_hosts: localhost env: # TravisCI support said this could prevent errors from "make". PYTHONUNBUFFERED=1 before_install: # disable mongodb as we don't need it and it sometimes temporary fails # https://github.com/travis-ci/travis-ci/issues/4937#issuecomment-149289729 - sudo rm -f /etc/apt/sources.list.d/mongodb*.list - sudo apt-key del 90CFB1F5 - sudo apt-get -qq update # install screen, and util-linux (provides flock) for test_sshtools - sudo apt-get install -y sshfs screen util-linux libdbus-1-dev - sudo apt-get install -y ruby rubygems asciidoctor encfs gocryptfs - sudo gem install asciidoctor # jobs: # exclude: # - python: "3.11" # - python: "3.12" # - python: "3.13" install: - pip install -U pip - pip install pylint ruff flake8 codespell pyfakefs keyring - pip install pyqt6 dbus-python # add ssh public / private key pair to ensure user can start ssh session to localhost for tests - ssh-keygen -b 2048 -t rsa -f /home/travis/.ssh/id_rsa -N "" - cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # start ssh-agent so that we can add private keys - eval `ssh-agent -s` script: # Add linter versions to build log - ruff --version - flake8 --version - pylint --version - codespell --version # compile all files - ensure that syntax is correct - python -m compileall common common/test common/plugins qt qt/test qt/plugins # common: Install - cd common - ./configure - make - sudo make install # common: test - pytest --verbose # qt: Install - cd .. - cd qt - ./configure - make # qt: Test - pytest --verbose # Codespell on whole repo - cd .. - codespell backintime-1.6.1/AUTHORS000066400000000000000000000005501514264426600147070ustar00rootroot00000000000000Oprea Dan Bart de Koning Richard Bailey Germar Reitze Taylor Raack Christian Buhtz Michael Büker Jürgen Altfeld …as well as many others involved, whose contributions make this project possible and help it continue to grow and evolve. backintime-1.6.1/CHANGES000066400000000000000000002136351514264426600146440ustar00rootroot00000000000000Back In Time Version 1.6.1 (2026-02-10) * Fixed: SSH-Key selector widget handle binary keys, missing but configured keys (#2399, #2400) * Fixed: SSH-Key selector widget is more robust on unexpected edge cases (#2399, #2400) * Fixed: Install backintime-config man page in correct location Version 1.6.0 (2026-02-08) * Changed: **Breaking** Disable EncFS for creation of new backup profiles (#2315, #1734) * Changed: **Breaking** A "snapshot" now is a "backup" (#1929) * Changed: **Breaking** Deprecated and removed make targets: "test", "test-v", "unittest", "unittest-v" * Changed: Manpage backintime-config moved from section 1 to 5 (#1773) * Changed: New dependency "bash" for root mode starter script "backintime-qt_polkit" (#2328) * Changed: New dependency (runtime GUI) to "python3-pyqt6.qtsvg" for loading SVG icons (#1961) * Changed: Disable scheduling widget in GUI if cron/crontab is missing (#2245, @m4rcu5 Marcus von Dam) * Changed: Expert Options replaced two checkboxes with single widget to configure symlink copying behavior (#1652) * Changed: "Repeatedly (anacron)" scheduling behave consistent. Reversed minor bug introduced with 060324e (#1791) in 1.5.3 (#2250) * Changed: Stricter permissions (600) for fileinfo.bz2 and takesnapshot.log.bz2 (#2235) * Changed: Unlocking ssh-agent use "force" instead of "prefer" for SSH_ASKPASS_REQUIRE (#2170) (@daviewales) * Changed: Stop passing window ID when inhibiting suspend via D-Bus power manager (#2084) * Changed: Reorder DBUS service provider list for suspend mode inhibition (#2084) * Changed: Man pages generated from AsciiDoc, except backintime-config (#2085) * Changed: Deprecate command "benchmark-cipher" (#2120) * Changed: Deprecate command "snapshots-path" (#2130) * Changed: Deprecate commands "snapshots-list", "snapshots-list-path", "last-snapshots" and "last-snapshot-path" (#2130) * Changed: Deprecate command "smart-remove" (#2124) * Changed: Deprecate command "backup-job" (#2124) * Changed: Deprecate command "remove-and-do-not-ask-again" (#2124) * Changed: Deprecate command "decode" (#2124) * Changed: Deprecate flag-like command aliases (e.g. "--backup" for "backup") (#2124) * Changed: Deprecate argument flag "--profile-id" (#2125) * Changed: Deprecate argument flag "--share-path" (#2124) * Changed: Deprecate use of SSH Cipher (#2143) * Changed: Prefer ed25519 SSH keys (if present) for new created profiles (#2094) * Changed: Generating new SSH key will use default key type provided by ssh-keygen (#2194) * Changed: Open man page and changelog in a text dialog * Changed: Minimum PyLint version increased to 4.0.0 * Added: Language Georgian (ka) * Added: Gocryptfs for local encrypted profiles (#1897, #1734, @germar, @daviewales) * Added: Dialog to suggest commonly used files/dirs/patterns for backup exclusion (#2309) * Added: Systray icon can be forced to Dark or Light * Added: Application logo and symbolic systray icon (#1961, Gregory Deseck @gregorydk) * Added: Root mode indicator in status bar (#1964) * Added: Option to not using an explicit SSH key file. In consequence this supports extern key agents and SSH clients own configuration (#1146) * Added: SSH-Key selector widget in Manage profiles dialog (#1146, #2094, #2095, #2275 @m4rcu5 Marcus van Dam) * Added: "ETA" value in status bar (#2101) * Added: Shutdown confirmation dialog (#2102) (Huaide Jiang @LatiosInAltoMare) * Added: Check and warn if include list entries do not exists in backup source (#1586) (@rafaelhdr) * Added: Asciidoctor as build dependence (#2085) * Added: Command "show" to replace "snapshots-list", "snapshots-list-path", "last-snapshots" and "last-snapshot-path" (#2130) * Added: Command "prune" to replace "smart-remove" (#2124) * Added: Flag "--background" for command "backup" to replace command "backup-job" (#2124) * Added: Flag "--skip-confirmation" for command "remove" to replace command "remove-and-do-not-ask-again" (#2124) * Added: Flag "--profile" accept ID's beside names only (#2125) * Added: Flag "-p" as alias for "--profile" (#2125) * Added: "Less storage space" threshold to warn the user (#2110) (@fest6) * Added: Remember size and position of Manage profiles dialog * Added: User-callback editor offer a default script in case no script exists (#1331) * Removed: **Breaking** Drop Python support for version 3.9 & 3.10 (#2129) * Removed: Stop using QWindow.winId() (#2084) * Removed: UI translation in Bosnian, Thai, and Occidental/Interlingue (#1914) * Removed: LICENSE file in favor of LICENSES directory and LICENSES.md file * Removed: SSH Cipher configuration in Manage profiles dialog (#2143) * Fixed: Crash in config restore dialog * Fixed: Consider symbolic icons as fallbacks (#2345, #2289) * Fixed: Warn users and prevent backups to exFAT volumes due to lack of hardlink support (#2337) * Fixed: Show proper message to users when root mode fails due to inactive or missing polkit agent (#2328, Derek Veit @DerekVeit) * Fixed: Crash in Compare snapshots dialog (aka Snapshots dialog) when comparing/diff two backups (#2327 Michael Neese @madic-creates) * Fixed: File view and Compare Backups dialog now open the clicked item correctly even with multiple selection or single-click-to-open enabled (#2330) * Fixed: Crash in Compare snapshots dialog (aka Snapshots dialog) when comparing/diff two backups (#2327 Michael Neese @madic-creates) * Fixed: Enforce UTF-8 encoding in takesnapshot.log and some other files (#2298) * Fixed: Attribute error about missing 'cbCopyUnsafeLinks' (#2279) * Fixed: Use LC_ALL instead of LC_TIME to set the locale * Fixed: Optimize subparsers and usage output (#2132) * Fixed: Re-design about dialog (#1936) * Fixed: Stop waking up monitor when inhibit suspend on backup starts (#714, #1090) * Fixed: Avoid shutdown confirmation dialog on Budgie and Cinnamon desktop environments (#788) * Fixed: Crash in "Manage profiles" dialog when using "qt6ct" (#2128) * Fixed: **Breaking** Systray process no longer exposes sensitive backup profile information when the desktop session belongs to another user (#2237, reported and co-authored by @samo-sk) * Fixed: Allow in BITs root-mode opening URLs in extern browse Version 1.5.6 (2025-10-05) * Fixed: Always use 0 as window ID value when inhibiting suspend via D-Bus power manager (#2084, #2268, #2192) * Fixed: Crash in "Manage profiles" dialog when using "qt6ct" (#2128) * Fixed: Open online changelog if local CHANGES file is missing (#2266) * Fixed: Disable opening browser (e.g. project website) in root-mode Version 1.5.5 (2025-06-05) * Fixed: Unlocking SSH keys with passphrases on new created profiles (#2164) (@davidfjoh) Version 1.5.4 (2025-03-24) * Breaking Change: Auto-remove rules "Free inodes" and "Free space" disabled by default in new created profiles (#1976) * Changed: Completed license information to conform to REUSE.software and SPDX standards. * Changed: More clear and intense warning about EncFS deprecation and removal (#1904) * Changed: Updated desktop entry files * Changed: Move several values from config file into new introduce state file ($XDG_STATE_HOME/backintime.json) * Fix!: Smart-remove rule "Keep one snapshots per week or the last week" use calendar weeks * Fix: Exclude patterns are now case-sensitive when added (#2040) * Fix: The width of the fourth column in files view is now saved * Fix: Snapshot compare copy symlink as symlink (#1902) (Peter Sevens @sevens) * Fix: Crash when comparing a snapshot with a symlink pointing to a nonexistent target (Peter Sevens @sevens) * Fix: Crash (KeyError) opening language setup dialog with unknown locale/language * Doc: Remove & Retention (formally known as Auto-/Smart-Remove) with improved GUI and user manual section (#2000) * Feature: Open user manual (local if available otherwise online) via Help menu * Feature: Toolbar context menu to display the buttons in different combinations with icons and text (#1105, #2002) (Samuel Moore @s4moore) * Feature: Add offset minutes to hourly schedules (David Gibbs @fallingrock) Version 1.5.3 (2024-11-13) * Doc: User manual (build with MkDocs) (#1838) (Kosta Vukicevic @stcksmsh) * Doc: User-callback topic in user manual (#1659) * Feature: Support language Interlingua (Occidental) * Feature: Warn if destination directory is formatted as NTFS (#1854) (David Gibbs @fallingrock) * Breaking Change: Minimal Python version 3.9 required (#1731) * Breaking Change: Auto migration of config version 4 or lower not longer supported (#1857) * Fix: Prevent duplicates in Exclude/Include list of Manage Profiles dialog * Fix: Fix Qt segmentation fault when canceling out of unconfigured BiT (#1095) (Derek Veit @DerekVeit) * Fix: Correct global flock fallbacks (#1834) (Timothy Southwick @NickNackGus) * Fix: Use SSH key password only if it is valid, otherwise request it from user (#1852) (David Wales @daviewales) * Feature: Support fcron (#610) * Feature: User message about release candidate (#1906) * Refactor: General tab and its Schedule section * Refactor: Own module for Manage Profiles dialog and separate Generals tab code (#1865) * Refactor: Remove class OrderedSet * Refactor: Remove os.system() from class Execute * Refactor: Systray notifications send utilize DBUS instead of notify-send (#1156) (Felix Stupp @Zocker1999NET) * Refactor!: Remove unused config field "user_callback.no_logging" (#1887) * Refactor!: Remove eCryptFS check for home folder (#1855) * Dependency: Remove libnotify-bin (notify-send) (#1156) * Dependency: PyFakeFS minimal version 5.6 (#1911) * Build: Replace "pycodestyle" linter with "flake8" (#1839) Version 1.5.2 (2024-08-06) * Fix: Ensure crontab with ending newline (#781) * Fix(translation): Correct corrupt translated strings in Basque, Islandic and Spanish causing application crashes (#1828) * Build(translation): Language helper script processing syntax checks on po-files Version 1.5.1 (2024-07-27) * Fix: Use correct port to ping SSH Proxy (#1815) Version 1.5.0 (2024-07-26) * Dependency: Migration to PyQt6 * Breaking Change: EncFS deprecation warning (#1735, #1734) * Breaking Change: GUI started with --debug does no longer add --debug to the crontab for scheduled profiles. Use the new "enable logging for debug messages" in the 'Schedule' section of the 'Manage profiles' GUI instead. * Feature: Warn if Cron is not running (#1747) * Feature: Profile and GUI allow to activate debug output for scheduled jobs by adding '--debug' to crontab entry (#1616, contributed by @stcksmsh Kosta Vukicevic) * Feature: Support SSH proxy (jump) host (#1688) (@cgrinham, Christie Grinham) * Feature: Support rsync '--one-file-system' in Expert Options (#1598) * Feature: "*-dev" version strings contain last commit hash (#1637) * Fix: Global flock fallback to single-user mode if insufficient permissions (#1743, #1751) * Fix: Fix Qt segmentation fault with uninstall ExtraMouseButtonEventFilter when closing main window (#1095) * Fix: Names of weekdays and months translated correct (#1729) * Fix: Global flock for multiple users (#1122, #1676) * Fix bug: "Backup folders" list does reflect the selected snapshot (#1585) (@rafaelhdr Rafael Hurpia da Rocha) * Fix: Validation of diff command settings in compare snapshots dialog (#1662) (@stcksmsh Kosta Vukicevic) * Fix bug: Open symlinked folders in file view (#1476) * Fix bug: Respect dark mode using color roles (#1601) * Fix: "Highly recommended" exclusion pattern in "Manage Profile" dialog's "Exclude" tab show missing only (#1620) * Fix bug: `make install` ignored $(DEST) in file migration part (#1630) * Removed: Context menu in LogViewDialog (#1578) * Removed: Field "filesystem_mount" and "snapshot_version" in "info" file (#1684) * Refactor: Replace Config.user() with getpass.getuser() (#1694) * Chore!: Remove "debian" folder (#1548) * Build: Enable several PyLint rules (#1755, #1766) * Build: Add AppStream meta data (#1642) * Build: PyLint unit test is skipped if PyLint isn't installed, but will always run on TravisCI (#1634) * Build: Git commit hash is presevered while "make install" (#1637) * Build: Fix bash-completion symlink creation while installing & adding --diagnostics (#1615) * Build: TravisCI use PyQt (except arch "ppc64le") Version 1.4.3 (2024-01-30) * Feature: Exclude 'SingletonLock' and 'SingletonCookie' (Discord) and 'lock' (Mozilla Firefox) files by default (part of #1555) * Work around: Relax `rsync` exit code 23: Ignore instead of error now (part of #1587) * Feature (experimental): Add new snapshot log filter `rsync transfer failures (experimental)` to find them easier (they are normally not shown as "error"). This feature is experimental because it is based on hard-coded error message strings in the rsync source code and may possibly not find all rsync messages or show false positives. * Fix bug: 'qt5_probing.py' hangs when BiT is run as root and no user is logged into a desktop environment (#1592 and #1580) * Fix bug: Launching BiT GUI (root) hangs on Wayland without showing the GUI (#836) * Improve: Launcher for BiT GUI (root) does not enforce Wayland anymore but uses same settings as for BiT GUI (userland) (#1350) * Fix bug: Disabling suspend during taking a backup ("inhibit suspend") hangs when BiT is run as root and no user is logged into a desktop environment (#1592) * Change of semantics: BiT running as root never disables suspend during taking a backup ("inhibit suspend") even though this may have worked before in BiT <= v1.4.1 sometimes (required to fix #1592) * Fix bug: RTE: module 'qttools' has no attribute 'initate_translator' with encFS when prompting the user for a password (#1553). * Fix bug: Schedule dropdown menu used "minutes" instead of "hours". * Fix bug: Unhandled exception "TypeError: 'NoneType' object is not callable" in tools.py function __log_keyring_warning (#820). Logging thread removed and logger module correctly initialized as fix. Is "Heisenbug" so 100 % retesting was not possible. * Build: Use PyLint in unit testing to catch E1101 (no-member) errors. * Build: Activate PyLint warning W1401 (anomalous-backslash-in-string). * Build: Add codespell config. * Build: Allow manual specification of python executable (--python=PYTHON_PATH) in common/configure and qt/configure * Build: All starter scripts do use an absolute path to the python executable by default now via common/configure and qt/configure (#1574) * Build: Install dbus configuration file to /usr/share not /etc (#1596) * Build: `configure` does delete old installed files (`qt4plugin.py` and `net.launchpad.backintime.serviceHelper.conf`) that were renamed or moved in a previous release (#1596) * Translation: Minor modifications in source strings and updating language files. * Refactor: Solved circular dependency between tools.py and logger.py to fix #820 * Improved: qtsystrayicon.py, qt5_probing.py, usercallbackplugin.py and all parts of app.py do now also use "backintime" as logging namespace in the syslog to ensure complete log output with `journalctl | grep -i backintime` Version 1.4.1 (2023-10-01) * Dependency: Add "qt translations" to GUI runtime dependencies (#1538). * Build: Unit tests do generically ignore all instead of well-known warnings now (#1539). * Build: Warnings about missing Qt translation now are ignored while testing (#1537). * Fix bug: GUI didn't start when "show hidden files" button was on (#1535). Version 1.4.0 (2023-09-14) * Project: Renamed branch "master" to "main" and started "gitflow" branching model. * Refactor: Renamed qt4plugin.py to systrayiconplugin.py (we are using Qt5 for years now ;-) * Refactor: Removed unfinished feature "Full system backup" (#1526) * Fix bug: AttributeError: can't set attribute 'showHiddenFiles' in app.py (#1532) * Fix bug: Check SSH login works on machines with limited commands (#1442) * Fix bug: Missing icon in SSH private key button (#1364) * Fix bug: Master issue for missing or empty system-tray icon (#1306) * Fix bug: System-tray icon missing or empty (GUI and cron) (#1236) * Fix bug: Improve KDE plasma icon compatibility (#1159) * GUI Change: View last (snapshot) log button in GUI uses "document-open-recent" icon now instead of "document-new" (#1386) * Fix bug: Unit test fails on some machines due to warning "Ignoring XDG_SESSION_TYPE=wayland on Gnome..." (#1429) * Fix bug: Generation of config-manpage caused an error with Debian's Lintian (#1398). * Fix bug: Return empty list in smartRemove (#1392, Debian Bug Report 973760) * Fix bug: Taking a snapshot reports `rsync` errors now even if no snapshot was taken (#1491) * Fix bug: takeSnapshot() recognizes errors now by also evaluating the rsync exit code (#489) Fixes related problem: Killing `rsync` was not handled gracefully (by ignoring the rsync exit code) * Fix bug: The error user-callback is now always called if an error happened while taking a snapshot (#1491) * Fix bug: D-Bus serviceHelper error "LimitExceeded: Maximum length of command line reached (100)": Max command length is now 120 instead of 100 (#1027) * Feature: Introduce new error codes for the "error" user callback (as part of #1491): 5: Error while taking a snapshot. 6: New snapshot taken but with errors. * Feature: The `rsync` exit code is now contained in the snapshot log (part of #489). Example: [E] Error: 'rsync' ended with exit code -9 (negative values are signal numbers, see 'kill -l') * Fix bug: Treat rsync exit code 24 as INFO instead of ERROR (#1506) * Breaking change: Minimal Python version 3.8 required (#1358). * Removed: Handling and checking of user group "fuse" (#1472). * Feature: Exclude /swapfile by default (#1053) * Feature: Rearranged menu bar and its entries in the main window (#1487, #1478). * Feature: Configure user interface language via config file and GUI. * Documentation: Removed outdated docbook (#1345). * Testing: TravisCI now can use dbus * Build: Introduced .readthedocs.yaml as asked by ReadTheDocs.org (#1443). * Dependency: The oxygen icons should be installed with the BiT Qt GUI since they are used as fallback in case of missing icons * Fix bug: Add support for ChainerBackend class as keyring which iterates over all supported keyring backends (#1410) * Translation: Strings to translate now easier to understand for translators (#1448, #1457, #1462, #1465). * Translation: Improved completeness of translations and additional modifications of source strings (#1454, #1512) * Translation: Plural forms support (#1488). * Removed: Translation in Canadian English, British English and Javanese (#1455). * Added: Translation in Persian and Vietnamese (#1460). * Added: Message to users (after 10 starts of BIT Gui) to motivate them contributing translations (#1473). Version 1.3.3 (2023-01-04) * Feature: New command line argument "--diagnostics" to show helpful info for better issue support (#1100) * GUI change: Remove Exit button from the toolbar (#172) * GUI change: Define accelerator keys for menu bar and tabs, as well as toolbar shortcuts (#1104) * Desktop integration: Update .desktop file to mark Back In Time as a single main window program (#1258) * Feature: Write all log output to stderr; do not pollute stdout with INFO and WARNING messages anymore (#1337) * Fix bug: RTE "reentrant call inside io.BufferedWriter" in logFile.flush() during backup (#1003) * Fix bug: Incompatibility with rsync 3.2.4 or later because of rsync's "new argument protection" (#1247). Deactivate "--old-args" rsync argument earlier recommended to users as a workaround. * Fix bug: DeprecationWarnings about invalid escape sequences. * Fix bug: AttributeError in "Diff Options" dialog (#898) * Fix bug: Settings GUI: "Save password to Keyring" was disabled due to "no appropriate keyring found" (#1321) * Fix bug: Back in Time did not start with D-Bus error "dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NameHasNoOwner: Could not get owner of name 'net.launchpad.backintime.serviceHelper': no such name" (fixes client-side part of #921 - system D-Bus part of the Udev serviceHelper is still under investigation). * Fix bug: Avoid logging errors while waiting for a target drive to be mounted (#1142, #1143, #1328) * Fix bug: [Arch Linux] AUR pkg "backintime-git": Build tests fails and installation is aborted (#1233, fixed with #921) * Fix bug: Wrong systray icon showing in Wayland (#1244) * Documentation update: Correct description of profile.schedule.time in backintime-config manpage (#1270) * Translation update: Brazilian Portuguese (#1267) * Translation update: Italian (#1110, #1123) * Translation update: French (#1077) * Testing: Fix a test fail when dealing with an empty crontab (#1181) * Testing: Fix a test fail when dealing with an empty config file (#1305) * Testing: Skip "test_quiet_mode" (does not work reliably) * Testing: Improve "test_diagnostics_arg" (introduced with #1100) to no longer fail when JSON output was mixed with logging output (part of #921, fixes #1233) * Testing: Numerous fixes and extensions to testing (#1115, #1213, #1279, #1280, #1281, #1285, #1288, #1290, #1293, #1309, #1334) Version 1.3.2 (2022-03-12) * Fix bug: Tests no longer work with Python 3.10 (https://github.com/bit-team/backintime/issues/1175) Version 1.3.1 (2021-07-05) * bump version, forgot to push branch to Github before releasing Version 1.3.0 (2021-07-04) * Merge PR: Fix FileNotFoundError exception in mount.mounted, Thanks tatokis (https://github.com/bit-team/backintime/pull/1157) * Merge PR: qt/plugins/notifyplugin: Fix setting self.user, not local variable, Thanks Zocker1999NET (https://github.com/bit-team/backintime/pull/1155) * Merge PR: Use Link Color instead of lightGray as not to break theming, Thanks newhinton (https://github.com/bit-team/backintime/pull/1153) * Merge PR: Match old and new rsync version format, Thanks TheTimeWalker (https://github.com/bit-team/backintime/pull/1139) * Merge PR: 'TempPasswordThread' object has no attribute 'isAlive', Thanks FMeinicke (https://github.com/bit-team/backintime/pull/1135) * Merge PR: Keep permissions of an existing mountpoint from being overridden, Thanks bentolor (https://github.com/bit-team/backintime/pull/1058) * Fix bug: YEAR missing in config (https://github.com/bit-team/backintime/issues/1023) * Fix bug: SSH module didn't send identification string while checking if remote host is available (https://github.com/bit-team/backintime/issues/1030) Version 1.2.1 (2019-08-25) * Fix bug: TypeError in backintime.py if mount failed while running a snapshot (https://github.com/bit-team/backintime/issues/1005) Version 1.2.0 (2019-04-27) * Fix bug: Exit code is linked to the wrong status message (https://github.com/bit-team/backintime/issues/906) * minor changes to allow running BiT inside Docker (https://github.com/bit-team/backintime/pull/959) * Fix bug: AppName showed 'python3' instead of 'Back In Time' (https://github.com/bit-team/backintime/issues/950) * Fix bug: configured cipher is not used with all ssh-commands (https://github.com/bit-team/backintime/issues/934) * remove progressbar on systray icon until BiT has it's own icon (https://github.com/bit-team/backintime/issues/902) * Fix bug: 'make test' fails because local SSH server is running on non-standard port (https://github.com/bit-team/backintime/issues/945) * clarify 'nocache' option (https://github.com/bit-team/backintime/issues/857) * create a config-backup in root dir if backup is encrypted (https://github.com/bit-team/backintime/issues/556) * Fix bug: 23:00 is missing in the list of every day hours (https://github.com/bit-team/backintime/issues/736) * Fix bug: ssh-agent output changed (https://github.com/bit-team/backintime/issues/840) * remove unused and undocumented userscript plugin * Fix bug: exception on making backintime folder world writable (https://github.com/bit-team/backintime/issues/812) * Fix bug: stat free space for snapshot folder instead of backintime folder (https://github.com/bit-team/backintime/issues/733) * add contextmenu for logview dialog which can copy, exclude and decode lines * move progressbar under statusbar * Fix bug: backintime root crontab doesn't run; missing line-feed 0x0A on last line (https://github.com/bit-team/backintime/issues/781) * Fix bug: IndexError in inhibitSuspend (https://github.com/bit-team/backintime/issues/772) * alleviate default exclude [Tt]rash* (https://github.com/bit-team/backintime/issues/759) * enable high DPI scaling (https://github.com/bit-team/backintime/issues/732) * Fix bug: polkit CheckAuthorization: race condition in privilege authorization (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7572) * Fix bug: OSError when running backup-job from systemd (https://github.com/bit-team/backintime/issues/720) * Smart Remove try to keep healthy snapshots (https://github.com/bit-team/backintime/issues/703) * Fix critical bug: restore filesystem-root without 'Full rsync mode' with ACL and/or xargs activated broke whole system (https://github.com/bit-team/backintime/issues/708) * Fix bug: use current folder if no file is selected in files view (https://github.com/bit-team/backintime/issues/687, https://github.com/bit-team/backintime/issues/685) * Fix bug: don't reload profile after editing profile name (https://github.com/bit-team/backintime/issues/706) * Fix bug: Exception in FileInfo * ask for restore-to path before confirm (https://github.com/bit-team/backintime/issues/678) * fix 'Back in Time (root)' on wayland (https://github.com/bit-team/backintime/issues/640) * sort int values in config numerical instead if alphabetical (https://github.com/bit-team/backintime/issues/175#issuecomment-272941811) * set timestamp directly after new snapshot (https://github.com/bit-team/backintime/issues/584) * add shortcut CTRL+H for toggle show hidden files to fileselect dialog (https://github.com/bit-team/backintime/issues/378) * add 'Edit user-callback' dialog * Fix bug: failed to restore suid permissions (https://github.com/bit-team/backintime/issues/661) * redesign restore menu (https://github.com/bit-team/backintime/issues/661) * Fix bug: on remount user-callback got called AFTER trying to mount (https://github.com/bit-team/backintime/issues/654) * add ability to disable SSH command- and ping-check (https://github.com/bit-team/backintime/issues/647) * enable bwlimit for local profiles (https://github.com/bit-team/backintime/issues/646) * import remote host-key into known_hosts from Settings * copy public SSH key to remote host from Settings * create a new SSH key from Settings * Fix bug: confirm restore dialog has no scroll bar (https://github.com/bit-team/backintime/issues/625) * Fix bug: DEFAULT_EXCLUDE not deletable (https://github.com/bit-team/backintime/issues/634) * rename debian package from backintime-qt4 into backintime-qt * rename paths and methods from *qt4* into *qt* * rename executable backintime-qt4 into backintime-qt * new config version 6, rename qt4 keys into qt, add new domain for schedule * check crontab entries on every GUI startup (https://github.com/bit-team/backintime/issues/129) * start a new ssh-agent instance only if necessary * add cli command 'shutdown' (https://github.com/bit-team/backintime/issues/596) * Fix bug: GUI status bar unreadable (https://github.com/bit-team/backintime/issues/612) * Fix bug: udev schedule not working (https://github.com/bit-team/backintime/issues/605) * add cli command 'smart-remove' * make LogView and Settings Dialog non-modal (https://github.com/bit-team/backintime/issues/608) * Fix bug: decode path spooled from /etc/mtab (https://github.com/bit-team/backintime/pull/607) * Fix bug: in snapshots.py, gives more helpful advice if a lock file is present that shouldn't be. (https://github.com/bit-team/backintime/issues/601) * port to Qt5/pyqt5 (https://github.com/bit-team/backintime/issues/518) * Fix bug: Fail to create remote snapshot path with spaces (https://github.com/bit-team/backintime/issues/567) * Fix bug: broken new_snapshot can run into infinite saveToContinue loop (https://github.com/bit-team/backintime/issues/583) * Recognize changes on previous runs while continuing new snapshots * Fix bug: udev schedule didn't work with LUKS encrypted drives (https://github.com/bit-team/backintime/issues/466) * Add pause, resume and stop function for running snapshots (https://github.com/bit-team/backintime/issues/474, https://github.com/bit-team/backintime/issues/195) * Fix bug: sshMaxArg failed on none default ssh port (https://github.com/bit-team/backintime/issues/581) * Fix bug: failed if remote host send SSH banner (https://github.com/bit-team/backintime/issues/581) * Fix bug: incorrect handling of IPv6 addresses (https://github.com/bit-team/backintime/issues/577) * use rsync to save permissions * replace os.system calls with subprocess.Popen * automatically refresh log view if a snapshot is currently running * Fix bug: Snapshot Log View freeze on big log files (https://github.com/bit-team/backintime/issues/456) * Fix bug: 'inotify_add_watch failed: file or directory not found' after deleting snapshot * remove dependency for extended 'find' command on remote host * make full-rsync mode default, remove the other mode * Fix bug: a continued snapshot was not incremental (https://github.com/bit-team/backintime/issues/557) * use rsync to remove snapshots which will give a nice speedup (https://github.com/bit-team/backintime/issues/151) * open temporary local copy of files instead of original backup on double-click in GUI * add option to decrypt paths in systray menu with mode ssh-encrypted * open current log directly from systray icon during taking a snapshot * add tool-tips to restore menu * Fix bug: config backup in snapshot had wrong name if using --config option * add --share-path option * use Monospace font in logview * add restore option --only-new * add button 'Take snapshot with checksums' * Fix bug: Can't open files with spaces in name (https://github.com/bit-team/backintime/issues/552) * Fix bug: BIT-root won't start from .desktop file (https://github.com/bit-team/backintime/issues/549) * Fix bug: Keyring doesn't work with KDE Plasma5 (https://github.com/bit-team/backintime/issues/545) * Fix bug: Qt4 built-in phrases where not translated (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=816197) * Fix bug: configure ignore unknown args (https://github.com/bit-team/backintime/issues/547) * Fix bug: snapshots-list on command-line was not sorted * Fix bug: SHA256 ssh-key fingerprint was not detected * change default configure option to --no-fuse-group as Ubuntu >= 12.04 don't need fuse group-membership anymore * Fix bug: new snapshot did not show up after finished * Fix bug: TimeLine headers were not correct * Fix lintian warning: manpage-has-errors-from-man: bad argument name 'P' * Fix bug: wildcards ? and [] wasn't recognized correctly * Fix bug: last char of last element in tools.get_rsync_caps got cut off * Fix bug: TypeError in tools.get_git_ref_hash * Do not print 'SnapshotID' or 'SnapshotPath' if running 'snapshots-list' command (and other) with '--quiet' * Remove dependency 'ps' * Fix bug: don't include empty values in list (https://github.com/bit-team/backintime/issues/521) * Fix bug: bash-completion doesn't work for backintime-qt4 * Fix bug: 'make unittest' incorrectly used 'coverage' by default (https://github.com/bit-team/backintime/issues/522) * Fix bug: pm-utils is deprecated; Remove dependency (https://github.com/bit-team/backintime/issues/519) * rewrite huge parts of snapshots.py * remove backwards compatibility to version < 1.0 Version 1.1.24 (2017-11-07) * fix critical bug: CVE-2017-16667: shell injection in notify-send (https://github.com/bit-team/backintime/issues/834) Version 1.1.22 (2017-10-28) * fix bug: stat free space for snapshot folder instead of backintime folder (https://github.com/bit-team/backintime/issues/552733) * backport bug fix: backintime root crontab doesn't run; missing line-feed 0x0A on last line (https://github.com/bit-team/backintime/issues/552781) * backport bug fix: can't open files with spaces in name (https://github.com/bit-team/backintime/issues/552552) Version 1.1.20 (2017-04-09) * backport bug fix: CVE-2017-7572: polkit CheckAuthorization: race condition in privilege authorization Version 1.1.18 (2017-03-29) * Fix bug: manual snapshots from GUI didn't work (https://github.com/bit-team/backintime/issues/728) Version 1.1.16 (2017-03-28) * backport bug fix: start a new ssh-agent instance only if necessary (https://github.com/bit-team/backintime/issues/722) * Fix bug: OSError when running backup-job from systemd (https://github.com/bit-team/backintime/issues/720) Version 1.1.14 (2017-03-05) * backport bug fix: udev schedule not working (https://github.com/bit-team/backintime/issues/605) * backport bug fix: Keyring doesn't work with KDE Plasma5 (https://github.com/bit-team/backintime/issues/545) * backport bug fix: nameError in tools.make_dirs (https://github.com/bit-team/backintime/issues/622) * backport bug fix: use current folder if no file is selected in files view * Fix critical bug: restore filesystem-root without 'Full rsync mode' with ACL and/or xargs activated broke whole system (https://github.com/bit-team/backintime/issues/708) Version 1.1.12 (2016-01-11) * Fix bug: remove x-terminal-emulator dependency (https://github.com/bit-team/backintime/issues/515) * Fix bug: AttributeError in About Dialog (https://github.com/bit-team/backintime/issues/515) Version 1.1.10 (2016-01-09) * Fix bug: failed to remove empty lock file (https://github.com/bit-team/backintime/issues/505) * Add Icon 'show-hidden' (https://github.com/bit-team/backintime/issues/507) * Add Modify for Full System Backup button to settings page, to change some profile settings * Fix bug: Restore the correct file owner and group fail if they are not present in system (https://github.com/bit-team/backintime/issues/58) * add get|set_list_value to configfile * Fix bug: QObject::startTimer error on closing app * subclass ApplicationInstance in GUIApplicationInstance to reduce redundant code * speed up app start by adding snapshots to timeline in background thread * add warning on failed permission restore (https://github.com/bit-team/backintime/issues/58) * add unittest (thanks to Dorian, Alexandre, Aurélien and Gregory from IAGL) * Fix bug: FileNotFoundError while starting pw-cache from source * continue an unfinished new_snapshot if possible (https://github.com/bit-team/backintime/issues/400) * Fix bug: suppress warning about failed inhibit suspend if run as root (https://github.com/bit-team/backintime/issues/500) * Fix bug: UI blocked/grayed out while removing snapshot (https://github.com/bit-team/backintime/issues/487) * Fix bug: pw-cache failed on leftover PID file, using ApplicationInstance now (https://github.com/bit-team/backintime/issues/468) * Fix bug: failed to parse some arguments (https://github.com/bit-team/backintime/issues/492) * Fix bug: failed to start GUI if launched from systray icon * Fix bug: deleted snapshot is still listed in Timeline if using mode SSH (https://github.com/bit-team/backintime/issues/493) * Fix bug: PermissionError while deleting readonly files on sshfs mounted share (https://github.com/bit-team/backintime/issues/490) * Add Nautilus-like shortcuts for navigating in file browser (https://github.com/bit-team/backintime/issues/483) * speed up mounting of SSH+encrypted profiles * Fix bug: create new encrypted profiles with encfs >= 1.8.0 failed (https://github.com/bit-team/backintime/issues/477) * Fix bug: AttributeError in common/tools.py if keyring is missing (https://github.com/bit-team/backintime/issues/473) * Fix bug: remote rename of 'new_snapshot' folder sometimes isn't recognized locally; rename local now (https://answers.launchpad.net/questions/271792) * Move source code and bug tracking to GitHub Version 1.1.8 (2015-09-28) * Fix bug: unlock private SSH key run into 5sec timeout if password is empty * show current app name and profile ID in syslog (https://launchpad.net/bugs/906213) * Fix bug: BiT freeze when activate 'Decode path' in 'Snapshot Log View' * Show 'Profiles' dropdown only in 'Last Log Viewer', add 'Snapshots' dropdown in 'Snapshot Log Viewer' (https://launchpad.net/bugs/1478219) * Fix bug: empty gray window appears when starting the gui as root (https://launchpad.net/bugs/1493020) * do not restore permission if they are identical with current permissions * Fix bug: gnu_find_suffix_support doesn't set back to True (https://launchpad.net/bugs/1487781) * security issue: do not run user-callback in a shell * add option to not log user-callback output * Fix lintian warning dbus-policy-without-send-destination * apply timestamps-in-gzip.patch from Debian backintime/1.1.6-1 package * run multiple smart-remove jobs in one screen session (https://launchpad.net/bugs/1487781) * add error messages if PID file creation fail * Fix bug: dbus exception if dbus systembus is not running * Fix bug: depend on virtual package cron-daemon instead of cron for compatibility with other cron implementations (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=776856) * Fix bug: wasn't able to start from alternate install dir (https://launchpad.net/bugs/478689) * Fix bug: wasn't able to start from source dir * Add Warning about unsupported filesystems * use native Python code to check mountpoint * Add expert option for stdout and stderr redirection in cronjobs (https://answers.launchpad.net/questions/270105) * Fix bug: 'Inhibit Suspend' fails with 'org.freedesktop.PowerManagement.Inhibit' (https://launchpad.net/bugs/1485242) * Fix bug: No mounting while selecting a secondary profile in the gui (https://launchpad.net/bugs/1481267) * remove shebang in common/askpass.py and common/create-manpage-backintime-config.py * Fix bug: fix for bug #1419466 broke crontab on Slackware (https://launchpad.net/bugs/1478576) * Fix bug: fix for bug #1431305 broke pw-cache on Ubuntu (https://launchpad.net/bugs/1431305) * Fix bash-complete * show 'man backintime' on Help; remove link to backintime.le-web.org (https://launchpad.net/bugs/1475995) * add --debug argument * Fix bug: Settings accepted empty strings for Host/User/Profile-ID (https://launchpad.net/bugs/1477733) * Fix bug: IndexError on 'check_remote_commands' due to too long args (https://launchpad.net/bugs/1471930) * add --local-backup, --no-local-backup and --delete option to restore on command-line (https://launchpad.net/bugs/1467239) * add 'backup on restore' option to confirm dialog * add check-config command for command-line * rewrite command-line argument parsing. Now using argparse * add expert option SSH command prefix * Fix bug: Makefile has no uninstall target (https://launchpad.net/bugs/1469152) Version 1.1.6 (2015-06-27) * show Profile name in systrayicon menu * Fix bug: encrypted remote backup hangs on 'start encfsctl encode process' (https://launchpad.net/bugs/1455925) * make own Exceptions a childclass from BackInTimeException * Fix bug: missing profile.name crashed GUI * Fix bug: Segmentation fault caused by two QApplication instances (https://launchpad.net/bugs/1463732) * remove consolekit from dependencies * Fix bug: no Changes [C] log entries with 'Check for changes' disabled (https://launchpad.net/bugs/1463367) * Fix bug: some changed options from Settingsdialog where not respected during automatic tests after hitting OK * Fix bug: python version check fails on python 3.3 (https://launchpad.net/bugs/1463686) * Specifying the SSH private key whenever ssh is called (https://launchpad.net/bugs/1433682) * add to in-/exclude directly from mainwindow (https://launchpad.net/bugs/1454856) * Fix bug: pw-cache didn't start on Mint KDE because of missing stdout and stderr (https://launchpad.net/bugs/1431305) * add option to run Smart Remove in background on remote host (https://launchpad.net/bugs/1457210) * Use current profile when starting GUI from Systray * Fix bug: failed to restore file names with white spaces using CLI (https://launchpad.net/bugs/1435602) * Fix bug: UnboundLocalError with 'last_snapshot' in _free_space (https://launchpad.net/bugs/1437623) Version 1.1.4 (2015-03-22) * add option to keep new snapshot with 'full rsync mode' regardless of changes (https://launchpad.net/bugs/1434722) * Fix bug: wrong quote in 'Save config file' * Fix bug: Deleting the last snapshot does not update the last_snapshot symlink (https://launchpad.net/bugs/1434724) * remove base64 encoding for passwords as it doesn't add any security but broke the password process (https://launchpad.net/bugs/1431305) * add confirm dialog before restoring (https://launchpad.net/bugs/438079) * Fix bug: Wrong status text in the tray icon (https://launchpad.net/bugs/1429400) * add option to run only one snapshot at a time * Fix bug: restore permissions of lots of files made BackInTime unresponsive (https://launchpad.net/bugs/1428423) * Fix bug: failed to restore file owner and group * cache uuid in config so it doesn't fail if the device isn't plugged in (https://launchpad.net/bugs/1426881) * add warning about wrong Python version in configure * prevent snapshots from being removed with restore and delete; show warning if restore and delete filesystem root (https://answers.launchpad.net/questions/262837) * Fix bug: OSError in free_space; add alternate method to get free space * add bash-completion * Fix bug: ugly theme while running as root on Gnome based DEs (https://launchpad.net/bugs/1418447) * Fix bug: UnicodeError thrown if filename has broken charset (https://launchpad.net/bugs/1419694) * use 'crontab' instead of 'crontab -' to read from stdin (https://launchpad.net/bugs/1419466) Version 1.1.2 (2015-02-04) * sort 'Backup folders' in main window * save in- and exclude sort order * use PolicyKit to install Udev rules * move compression from install to build in Makefiles * use pkexec to start backintime-qt4 as root Version 1.1.0 (2015-01-15) * add tooltips for rsync options * make only one debian/control * multiselect files to restore (https://launchpad.net/bugs/1135886) * force run manual snapshots on battery (https://launchpad.net/bugs/861553) * backup encfs config to local config folder * apply 'install-docs-move.patch' from Debian package by Jonathan Wiltshire * add restore option to delete new files during restore (https://launchpad.net/bugs/1371951) * use flock to prevent two instances running at the same time * restore config dialog added (https://launchpad.net/bugs/480391) * inhibit suspend/hibernate while take_snapshot or restore * use more reliable code for get_user * implement anacrons functions inside BIT => more flexible schedules and no new timestamp if there was an error * automatically run in background if started with 'backintime --backup-job' * fix typos and style warnings in manpages reported by Lintian (https://lintian.debian.org/full/jmw@debian.org.html#backintime_1.0.34-0.1) * add exclude files by size (https://launchpad.net/bugs/823719) * remove 'Auto Host/User/Profile-ID' as this is more confusing than helping * Fix bug: check procname of pid-locks (https://launchpad.net/bugs/1341414) * optional run 'rsync' with 'nocache' (https://launchpad.net/bugs/1344528) * mark invalid exclude pattern with mode ssh-encrypted * make Settingsdialog tabs scrollable * remove colon (:) restriction in exclude pattern * prevent starting new snapshot if restore is running * Fix bug: Port check failed on IPv6 (https://launchpad.net/bugs/1361634) * add top-level directory for tarball (https://launchpad.net/bugs/1359076) * add more user-callback events (on App start and exit, on mount and unmount) * add context menu to files view * remove snapshots from commandline * multi selection in timeline => remove multiple snapshots with one click * print warning if started with sudo * add more default exclude; remove [Cc]ache* from exclude * Fix bug: 'inotify_add_watch failed' while closing BIT * add option for custom rsync-options * add ProgressBar for rsync * add progress for smart-remove * remove old status-bar message after a snapshot crashed. * ask to include symlinks target instead link (https://launchpad.net/bugs/1117709) * port to Python 3.x * returncode >0 if there was an error (https://launchpad.net/bugs/1040995) * Enable user-callback script to cancel a backup by returning a non-zero exit code. * merge backintime-notify into backintime-qt4 * add --gksu/--gksudo arg to qt4/configure * remember last path for each profile (https://bugs.launchpad.net/bugs/1254870) * sort include and exclude list (https://bugs.launchpad.net/bugs/1193149) * Timeline show tooltip 'Last check' * Fix bug: systray icon didn't show up (https://bugs.launchpad.net/backintime/+bug/658424) * show hidden files in FileDialog (https://bugs.launchpad.net/backintime/+bug/995925) * add button text for all buttons (https://bugs.launchpad.net/backintime/+bug/992020) * add shortcuts (https://bugs.launchpad.net/backintime/+bug/686694) * add menubar (https://bugs.launchpad.net/backintime/+bug/528851) * port KDE4 GUI to pure Qt4 to replace both KDE4 and Gnome GUI Version 1.0.40 (2014-11-02) * use fingerprint to check if ssh key was unlocked correctly (https://answers.launchpad.net/questions/256408) * add fallback method to get UUID (https://answers.launchpad.net/questions/254140) * Fix bug: 'Attempt to unlock mutex that was not locked'... this time for good Version 1.0.38 (2014-10-01) * Fix bug: 'Attempt to unlock mutex that was not locked' in gnomeplugin (https://answers.launchpad.net/questions/255225) * compare os.path.realpath instead of os.stat to get devices UUID * Fix bug: housekeeping by gnome-session-daemon might delete backup and original data (https://bugs.launchpad.net/bugs/1374343) * Fix bug: Type Error in 'backintime --decode' (https://bugs.launchpad.net/bugs/1365072) * Fix bug: take_snapshot didn't wait for snapshot folder come available if notifications are disabled (https://bugs.launchpad.net/bugs/1332979) Version 1.0.36 (2014-08-06) * remove UbuntuOne from exclude (https://bugs.launchpad.net/bugs/1340131) * Gray out 'Add Profile' if 'Main Profile' isn't configured yet (https://bugs.launchpad.net/bugs/1335545) * Don't check for fuse group-membership if group doesn't exist * Fix bug: backintime-kde4 as root failed to load ssh-key (https://bugs.launchpad.net/bugs/1276348) * Fix bug: kdesystrayicon.py crashes because of missing environ (https://bugs.launchpad.net/bugs/1332126) * Fix bug: OSError if sshfs/encfs is not installed (https://bugs.launchpad.net/bugs/1316288) * Fix bug: TypeError in config.py check_config() (https://bugzilla.redhat.com/show_bug.cgi?id=1091644) * Fix bug: unhandled exception in create_last_snapshot_symlink() (https://bugs.launchpad.net/bugs/1269991) * disable keyring for root Version 1.0.34 (2013-12-21) * sync/flush all disks before shutdown (https://bugs.launchpad.net/bugs/1261031) * Fix bug: BIT running as root shutdown after snapshot, regardless of option checked (https://bugs.launchpad.net/bugs/1261022) Version 1.0.32 (2013-12-13) * Fix bug: cron scheduled snapshots won't start with 1.0.30 Version 1.0.30 (2013-12-12) * scheduled and manual snapshots use --config * make configure scripts portable (https://bugs.launchpad.net/backintime/+bug/377429) * Fix bug: udev rule doesn't finish (https://bugs.launchpad.net/backintime/+bug/1249466) * add symlink last_snapshot (https://bugs.launchpad.net/backintime/+bug/787118) * add virtual package backintime-kde for PPA * Fix multiple errors in PPA build process; reorganize updateversion.sh * Fix bug: Mate and xfce desktop didn't show systray icon (https://bugs.launchpad.net/backintime/+bug/658424/comments/31) * add option to run rsync with 'nice' or 'ionice' on remote host (https://bugs.launchpad.net/backintime/+bug/1240301) * add Shutdown button to shutdown system after snapshot has finished (https://bugs.launchpad.net/backintime/+bug/838742) * Fix bug: Ubuntu Lucid doesn't provide SecretServiceKeyring (https://bugs.launchpad.net/backintime/+bug/1243911) * wrap long lines for syslog * Fix bug: 'gksu backintime-gnome' failed with dbus.exceptions.DBusException Version 1.0.28 (2013-10-19) * remove config on 'apt-get purge' * add more options for configure scripts; update README * add udev schedule (run BIT as soon as the drive is connected) * Fix bug: AttributeError with python-keyring>1.6.1 (https://bugs.launchpad.net/backintime/+bug/1234024) * Fix bug: TypeError: KDirModel.removeColumns() is a private method in kde4/app.py (https://bugs.launchpad.net/backintime/+bug/1232694) * add '--checksum' commandline option (https://bugs.launchpad.net/backintime/+bug/886021) * Fix bug: sshfs mount disconnect after a while due to some firewalls (add ServerAliveInterval) (https://answers.launchpad.net/backintime/+question/235685) * Fix bug: Ping fails if ICMP is disabled on remote host (https://bugs.launchpad.net/backintime/+bug/1226718) * Fix bug: KeyError in getgrnam if there is no 'fuse' group (https://bugs.launchpad.net/backintime/+bug/1225561) * Fix bug: anacrontab won't work with profilename with spaces (https://bugs.launchpad.net/backintime/+bug/1224620) * Fix bug: NameError in tools.move_snapshots_folder (https://bugs.launchpad.net/backintime/+bug/871466) * Fix bug: KPassivePopup is not defined (https://bugs.launchpad.net/backintime/+bug/871475) * multi selection for include and exclude list (https://bugs.launchpad.net/backintime/+bug/660753) * Fix bug: ValueError while reading pw-cache PID (https://answers.launchpad.net/backintime/+question/235407) Version 1.0.26 (2013-09-07) * add feature: keep min free inodes * roll back commit 836.1.5 (check free-space on ssh remote host): statvfs DOES work over sshfs. But not with quite outdated sshd * add daily anacron schedule * add delete button and 'list only equal' in Snapshot dialog; multiSelect in snapshot list * add manpage backintime-config and config-examples * Fix bug: Restore makes files public during the operation * Fix bug: Cannot keep modifications to cron (https://bugs.launchpad.net/backintime/+bug/698106) * add feature: restore from command line; add option --config * Fix bug: cannot stat 'backintime-kde4-root.desktop.kdesudo' (https://bugs.launchpad.net/backintime/+bug/696659) * Fix bug: unreadable dark KDE color schemes (https://bugs.launchpad.net/backintime/+bug/1184920) * use 'ps ax' to check if 'backintime --pw-cache' is still running * mount after locking, unmount before unlocking in take_snapshot * Fix bug: permission denied if remote uid wasn't the same as local uid * add option --bwlimit for rsync * redirect logger.error and .warning to stderr; new argument --quiet * deactivate 'Save Password' if no keyring is available * use Password-cache for user-input too * handle two Passwords * add 'SSH encrypted': mount / with encfs reverse and sync encrypted with rsync. EXPERIMENTAL! * add 'Local encrypted': mount encfs Version 1.0.24 (2013-05-08) * hide check_for_canges if full_rsync_mode is checked * DEFAULT_EXCLUDE system folders with /foo/* so at least the folder itself will backup * DEFAULT_EXCLUDE /run; exclude MOUNT_ROOT with higher priority and not with DEFAULT_EXCLUDE anymore * Fix bug: 'CalledProcessError' object has no attribute 'strerror' * Fix bug: quote rsync remote path with spaces * 'Save Password' default off to avoid problems with existing profiles * if restore uid/gid failed try to restore at least gid * SSH need to store permissions in separate file with "Full rsync mode" because remote user might not be able to store ownership * Fix bug: restore permission failed on "Full rsync mode" * Fix bug: glib.GError: Unknown internal child: selection * Fix bug: GtkWarning: Unknown property: GtkLabel.margin-top * Fix bug: check keyring backend only if password is needed * switch to 'find -exec cmd {} +' (https://bugs.launchpad.net/backintime/+bug/1157639) * change all indent tabs to 4 spaces Version 1.0.22 (2013-03-26) * check free-space on ssh remote host (statvfs didn't work over sshfs) * Add Password storage mode ssh * Add "Full rsync mode" (can be faster but ...) * Fix bug: "Restore to..." failed due to spaces in directory name (https://bugs.launchpad.net/backintime/+bug/1096319) * Fix bug: host not found in known_hosts if port != 22 (https://bugs.launchpad.net/backintime/+bug/1130356) * Fix bug: sshtools.py used not POSIX conform conditionals Version 1.0.20 (2012-12-15) * Fix bug: restore remote path with spaces using mode ssh returned error Version 1.0.18 (2012-11-17) * Fix packages: man & translations * Fix bug: https://bugs.launchpad.net/backintime/+bug/1077446 * Fix bug: https://bugs.launchpad.net/backintime/+bug/1078979 * Fix bug: https://bugs.launchpad.net/backintime/+bug/1079479 * Map multiple arguments for gettext so they can be rearranged by translators Version 1.0.16 (2012-11-15) * Fix a package dependency problem ... this time for good (https://bugs.launchpad.net/backintime/+bug/1077446) Version 1.0.14 (2012-11-09) * Fix a package dependency problem Version 1.0.12 (2012-11-08) * Add links to: website, documentation, report a bug, answers, faq * Use libnotify for gnome/kde4 notifications instead of gnome specific libraries * Fix bug: https://bugs.launchpad.net/backintime/+bug/1059247 * Add more schedule options: every 30 min, every 2 hours, every 4 hours, every 6 hours & every 12 hours * Add generic mount-framework * Add mode 'SSH' for backups on remote host using ssh protocol. * Fix bug: wrong path if restore system root * Fix bug: glade (xml) files did not translate * Fix bug: https://bugs.launchpad.net/backintime/+bug/1073867 Version 1.0.10 (2012-03-06) * Add "Restore to ..." in replacement of copy (with or without drag & drop) because copy don't restore user/group/rights Version 1.0.8 (2011-06-18) * Fix bug: https://bugs.launchpad.net/backintime/+bug/723545 * Fix bug: https://bugs.launchpad.net/backintime/+bug/705237 * Fix bug: https://bugs.launchpad.net/backintime/+bug/696663 * Fix bug: https://bugs.launchpad.net/backintime/+bug/671946 Version 1.0.6 (2011-01-02) * Fix bug: https://bugs.launchpad.net/backintime/+bug/676223 * Smart remove: configurable options (https://bugs.launchpad.net/backintime/+bug/406765) * Fix bug: https://bugs.launchpad.net/backintime/+bug/672705 Version 1.0.4 (2010-10-28) * SettingsDialog: show highly recommended excludes * Fix bug: https://bugs.launchpad.net/backintime/+bug/664783 * Option to use checksum to detect changes (https://bugs.launchpad.net/backintime/+bug/666964) * Option to select log verbosity (https://bugs.launchpad.net/backintime/+bug/664423) * Gnome: use gloobus-preview if installed Version 1.0.2 (2010-10-16) * reduce log file (no more duplicate "Compare with..." lines) * declare backintime-kde4 packages as a replacement of backintime-kde Version 1.0 (2010-10-16) * add '.dropbox*' to default exclude patterns (https://bugs.launchpad.net/backintime/+bug/628172) * add option to take a snapshot at every boot (https://bugs.launchpad.net/backintime/+bug/621810) * fix xattr * add continue on errors (https://bugs.launchpad.net/backintime/+bug/616299) * add expert options: copy unsafe links & copy links * "user-callback" replace "user.callback" and receive profile information * documentation: on-line only (easier to maintain) * add error log and error log view dialog (Gnome & KDE4) * merge with: lp:~dave2010/backintime/minor-edits * merge with: lp:~mcfonty/backintime/unique-snapshots-view * fix bug: https://bugs.launchpad.net/backintime/+bug/588841 * fix bug: https://bugs.launchpad.net/backintime/+bug/588215 * fix bug: https://bugs.launchpad.net/backintime/+bug/588393 * fix bug: https://bugs.launchpad.net/backintime/+bug/426400 * fix bug: https://bugs.launchpad.net/backintime/+bug/575022 * fix bug: https://bugs.launchpad.net/backintime/+bug/571894 * fix bug: https://bugs.launchpad.net/backintime/+bug/553441 * fix bug: https://bugs.launchpad.net/backintime/+bug/550765 * fix bug: https://bugs.launchpad.net/backintime/+bug/507246 * fix bug: https://bugs.launchpad.net/backintime/+bug/538855 * fix bug: https://bugs.launchpad.net/backintime/+bug/386230 * fix bug: https://bugs.launchpad.net/backintime/+bug/527039 * reduce memory usage during compare with previous snapshot process * fix bug: https://bugs.launchpad.net/backintime/+bug/520956 * fix bug: https://bugs.launchpad.net/backintime/+bug/520930 * fix bug: https://bugs.launchpad.net/backintime/+bug/521223 * custom backup hour (for daily backups or mode): https://bugs.launchpad.net/backintime/+bug/507451 * fix bug: https://bugs.launchpad.net/backintime/+bug/516066 * fix bug: https://bugs.launchpad.net/backintime/+bug/512813 * smart remove was slightly changed (https://bugs.launchpad.net/backintime/+bug/502435) * fix bug: https://bugs.launchpad.net/backintime/+bug/503859 * make backup on restore optional * fix bug: https://bugs.launchpad.net/backintime/+bug/501285 * add ionice support for user/cron backup process * fix bug: https://bugs.launchpad.net/backintime/+bug/493558 * fix bug that could cause "ghost" folders in snapshots (LP: 406092) * fix bug that converted / into // (LP: #455149) * fix bug: https://bugs.launchpad.net/backintime/+bug/441628 * remove "schedule per included directory" (profiles do that) (+ bug LP: #412470) * fig bug: https://bugs.launchpad.net/backintime/+bug/489380 * fix bug: https://bugs.launchpad.net/backintime/+bug/489319 * fix bug: https://bugs.launchpad.net/backintime/+bug/447841 * fix bug: https://bugs.launchpad.net/backintime/+bug/412695 * update Slovak translation (Tomáš Vadina ) * multiple profiles support * GNOME: fix notification * backintime snapshot folder is restructured to ../backintime/machine/user/profile_id/ * added the possibility to include other snapshot folders within a profile, it can only read those, there is not a GUI implementation yet * added a tag suffix to the snapshot_id, to avoid double snapshot_ids * added a desktop file for kdesu and a test if kdesu or kdesudo should be used (LP: #389988) * added expert option to disable snapshots when on battery (LP: #388178) * fix bug handling big files by the GNOME GUI (LP: #409130) * fix bug in handling of & characters by GNOME GUI (LP: #415848) * fix a security bug in chmods before snapshot removal (LP: #419774) * snapshots are stored entirely read-only (LP: #386275) * fix exclude patterns in KDE4 (LP:#432537) * fix opening german files with external applications in KDE (LP: #404652) * changed default exclude patterns to caches, thumbnails, trashbins, and backups (LP: #422132) * write access to snapshot folder is checked & change to snapshot version 2 (LP: #423086) * fix small bugs (a.o. LP: #474307) * Used a more standard crontab syntax (LP: #409783) * Stop the "Over zealous removal of crontab entries" (LP: #451811) Version 0.9.26 (2009-05-19) * update translations from Launchpad * Fix a bug in smart-remove algorithm (https://bugs.launchpad.net/backintime/+bug/376104) * Fix bug: https://bugs.launchpad.net/backintime/+bug/374477 * Fix bug: https://bugs.launchpad.net/backintime/+bug/375113 * update German translation (Michael Wiedmann ) * add '--no-check' option to configure scripts * use only 'folder' term (more consistent with GNOME/KDE) * add 'expert option': enable/disable nice for cron jobs * GNOME & KDE4: refresh snapshots button force files view to update too * you can include a backup parent directory (backup directory will auto-exclude itself) * fix some small bugs Version 0.9.24 (2009-05-07) * update translations * KDE4: fix python string <=> QString problems * KDE4 FilesView/SnapshotsDialog: ctrl-click just select (don't execute) * KDE4: fix crush after "take snapshot" process (https://bugs.launchpad.net/backintime/+bug/366241) * store basic permission in a special file so it can restore them correctly (event from NTFS) * add config version * implement Gnome/KDE4 systray icons and user.callback as plugins * reorganize code: common/GNOME/KDE4 * GNOME: break the big glade file in multiple file * backintime is no longer aware of 'backintime-gnome' and 'backintime-kde4' (you need run 'backintime-gnome' for GNOME version and 'backintime-kde4' for KDE4 version) Version 0.9.22.1 (2009-04-27) * fix French translation Version 0.9.22 (2009-04-24) * update translations from Launchpad * KDE4: fix some translation problems * remove --safe-links for save/restore (this means copy symlinks as symlinks) * update German translation (Michael Wiedmann ) * create directory now use python os.makedirs (replace use of mkdir command) * KDE4: fix a crush related to QString - python string conversion * GNOME & KDE4 SettingsDialog: if schedule automatic backups per directory is set, global schedule is hidden * GNOME FilesView: thread "*~" files (backup files) as hidden files * GNOME: use gtk-preferences icon for SettingsDialog (replace gtk-execute icon) * expert option: $XDG_CONFIG_HOME/backintime/user.callback (if exists) is called a different steps of a "take snapshot" process (before, after, on error, is a new snapshot was taken). * add more command line options: --snapshots-list, --snapshots-list-path, --last-snapshot, --last-snapshot-path * follow FreeDesktop directories specs: $XDG_DATA_HOME (default: $HOME/.local/share) to store app.lock files $XDG_CONFIG_HOME (default: $HOME/.config) to save settings * new install system: use more common steps (./configure; make; sudo make install) Version 0.9.20 (2009-04-06) * smart remove: fix an important bug and make it more verbose in syslog * update Spanish translation (Francisco Manuel García Claramonte ) Version 0.9.18 (2009-04-02) * update translations from Launchpad * update Slovak translation (Tomáš Vadina ) * update French translation (Michel Corps ) * update German translation (Michael Wiedmann ) * GNOME bugfix: fix a crush in files view for files with special characters (ex: "a%20b") * GNOME SettingsDialog bugfix: if snapshots path is a new created folder, snapshots navigation (files view) don't work * update doc * GNOME & KDE4 MainWindow: Rename "Places" list with "Snapshots" * GNOME SettingsDialog bugfix: modify something, then press cancel. If you reopen the dialog it show wrong values (the ones before cancel) * GNOME & KDE4: add root mode menu entries (use gksu for gnome and kdesudo for kde) * GNOME & KDE4: MainWindow - Files view: if the current directory don't exists in current snapshot display a message * SettingDialog: add an expert option to enable to schedule automatic backups per directory * SettingDialog: schedule automatic backups - if the application can't find crontab it show an error * SettingDialog: if the application can't write in snapshots directory there should be an error message * add Polish translation (Paweł Hołuj ) * add cron in common package dependencies * GNOME & KDE4: rework settings dialog * SettingDialog: add an option to enable/disable notifications Version 0.9.16.1 (2009-03-16) * fix a bug/crush for French version Version 0.9.16 (2009-03-13) * update Spanish translation (Francisco Manuel García Claramonte ) * add Slovak translation (Tomáš Vadina ) * update Swedish translation (Niklas Grahn ) * update French translation (Michel Corps ) * update German translation (Michael Wiedmann ) * update Slovenian translation (Vanja Cvelbar ) * don't show the snapshot that is being taken in snapshots list * GNOME & KDE4: when the application starts and snapshots directory don't exists show a messagebox * give more information for 'take snapshot' progress (to prove that is not blocked) * MainWindow: rename 'Timeline' column with 'Snapshots' * when it tries to take a snapshot if the snapshots directory don't exists (it is on a removable drive that is not plugged) it will notify and wait maximum 30 seconds (for the drive to be plugged) * GNOME & KDE4: add notify if the snapshots directory don't exists * KDE4: rework MainWindow Version 0.9.14 (2009-03-05) * update German translation (Michael Wiedmann ) * update Swedish translation (Niklas Grahn ) * update Spanish translation (Francisco Manuel García Claramonte ) * update French translation (Michel Corps ) * GNOME & KDE4: rework MainWindow * GNOME & KDE4: rework SettingsDialog * GNOME & KDE4: add "smart" remove Version 0.9.12 (2009-02-28) * bug fix: now if you include ".abc" folder and exclude ".*", ".abc" will be saved in the snapshot * KDE4: add help * add Slovenian translation (Vanja Cvelbar ) * bug fix (GNOME): bookmarks with special characters Version 0.9.10 (2009-02-24) * add Swedish translation (Niklas Grahn ) * KDE4: drop and drop from backintime files view to any file manager * bug fix: fix a segfault when running from cron Version 0.9.8 (2009-02-20) * update Spanish translation (Francisco Manuel García Claramonte ) * bug fix: unable to restore files that contains space char in their name * unsafe links are ignored (that means that a link to a file/directory outside of include directories are ignored) * KDE4: add copy to clipboard * KDE4: sort files by name, size or date * cron 5/10 minutes: replace multiple lines with a single crontab line using divide (*/5 or */10) * cron: when called from cron redirect output (stdout & stderr) to /dev/null Version 0.9.6 (2009-02-09) * update Spanish translation (Francisco Manuel García Claramonte ) * update German translation (Michael Wiedmann ) * GNOME: update docbook * KDE4: add snapshots dialog * GNOME & KDE4: add update snapshots button * GNOME: handle special folders icons (home, desktop) Version 0.9.4 (2009-01-30) * update German translation (Michael Wiedmann ) * gnome: better handling of 'take snapshot' status icon * KDE4 (>= 4.1): first version (not finished) * update man Version 0.9.2 (2009-01-16) * update Spanish translation (Francisco Manuel García Claramonte ) * update German translation (Michael Wiedmann ) * bug fix: if you add "/a" in include directories and "/a/b" in exclude patterns, "/a/b*" items are not excluded * replace diff with rsync to check if a new snapshot is needed * code cleanup * add show hidden & backup files toggle button for files view * bug fix: it does not include ".*" items even if they are not excluded (the items was included but not showed because hidden & backup files was never displayed in files view in previous versions) Version 0.9 (2009-01-09) * update Spanish translation (Francisco Manuel García Claramonte ) * make deb packages more debian friendly (thanks to Michael Wiedmann ) * update German translation (Michael Wiedmann ) * bug fix: when you open snapshots dialog for the second time ( or more ) and you make a diff it will make the diff on the file for the first dialog ( all previous dialogs ) and then for the current one * better separation between common and gnome specific files and divide backintime package in backintime-common & backintime-gnome (this will allow me to write other GUI front-ends like KDE4 or KDE) * code cleanup Version 0.8.20 (2008-12-22) * bug fix: sorting files/directories by name is now case insensitive * getmessages.sh: ignore "gtk-" items (this are gtk stock item ids and should not be changed) Version 0.8.18 (2008-12-17) * update man/docbook * add sort columns in MainWindow/FileView (by name, by size or by date) and SnapshotsDialog (by date) * fix German translation (Michael Wiedmann ) Version 0.8.16 (2008-12-11) * add Drag & Drop from MainWindow:FileView/SnapshotsDialog to Nautilus * update German translation (Michael Wiedmann ) Version 0.8.14 (2008-12-07) * add more command line parameters ( --version, --snapshots, --help ) * fix a crush for getting info on dead symbolic links * when taking a new backup based on the previous one don't copy the previous extra info (ex: name) * copy unsafe links when taking a snapshot Version 0.8.12 (2008-12-01) * add German translation (Michael Wiedmann ) * add SnapshotNameDialog * add Name/Remove snapshot in main toolbar * change the way it detects if the mainwindow is the active window (no dialogs) * toolbars: show icons only * update Spanish translation (Francisco Manuel García Claramonte ) Version 0.8.10 (2008-11-22) * SnapshotsDialog: add right-click popup-menu and a toolbar with copy & restore buttons * use a more robust backup lock file * log using syslog * fix a small bug in copy to clipboard * update Spanish translation (Francisco Manuel García Claramonte ) Version 0.8.8 (2008-11-19) * SnapshotsDialog: add diff * update Spanish translation (Francisco Manuel García Claramonte ) Version 0.8.6 (2008-11-17) * fix change backup path crush * add SnapshotsDialog Version 0.8.2 (2008-11-14) * add right-click menu in files list: open (using gnome-open), copy (you can paste in Nautilus), restore (for snapshots only) * add Copy toolbar button for files list Version 0.8.1 (2008-11-10) * add every 5/10 minutes automatic backup Version 0.8 (2008-11-07) * don't show backup files (*~) * add backup files to default exclude patterns (*~) * makedeb.sh: make a single package with all languages included * install.sh: install all languages * add English manual (man) * add English help (docbook) * add help button in main toolbar * the application can be started with a 'path' to a folder or file as command line parameter * when the application start, if it is already running pass its command line to the first instance (this allow a basic integration with file-managers - see README) * bug fix: when the application was started a second time it raise the first application's window but not always focused Version 0.7.4 (2008-11-03) * if there is already a GUI instance running raise it * add Spanish translation (Francisco Manuel García Claramonte ) Version 0.7.2 (2008-10-28) * better integration with gnome icons (use mime-types) * remember last path * capitalize month in timeline (bug in french translation) Version 0.7 (2008-10-22) * fix cron segfault * fix a crush when launched the very first time (not configured) * multi-lingual support * add French translation Version 0.6.4 (2008-10-20) * remove About & Settings dialogs from the pager * allow only one instance of the application Version 0.6.2 (2008-10-16) * remember window position & size Version 0.6 (2008-10-13) * when it make a snapshot it display an icon in systray area * the background color for group items in timeline and places reflect more the system color scheme * during restore only restore button is grayed ( even if everything is blocked ) Version 0.5.1 (2008-10-10) * add size & date columns in files view * changed some texts Version 0.5 (2008-10-03) * This is the first release. backintime-1.6.1/CONTRIBUTING.md000066400000000000000000000622001514264426600160700ustar00rootroot00000000000000 # How to contribute to _Back In Time_ 😊 **Thanks for taking the time to contribute.** 😊 🟢 **Contributions can be much more than code.** 🟢 The maintenance team welcomes all types of contributions. No contribution will be rejected solely because it doesn't meet our quality standards, guidelines, or rules. Every contribution is reviewed, and if necessary, improved in collaboration with the maintenance team. New contributors who may need assistance or are less experienced are warmly welcomed and will be mentored by the maintenance team upon request. There are many ways to contribute beyond coding: [translating the project](https://github.com/bit-team/backintime/issues/1915), performing manual tests, analyzing and reproducing [bugs](https://github.com/bit-team/backintime/issues), reviewing and testing [pull requests](https://github.com/bit-team/backintime/pulls), providing feedback on new features, designing an [application logo](https://github.com/bit-team/backintime/issues/1961), or reviewing the documentation and suggesting improvements. 🚀 Every contribution helps the project grow! 🚀 > [!TIP] > Don't forget to introduce yourself if you are new to the project. Also, read > this document carefully. # Index - [Before you start](#before-you-start) - [Best practice and recommendations](#best-practice-and-recommendations) - [Resources & Further Readings](#resources--further-readings) - [Build & Install](#build--install) - [Dependencies](#dependencies) - [Build and install via `make` system (recommended)](#build-and-install-via-make-system-recommended) - [Testing](#testing) - [SSH](#SSH) - [What happens after you opened a Pull Request (PR)?](#what-happens-after-you-opened-a-pull-request-PR) - [Instructions about translation](#instructions-about-translation) - [Terminology](#terminology) - [General recommendations for developers](#general-recommendations-for-developers) - [Consider Right-to-Left (RTL) and Bidirectional (BIDI) languages](#consider-right-to-left-rtl-and-bidirectional-bidi-languages) - [Be aware of shortcut indicators and possible duplicates](#be-aware-of-shortcut-indicators-and-possible-duplicates) - [Treat other translators work with respect](#treat-other-translators-work-with-respect) - [Strategy Outline](#strategy-outline) - [Licensing of contributed material](#licensing-of-contributed-material) - [Quick technical guide](#quick-tecnical-guide) # Before you start - **Read this document carefully.** - Remember that this project is maintained by volunteers in their free time – human beings just like you. - [You should be a user of this software](FAQ.md#can-i-contribute-without-using-the-software). - [Introduce yourself](FAQ.md#why-do-i-need-to-introduce-myself). - Check out the [FAQ entries about contributing to the project](FAQ.md#project--contributing--more). - And finally: Don't refuse to read this document carefully! # Best practice and recommendations If possible, please consider the following best practices. This will reduce the workload of the maintainers and increase the chances of your pull request being accepted. - Follow [PEP 8](https://peps.python.org/pep-0008/) as a minimal Style Guide for Python Code. - About strings: - Prefer _single quotes_ (e.g. `'Hello World'`) over _double qutoes_ (e.g. `"Hello World"`). Exceptions are when single quotes contained in the string (e.g. `"Can't unmount"`). - Enclose translatable strings like this: `_('Translate me')`. Find more details in our [localization docu](doc/maintain/2_localization.md#instructions-for-the-translation-process). - For docstrings follow [Google Style Guide](https://sphinxcontrib-napoleon.readthedocs.org/en/latest/example_google.html) (see our own [HOWTO about doc generation](doc/maintain/1_doc_howto.md)). - Avoid the use of automatic formatters like `black` but mention the use of them when opening a pull request. - Run unit tests before you open a pull request. Read [Testing](#testing) for further details. - Try to create new unit tests if appropriate. Use the style of regular Python `unittest` rather than `pytest`. If you know the difference, please try to follow the _Classical (aka Detroit) school_ instead of _London (aka mockist) school_. - See recommendations about [how to handle translatable strings](doc/maintain/2_localization.md#instructions-for-the-translation-process). # Resources & Further readings - [Mailing list _bit-dev_](https://mail.python.org/mailman3/lists/bit-dev.python.org/) - [Translations](https://translate.codeberg.org/engage/backintime) are done on a separate platform. - [HowTo's and maintenance](doc/maintain/README.md) - [FAQ entries about contributing to the project](FAQ.md#project--contributing--more). - Further readings - [contribution-guide.org](https://www.contribution-guide.org) - [How to submit a contribution (opensource.guide)](https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution) - [mozillascience.github.io/working-open-workshop/contributing](https://mozillascience.github.io/working-open-workshop/contributing) # Build & Install This section describes how to build and install _Back In Time_ in preparation of your own contributions. It is assumed that you `git clone` this repository first. ## Dependencies The following dependencies are based on _Debian GNU/Linux_. Please [open an Issue](https://github.com/bit-team/backintime/issues/new/choose) if something is missing. If you use another GNU/Linux distribution, please install the corresponding packages. Even if some packages are available from PyPi stick to the packages provided by the official repository of your GNU/Linux distribution. * Runtime dependencies for the CLI - `python3` (>= 3.11) - `rsync` - `cron-daemon` - `openssh-client` - `sshfs` - `python3-keyring` - `python3-dbus` - `python3-packaging` - Recommended - `encfs` - `gocryptfs` * Runtime dependencies for the GUI - `x11-utils` - `python3-pyqt6` (Do not use the version from _PyPi_ via `pip`) - `python3-dbus.mainloop.pyqt6` (not available from _PyPi_ via `pip`) - `python3-pyqt6.qtsvg` - `pkexec` - `bash` (Used by root mode starter script `qt/backintime-qt_polkit`) - `polkitd` - `qttranslations6-l10n` or alternative package name `qt6-translations-l10n` - `qtwayland6` (if Wayland is used as display server instead of X11) or alternative package name `qt6-wayland` - Recommended - For SSH key storage **one** of these packages - `python3-secretstorage` - `python3-keyring-kwallet` - `python3-gnomekeyring` - For diff-like comparing files between backups **one** of these packages - `kompare` - or `meld` * Build and testing dependencies - All CLI runtime dependencies including the recommended - All GUI runtime dependencies including the recommended - `build-essential` - `gzip` - `gettext` - `python3-pyfakefs` (>= 5.7) - `asciidoctor` - Optional but recommended: - `pylint` (>= 4.0.0) - `flake8` - `ruff` (>= 0.15.0) - `codespell` - `reuse` (>= 4.0.0) * Dependencies to build documentation - All runtime, build, testing dependencies including the recommended - `mkdocs` - `mkdocs-material` ## Build and install via `make` system (recommended) > [!IMPORTANT] > Install [Dependencies](#dependencies) before you build and install. Remember that _Back In Time_ does consist of two packages, which must be built and installed separately accordingly. * Command line tool 1. `cd common` 2. `./configure && make` 3. Run unit tests via `python -m unittest` or `pytest`. 4. `sudo make install` * Qt GUI 1. `cd qt` 2. `./configure && make` 3. Run unit tests via `python -m unittest` or `pytest`. 4. `sudo make install` You can use optional arguments to `./configure` for creating a Makefile. See `common/configure --help` and `qt/configure --help` for details. # Testing > [!IMPORTANT] > Remember to **manually** test _Back In Time_ and not rely solely on > the automatic test suite. See section > [Manual testing](doc/maintain/BiT_release_process.md#manual-testing---recommendations) > about recommendations how to perform such tests. After [building and installing](#build--install), run the test suite. Feel free to use Python's own `unittest` module or `pytest` as a test runer. Since _Back In Time_ consists of two components, `common` and `qt`, the tests are segregated accordingly. $ cd common $ pytest Or $ cd qt $ pytest > [!IMPORTANT] > Even if `pytest` is used as test runner, don't write tests in > `pytest`-style. Stick to the good old `unittest`-style. This is a project > rule, taking maintainability into account. ## SSH Some tests require an available SSH server. Those tests get skipped if no SSH server is available. The goal is to log into the SSH server on your local computer via `ssh localhost` without using a password: - Generate an RSA key pair executing `ssh-keygen`. Use the default file name and don't use a passphrase for the key. - Populate the public key to the server executing `ssh-copy-id`. - Make the `ssh` instance run. - The port `22` (SSH default) should be available. - _Authorize_ the key with `$ ssh localhost` and insert your user accounts password. To test the connection just execute `ssh localhost` and you should see an SSH shell **without** being asked for a password. For detailed setup instructions see the [how to setup openssh for unit tests](doc/maintain/3_How_to_set_up_openssh_server_for_ssh_unit_tests.md). # What happens after you opened a Pull Request (PR)? In short: 1. The maintenance team will review your PR in days or weeks. 2. Modifications may be requested, and the PR will eventually be approved. 3. One of two labels will be added to the PR: - [PR: Merge after creative-break](https://github.com/bit-team/backintime/labels/PR%3A%20Merge%20after%20creative-break): Merge, but with a minimum delay of one week to allow other maintainers to review. - [PR: Waiting for review](https://github.com/bit-team/backintime/labels/PR%3A%20Waiting%20for%20review): Wait until a second approval from another maintainer. The maintenance team members are promptly notified of your request. One of them will respond within days or weeks. Note that all team members perform their duties voluntarily in their limited spare time. Please read the maintainers' responses carefully, answer their questions, and try to follow their instructions. Do not hesitate to ask for clarification if needed. At least one maintainer will review and ultimately approve your pull request. Depending on the topic or impact of the PR, the maintainer may decide that an approval from a second maintainer is needed. This may result in additional waiting time. Please remain patient. In such cases, the PR will be labeled [PR: Waiting for review](https://github.com/bit-team/backintime/labels/PR%3A%20Waiting%20for%20review). If no second approval is necessary, the PR is labeled [PR: Merge after creative-break](https://github.com/bit-team/backintime/labels/PR%3A%20Merge%20after%20creative-break) and will remain open for minimum of one week. This rule allows all maintainers the chance to review and potentially veto the pull request. # Instructions about translation ## Terminology - The translators, as native speakers, are the maintainers of the translation in their language and have the final decision. All following points are strong recommendations, but not written in stone. Language maintainers are free to overule them for good reasons. - "Directory" or "Folder"? We prefer "Directory". In our opinion, it is a clearly defined technical term and more precise in describing an element in the file system. - Translate "Back In Time"? It is the name of the application. That shouldn't be translated at all. - The target user group for Back In Time consists of end users without a technical background. Write GUI strings and messages accordingly, avoiding technical or nerdy terminology. - Some points of the following [General recommendations for developers](#general-recommendations-for-develoeprs) are also relevant for translators. ## General recommendations for developers The following points are about creating translatable source strings. - Be aware that some of our translators are not skilled in Python programming. They might don't know about GNU gettext internals and other technical details. They only see the translatable string in the web-frontend of our [translation platform](https://translate.codeberg.org/engage/backintime). - Avoid escape characters in the strings. - Give translators enough context with providing meaningful placeholder names. - Avoid addressing users as persons with "you". Try neutral phrases instead. - Don't "scream" by using upper case letters (e.g. `WARNING`) or an exclamation mark (`!`). - Please provide a screenshot when introducing new translatable strings or modifying them. The picture will be used on the translation web-frontend to provide translators with more context. - [Consider Right-to-Left (RTL) and Bidiretional (BIDI) languages](#consider-right-to-left-rtl-and-bidiretional-bidi-languages). - [Be aware of shortcut indicators and possible duplicates](#be-aware-of-shortcut-indicators-and-possible-duplicates). - [Treat other translators work with respect](#treat-other-translators-work-with-respect). ```python # Avoid escape characters for string delimiters problematic = _('Hello \'World\'') correct = _("Hello 'World'") # Avoid escape characters like new lines problematic = _('One\nTwo')` correct = _('One') + '\n' + _('Two') # <- Separation into multiple strings is # no problem, because the translator # will have a screenshot. # Provide meaningful placeholder names problematic = _('Can not delete {var}.') correct = _('Can not delete {backup_path}.') # Avoid addressing the person with "you" problematic = _('Do you really want to delete this backup?') correct = _('Is it really intended to delete this backup?') ``` ## Consider Right-to-Left (RTL) and Bidirectional (BIDI) languages In short: Always include punctuation marks (e.g. colons) in the strings to translate. Languages such as Arabic or Hebrew are read from right to left (RTL). To be more precise, they can have mixed reading directions (BIDI). The GUI library used by _Back In Time_ takes this into account when arrange elements in a window. For example, a text-input widget is left from a label widget. This switched order is the reason why punctuation marks (e.g. colons) in the string of a label widget need to change their direction as well. This task can only be performed by the translator themselves, which is why punctuation marks need to be included in the string to translate. ## Be aware of shortcut indicators and possible duplicates In short: 1. Use the character `&` to indicate the letter to access a GUI element via keyboard shortcut. 2. Be careful not to create conflicts by using the same letter multiple times in the same GUI context. The _Back In Time_ GUI can be controlled via keyboard shortcuts. In the English version, for example, the menu _Back In Time_ in the main window can be unfolded via `Alt+T`, _Backup_ via `Alt+B`, or _Help_ via `Alt+H`. The keyboard letters to use are indicated in the GUI with an underlined letter. The original string in the source code uses the character `&` in front of a letter to indicate the shortcut and produce this underline. The example above use the source strings `Back In &Time`, `&Backup`, and `&Help`. This illustrates why it is not appropriate to always use the first letter for shortcuts. Here in this example, `&Back In Time` and `&Backup` would use the same letter. Translating `&Backup` and `&Help` into Turkish becomes `&Yedek` and `Y&ardım`, where using the first letter only would produce conflicts again. That is why the translator needs to decide which letter to use. ## Treat other translators work with respect Sometimes it is a matter of taste or habit how do you translate something. People are different, therefore their translation are also different. When modifying an existing translation please consider _Comments_ and _History_ section of that string on our translation platform. There might be another translator who has good reason for this translation. Don't waste other people work for no good reason. Also use the _Comments_ to document your own reasons if you expect discussions or conflicts. The translation for some specific languages (e.g. [German](https://translate.codeberg.org/projects/backintime/common/de/)) do have rules every translator should follow. That rules can be found in a colored box on top of the translation platform. Open an issue if you think they should be modified. # Strategy Outline This is a broad overview of the tasks or steps to enhance _Back In Time_ as a software and as a project. The schedule is not fixed, nor is the order of priority. - [Analyzing code and behavior](#analyzing-code-and-behavior) - [Code quality & unit tests](#code-quality--unit-tests) - [Issues](#issues) - [Replace and remove encryption library EncFS](#replace-and-remove-encryption-library-encfs) - [Packaging](#packaging) - [Code hosting](#code-hosting) - [Graphical User Interface (GUI): Redesign and Refactoring](#graphical-user-interface-gui-redesign-and-refactoring) - [Terminal User Interface (TUI)](#terminal-user-interface-tui) - [Tentative rough roadmap](#tentative-rough-roadmap) - [More stuff](#more-stuff) ## Analyzing code and behavior As none of the current team members were involved in the original development of _Back In Time_, there is a lack of deep understanding of certain aspects of the codebase and its functionality. Part of the work done in this project involves conducting research on the code, its features, infrastructure, and documenting the findings. ## Code quality & unit tests One challenge resembles a chicken-and-egg problem: the code structure lacks sufficient isolation, making it difficult, if not nearly impossible in some cases, to write valuable unit tests. Heavy refactoring of the code is necessary, but this carries a high risk of introducing new bugs. To mitigate this risk, unit tests are essential to catch any potential bugs or unintended changes in the behavior of _Back In Time_. Each of the problems is blocking the solution to the other problem. Considering the three major types of tests (_unit_, _integration_, _system_), the current test suite primarily consists of _system tests_. While these _system tests_ are valuable, their purpose differs from that of _unit tests_. Due to the lack of _unit tests_ in the test suite, the codebase has notably low test coverage (see [Issue #1489](https://github.com/bit-team/backintime/issues/1489)). The codebase does not adhere to [PEP8](https://peps.python.org/pep-0008/), which serves as the minimum Python coding style. Utilizing linters in their default configuration is currently not feasible. One of our objectives is to align with PEP8 standards and meet the requirements of code linters. See [Issue #1755](https://github.com/bit-team/backintime/issues/1755) about it. ## Issues All existing issues have been triaged by the current team. [Labels](https://github.com/bit-team/backintime/labels) are assigned to indicate priority, along with a [milestone](https://github.com/bit-team/backintime/milestones) indicating which planned release will address the issue. Some of these issues persists for a long time and involve multiple complex problems. They can be challenging to diagnose due to various factors. Enhancing test coverage and code quality is one aspect aimed at finding and implementing solutions for these issues. ## Replace and remove encryption library EncFS Currently, _Back In Time_ uses [EncFS](https://github.com/vgough/encfs) for encrypting backups, but it has known security vulnerabilities (see issue [#1549](https://github.com/bit-team/backintime/issues/1549)). This requires to remove it. A potential candidate for replacement is [GoCryptFS](https://github.com/rfjakob/gocryptfs). However, lack of resources hinders this effort. If no volunteers step forward, the encryption feature will be removed, prioritizing user security and team maintenance efforts. See [Issue #1734](https://github.com/bit-team/backintime/issues/1734) about the transition process and the discussion about alternatives to EncFS. ## Packaging At present, _Back In Time_ utilizes a build system that relies on `make`. However, this approach has several shortcomings and does not adhere to modern standards in Python packaging ([PEP 621](https://peps.python.org/pep-0621), [PEP 517](https://peps.python.org/pep-0517), [src layout](https://packaging.python.org/en/latest/tutorials/packaging-projects), [pyproject.toml](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html)). The team intends to migrate to these contemporary standards to streamline the maintenance of _Back In Time_ ([#1575](https://github.com/bit-team/backintime/issues/1575)). ## Code hosting The plan is to move to [Codeberg.org](https://codeberg.org). See also [this FAQ entry](FAQ.md##move-project-to-alternative-code-hoster-eg-codeberg-gitlab-). ## Graphical User Interface (GUI): Redesign and Refactoring Over the years, the GUI has become increasingly complex. It requires a visual redesign as well as code refactoring. Additionally, it lacks tests. This is an on-going tasks. ## Terminal User Interface (TUI) Various people use _Back In Time_ via the terminal, for example, through an SSH shell on a headless server. There where several ideas of creating alternatives to the Qt based GUI: terminal user interface (TUI) or enhance the existing command-line interface (CLI) ([#254](https://github.com/bit-team/backintime/issues/254)); a web-frontend ([#209](https://github.com/bit-team/backintime/issues/209)). All ideas are are rejected or postponed in favor of a human readable config file format using TOML ([#1984](https://github.com/bit-team/backintime/issues/1984)), assuming that a TUI or WebInterface, while convenient and pleasant, would no longer be necessary. ## More stuff - Migration of the logging mechanic to Python's own `logging` module ([#2286](https://github.com/bit-team/backintime/issues/2286). - Re-write interprocess communication (IPC) ([#2260](https://github.com/bit-team/backintime/issues/2260). ## Tentative rough roadmap This is a broad overview of upcoming developlment steps depending on each other: 1. Implement GoCrypt as an EncFS alternative. Related issue: [#1734](https://github.com/bit-team/backintime/issues/1734) 2. Removing EncFS. Related issue: [#1734](https://github.com/bit-team/backintime/issues/1734) 3. Introduce new configuration management code. Pending PR: [#1850](https://github.com/bit-team/backintime/pull/1850) 4. Implement new config file format (TOML). Related issue: [#1984](https://github.com/bit-team/backintime/issues/1984) # Licensing of contributed material Keep in mind as you contribute, that code, docs and other material submitted to the project are considered licensed under the same terms as the rest of the work. With a few exceptions, this is [GNU General Public License Version 2 or later](https://spdx.org/licenses/GPL-2.0-or-later.html) (`GPL-2.0-or-later`). This project uses [SPDX metadata](https://spdx.dev/) to provide detailed license and copyright information in a machine-readable format. This data is [available online](https://api.reuse.software/info/github.com/bit-team/backintime). or can be read from the local repository with [REUSE tools](https://reuse.software/). # Quick technical guide > [!CAUTION] > Please remember to create a new branch before you begin any modifications. > Baseline your feature or bug fix branch on `dev` > (reflecting the latest development state). 1. Fork this repository. See Microsoft GitHub's own documentation about [how to fork](https://docs.github.com/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo). 2. Clone your own fork to your local machine and enter the directory: $ git clone git@github.com:YOURNAME/backintime.git $ cd backintime 3. Create and checkout your own feature or bugfix branch with `dev` as baseline branch: $ git checkout -b myfancyfeature dev 4. Now you can add your modifications. 5. Commit and push it to your forked repo: $ git commit -am 'commit message' $ git push 6. Test your modifications. See section [Build & Install](#build--install) and [Testing](#testing) for further details. 7. Visit your own repository on Microsoft GitHub's website and create a Pull Request. See Microsoft GitHub's own documentation about [how to create a Pull Request based on your own fork](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). January 2026 backintime-1.6.1/FAQ.md000066400000000000000000002057741514264426600146070ustar00rootroot00000000000000 December 2025 # FAQ - Frequently Asked Questions - [General](#general) * [Does _Back in Time_ support full system backups?](#does-back-in-time-support-full-system-backups) * [Does _Back in Time_ support backups on cloud storage like OneDrive or Google Drive?](#does-back-in-time-support-backups-on-cloud-storage-like-onedrive-or-google-drive) * [Where is the log file?](#where-is-the-log-file) * [How to read log entries?](#how-to-read-log-entries) * [How to move backups to a new hard-drive?](#how-to-move-backups-to-a-new-hard-drive) * [How to move a large directory in the backup source without duplicating the files in the backup?](#how-to-move-a-large-directory-in-the-backup-source-without-duplicating-the-files-in-the-backup) * [How does _Back In Time_ compare with _Timeshift_?](#how-does-back-in-time-compare-with-timeshift) * [Additional features beside the GUI and benefits of using BIT](#additional-features-beside-the-gui-and-benefits-of-using-bit) - [Backups (snapshots)](#backups-snapshots) * [Backup or Snapshot?](#backup-or-snapshot) * [Does _Back In Time_ create incremental or full backups?](#does-back-in-time-create-incremental-or-full-backups) * [How do backups with hard-links work?](#how-do-backups-with-hard-links-work) * [How can I check if my backups are using hard-links?](#how-can-i-check-if-my-backups-are-using-hard-links) * [How to use checksum to find corrupt files periodically?](#how-to-use-checksum-to-find-corrupt-files-periodically) * [What is the meaning of the leading 11 characters (e.g. "cf...p.....") in my backup logs?](#what-is-the-meaning-of-the-leading-11-characters-eg-cfp-in-my-backup-logs) * [Backup "WITH ERRORS": [E] 'rsync' ended with exit code 23: See 'man rsync' for more details](#backup-with-errors-e-rsync-ended-with-exit-code-23-see-man-rsync-for-more-details) * [What happens when I remove a backup?](#what-happens-when-i-remove-a-backup) * [How can I exclude cache folders to improve backup speed and reduce storage?](#how-can-i-exclude-cache-folders-to-improve-backup-speed-and-reduce-storage) * [How to use extended filesystem attributes (xattr) to exclude files/directories?](#how-to-use-extended-filesystem-attributes-xattr-to-exclude-filesdirectories) * [How does Back In Time handle open or changed files during backup?](#how-does-back-in-time-handle-open-or-changed-files-during-backup) - [Restore](#restore) * [After Restore I have duplicates with extension ".backup.20131121"](#after-restore-i-have-duplicates-with-extension-backup20131121) * [Back In Time doesn't find my old backups on my new Computer](#back-in-time-doesnt-find-my-old-backups-on-my-new-computer) - [Schedule](#schedule) * [How does the 'Repeatedly (anacron)' schedule work?](#how-does-the-repeatedly-anacron-schedule-work) * [Will a scheduled backup run as soon as the computer is back on?](#will-a-scheduled-backup-run-as-soon-as-the-computer-is-back-on) * [If I edit my crontab and add additional entries, will that be a problem for BIT as long as I don't touch its entries? What does it look for in the crontab to find its own entries?](#if-i-edit-my-crontab-and-add-additional-entries-will-that-be-a-problem-for-bit-as-long-as-i-dont-touch-its-entries-what-does-it-look-for-in-the-crontab-to-find-its-own-entries) * [Can I use a systemd timer instead of cron?](#can-i-use-a-systemd-timer-instead-of-cron) - [Problems, Errors & Solutions](#problems-errors--solutions) * [OverflowError: Value 1702441408 out of range for UInt32](#overflowerror-value-1702441408-out-of-range-for-uint32) * [`SettingsDialog` object has no attribute `cbCopyUnsafeLinks`](#settingsDialog-object-has-no-attribute-cbcopyunsafelinks) * [WARNING: A backup is already running](#warning-a-backup-is-already-running) * [_Back in Time_ does not start and shows: The application is already running! (pid: 1234567)](#back-in-time-does-not-start-and-shows-the-application-is-already-running-pid-1234567) * [Switching to dark or light mode in the desktop environment is ignored by BIT](#switching-to-dark-or-light-mode-in-the-desktop-environment-is-ignored-by-bit) * [Version >= 1.2.0 works very slow / Unchanged files are backed up](#version--120-works-very-slow--unchanged-files-are-backed-up) * [What happens if I hibernate the computer while a backup is running?](#what-happens-if-i-hibernate-the-computer-while-a-backup-is-running) * [What happens if I power down the computer while a backup is running, or if a power outage happens?](#what-happens-if-i-power-down-the-computer-while-a-backup-is-running-or-if-a-power-outage-happens) * [What happens if there is not enough disk space for the current backup?](#what-happens-if-there-is-not-enough-disk-space-for-the-current-backup) * [NTFS Compatibility](#ntfs-compatibility) * [GUI does not scale on high resolution or 4k monitors](#gui-does-not-scale-on-high-resolution-or-4k-monitors) * [Tray icon or other icons not shown correctly](#tray-icon-or-other-icons-not-shown-correctly) * [Non-working password safe and BiT forgets passwords (keyring backend issues)](#non-working-password-safe-and-bit-forgets-passwords-keyring-backend-issues) * [Outdated](#outdated) * [Segmentation fault on Exit](#segmentation-fault-on-exit) * [Incompatibility with rsync >= 3.2.4](#incompatibility-with-rsync-324-or-newer) - [Hardware-specific Setup](#hardware-specific-setup) * [How to use BIT with an Ugreen NAS?](#how-to-use-bit-with-an-ugreen-nas) * [How to use QNAP QTS NAS with BIT over SSH](#how-to-use-qnap-qts-nas-with-bit-over-ssh) * [How to use Synology DSM 5 with BIT over SSH](#how-to-use-synology-dsm-5-with-bit-over-ssh) * [How to use Synology DSM 6 with BIT over SSH](#how-to-use-synology-dsm-6-with-bit-over-ssh) * [Using a non-standard port](#using-a-non-standard-port) * [How to use Synology DSM 7 with BIT over SSH](#how-to-use-synology-dsm-7-with-bit-over-ssh) * [Using a non-standard SSH port with a Synology NAS](#using-a-non-standard-ssh-port-with-a-synology-nas) * ["sshfs: No such file or directory" using BIT, but manually ssh with rsync works](#sshfs-no-such-file-or-directory-using-bit-but-manually-ssh-with-rsync-works) * [Synology: use different volume for backup](#synology-use-different-volume-for-backup) * [How to use Western Digital MyBook World Edition with BIT over ssh?](#how-to-use-western-digital-mybook-world-edition-with-bit-over-ssh) - [Project & Contributing & more](#project--Contributing--more) * [Why do I need to introduce myself?](#why-do-i-need-to-introduce-myself) * [Can I contribute without using the software?](#can-i-contribute-without-using-the-software) * [Can you assign this to me?](#can-you-assign-this-to-me) * [Can I use @ mentions freely in issues or PRs?](#can-i-use--mentions-freely-in-issues-or-prs) * [Can I boost my commit count?](#can-i-boost-my-commit-count) * [Can I submit AI-generated contributions?](#can-i-submit-ai-generated-contributions) * [Alternative installation options](#alternative-installation-options) * [Support for specific package formats (deb, rpm, Flatpack, AppImage, Snaps, PPA, …)](#support-for-specific-package-formats-deb-rpm-flatpack-appimage-snaps-ppa-) + [Is BIT really not supported by Canonical Ubuntu?](#is-bit-really-not-supported-by-canonical-ubuntu) * [Move project to alternative code hoster (e.g. Codeberg, GitLab, …)](#move-project-to-alternative-code-hoster-eg-codeberg-gitlab-) * [How to review a Pull Request](#how-to-review-a-pull-request) - [Testing & Building](#testing--building) * [SSH related tests are skipped](#ssh-related-tests-are-skipped) * [Setup SSH Server to run unit tests](#setup-ssh-server-to-run-unit-tests) # General ## Does _Back in Time_ support full system backups? _Back in Time_ is suited for file-based backups. A full system backup is neither supported nor recommended (even though you could use _Back in Time (root)_ and include your root folder `\`) because - Mounted file systems (even remote locations) - the backup needed to be done from within the running system - Linux kernel special files (eg. /proc) must be excluded - locked or open files (in an inconsistent state) must be handled - backups of additional disk partitions (bootloader, EFI...) are required to be able to boot - a restore cannot overwrite the running system (where the backups software is running) without the risk of crashes or losing data (for that a restore must be done from a separate boot device normally) - ... For full system backups look for - a disk imaging ("cloning") solution (eg. [Clonezilla](https://clonezilla.org/)) - file-based backup tools that are designed for this (eg. [`Timeshift`](https://github.com/linuxmint/timeshift)) ## Does _Back in Time_ support backups on cloud storage like OneDrive or Google Drive? Cloud storage as backup source or target is not support because _Back in Time_ uses `rsync` as backend for file transfer and therefore a locally mounted file system or a `ssh` connection is required. Neither is supported by cloud storage. Even with native support for mounting a cloud storage, most of the time it won't work because of limited support for 'special' file access which is used by BiT (eg. Linux hardlinks, atime). Typically "locally mounted" cloud storage uses a web-based API (REST-API) which does not support `rsync`. For a discussion about this topic see [Backup on OneDrive or Google Drive](https://github.com/bit-team/backintime/issues/1166). ## Where is the log file? There are three distinct logs generated: 1. The _backup log_ contains messages specific to a particular backup at a given time. It is stored within each backup and can be accessed through the GUI. 2. The _restore log_ contains messages specific to a particular restore process. It is displayed in the GUI after each restore. It is also located in the folder `~/.local/share/backintime/` and is named `restore_.log` for the main profile, `restore_2.log` for the second, and so forth. 3. The _application log_ is generated using the syslog feature of the operating system. See [How to read log entries?](#how-to-read-log-entries) for further details. ## How to read log entries? Both the _backup_ and _restore_ log files are plain text files and can be read accordingly. Refer to [Where is the log file?](#where-is-the-log-file). The _application_ log is generated via [syslog](https://en.wikipedia.org/wiki/Syslog) using the identifier `backintime`. Depending on the version of _Back In time_ and the GNU/Linux distribution used, there are three ways to get the log entries. 1. On modern systems: `journalctl --identifier backintime` 2. With an older _Back In Time_ version (1.4.2 or older): `journalctl --grep backintime` 3. If the error message `journalctl: command not found` appears, directly examine the syslog files: `sudo grep backintime /var/log/syslog` ## How to move backups to a new hard-drive? There are three different solutions: 1. Clone the drive with ``dd`` and enlarge the partition on the new drive to use all space. This will **destroy all data** on the destination drive! ```bash sudo dd if=/dev/sdbX of=/dev/sdcX bs=4M ``` where ``/dev/sdbX`` is the partition on the source drive and ``/dev/sdcX`` is the destination drive Finally use ``gparted`` to resize the partition. 1. Copy all files using ``rsync -H`` ```bash rsync -avhH --info=progress2 /SOURCE /DESTINATION ``` 1. Copy all files using ``tar`` ```bash cd /SOURCE; tar cf - * | tar -C /DESTINATION/ -xf - ``` Make sure that your `/DESTINATION` contains a folder named `backintime`, which contains all the backups. BIT expects this folder, and needs it to import existing backups. ## How to move a large directory in the backup source without duplicating the files in the backup? If you move a file/folder in the source ("include") location that is backed-up by BIT it will treat this like a new file/folder and create a new backup file for it (not hard-linked to the old one). With large directories this can fill up your backup drive quite fast. You can avoid this by moving the file/directory in the last backup too: 1. Create a new backup 2. Move the original directory 3. Manually move the same folder inside BiTs last backup in the same way you did with the original folder 4. Create a new backup 5. Remove the next to last backup (the one where you moved the directory manually) to avoid problems with permissions when you try to restore from that backup ## How does _Back In Time_ compare with _Timeshift_? Back In Time and Timeshift are both Linux application that provides back up functionality. 1. Similarity - Both programs are backup tools for Linux and they create backups at a specific time. - For both programs, backups are taken using rsync and hard-links, while Common files are shared between backups which saves disk space. - Both programs support GUI and CLI - Both programs allow you to schedule regular backups. You can also disable scheduled backups completely and create backups manually when required 2. Back In Time - It is designed to protect user data including any folders or files. - It backs up certain folders and files that you want to protect. Modified files are transferred, while unchanged files are linked to the new folder. You can restore certain files and folders. - It's great for protecting your personal data 3. TimeShift - It is designed for system backups which allows restoring whole Linux system to a previous state without affecting any user data. - It backs up system files, not including any personal data unless user explicitly configured. - It's good for restoring your system after an update failure or configuration change. ## Additional features beside the GUI and benefits of using BIT *Back In Time* stores the user and group name which will make it possible to restore permissions even if UID/GID changed. Additionally current user is stored. So if the User/Group doesn't exist on the system during restore it will restore to the old UID/GID. - Inhibit suspend/hibernate during backup creation - Shutdown system after finish - Remove & Retention policies to keep/remove old backups on reasonable rules - Support for Plugins and user defined callback scripts # Backups (snapshots) ## Backup or Snapshot? Until _Back In Time_ version 1.6.0 the term _snapshot_ was used, instead of _backup_. Beginning with version 1.6.0 that term was rephrased into _backup_. The reason was to not giving the impression that _Back In Time_ does create images of storage volumes. ## Does _Back In Time_ create incremental or full backups? Back In Time does use `rsync` and its `--hard-links` feature. Because of that each backup is technically a full backup (contains each file) but copies only the really changed files (to save disk space) and "reuses" unchanged files by setting a so-called "hard-link". In technical terms it is not an [incremental backups](https://en.wikipedia.org/wiki/Incremental_backup). ## How do backups with hard-links work? From the answer on Launchpad to the question [_Does auto remove smart mode merge incremental backups?_](https://answers.launchpad.net/backintime/+question/123486) If you create a new file on a Linux filesystem (e.g. ext3) the data will have a unique number that is called inode. The path of the file is a link to this inode (there is a database which stores which file point to which inode). Also every inode has a counter for how many links point to this inode. After you created a new file the counter is 1. Now you make a new hardlink. The filesystem now just has to store the new path pointing to the existing inode into the database and increase the counter of our inode by 1. If you remove a file than only the link from the path to that inode is removed and the counter is decreased by 1. If you have removed all links to that inode so the counter is zero the filesystem knows that it can override that block next time you save a new file. First time you create a new backup with BIT all files will have an inode counter = 1. #### backup0 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 1 | | fileB | 2 | 1 | | fileC | 3 | 1 | Let's say you now change ``fileB``, delete ``fileC`` and have a new ``fileD``. BIT first makes hardlinks of all files. ``rsync`` than delete all hardlinks of files that has changed and copy the new files. #### backup0 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 2 | | fileB | 2 | 1 | | fileC | 3 | 1 | #### backup1 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 2 | | fileB | 4 | 1 | | fileD | 5 | 1 | Now change ``fileB`` again and make a new backup #### backup0 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 3 | | fileB | 2 | 1 | | fileC | 3 | 1 | #### backup1 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 3 | | fileB | 4 | 1 | | fileC | 5 | 2 | #### backup2 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 3 | | fileB | 6 | 1 | | fileD | 5 | 2 | Finally smart-remove is going to remove **backup0**. All that is done by smart-remove is to ``rm -rf`` (force delete everything) the whole directory of **backup0**. #### backup0 (no longer exist) | path | inode | counter | |:-------|--------:|----------:| | (empty) | 1 | 2 | | (empty) | 2 | 0 | | (empty) | 3 | 0 | #### backup1 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 2 | | fileB | 4 | 1 | | fileD | 5 | 2 | #### backup2 | path | inode | counter | |:-------|--------:|----------:| | fileA | 1 | 2 | | fileB | 6 | 1 | | fileD | 5 | 2 | ``fileA`` is still untouched, ``fileB`` is still available in two different versions and ``fileC`` is gone for good. The blocks on your hdd that stored the data for inode 2 and 3 can now get overridden. I hope this will shed a light on the "magic" behind BIT. If it's even more confusing don't hesitate to ask ;) ## How can I check if my backups are using hard-links? Please compare the inodes of a file that definitely didn't change between two backups. For this open two terminals and ``cd`` into both backups directory. ``ls -lai`` will print a list where the first column is the inode which should be equal for the same file in both backups if the file didn't change and the backups are incremental. The third column is a counter (if the file is no directory) on how many hard-links exist for this inode. It should be >1. So if you took e.g. 3 backups it should be 3. Don't be confused on the size of each backup. If you right click on preferences for a backup in a file manager and look for its size, it will look like they are all full backups (not incremental). But that's not (necessary) the case. To get the correct size of each backups with respect on the hard-links you can run: ```bash du -chd0 /media//backintime///1/* ``` Compare with option `-l` to count hardlinks multiple times: ```bash du -chld0 /media//backintime///1/* ``` (``ncdu`` isn't installed by default so I won't recommend using it) ## How to use checksum to find corrupt files periodically? Starting with BIT Version 1.0.28 there is a new command line option ``--checksum`` which will do the same as *Use checksum to detect changes* in Options. It will calculate checksums for both the source and the last backups files and will only use this checksum to decide whether a file has changed or not. The normal mode (without checksums) is to compare modification times and sizes of the files which is much faster to detect changed files. Because this takes ages, you may want to use this only on Sundays or only the first Sunday per month. Please deactivate the schedule for your profile in that case. Then run ``crontab -e`` For daily backups on 2AM and ``--checksum`` every Sunday add: ``` # min hour day month dayOfWeek command 0 2 * * 1-6 nice -n 19 ionice -c2 -n7 /usr/bin/backintime --backup-job >/dev/null 2>&1 0 2 * * Sun nice -n 19 ionice -c2 -n7 /usr/bin/backintime --checksum --backup-job >/dev/null 2>&1 ``` For ``--checksum`` only at first Sunday per month add: ``` # min hour day month dayOfWeek command 0 2 * * 1-6 nice -n 19 ionice -c2 -n7 /usr/bin/backintime --backup-job >/dev/null 2>&1 0 2 * * Sun [ "$(date '+\%d')" -gt 7 ] && nice -n 19 ionice -c2 -n7 /usr/bin/backintime --backup-job >/dev/null 2>&1 0 2 * * Sun [ "$(date '+\%d')" -le 7 ] && nice -n 19 ionice -c2 -n7 /usr/bin/backintime --checksum --backup-job >/dev/null 2>&1 ``` Press CTRL + O to save and CTRL + X to exit (if you editor is `nano`. Maybe different depending on your default text editor). ## What is the meaning of the leading 11 characters (e.g. "cf...p.....") in my backup logs? This are from `rsync` and indicating what changed and why. Please see the section `--itemize-changes` in the [manpage](https://download.samba.org/pub/rsync/rsync.1#opt--itemize-changes) of `rsync`. See also some [rephrased explanations on Stack Overflow](https://stackoverflow.com/a/36851784/4865723). ## Backup "WITH ERRORS": [E] 'rsync' ended with exit code 23: See 'man rsync' for more details [BiT Version 1.4.0 (2023-09-14)](https://github.com/bit-team/backintime/releases/tag/v1.4.0) introduced the **evaluation of `rsync` exit codes for better error recognition**: Before this release `rsync` exit codes were ignored and only the backup files parsed for errors (which does not find each error, eg. dead symbolic links logged as `symlink has no referent`). This "exit code 23" message may occur at the end of backup logs and BiT logs when `rsync` was not able to transfer some (or even all) files. See [this comment in issue 1587](https://github.com/bit-team/backintime/issues/1587#issuecomment-1856490208) for a list all known reasons for `rsync`'s exit code 23. Currently you can ignore this error after checking the full backup log which error is hidden behind "exit code 23" (and possibly fix it - eg. delete or update dead symbolic links). We plan to implement an improved handling of exit code 23 in the future (presumably by introducing warnings into the backup log). ## What happens when I remove a backup? Each backup is stored in a dated subdirectory of the "full backup path" shown in Settings. It contains a ``backup`` directory of all the files as well as a log of the backup's creation and some other details. Removing the backup removes this whole directory. Each backup is independent of the others, so other backups are not affected. However, the data of identical files is not stored redundantly by multiple backups, so removing a backup will only recover the space used by files that are unique to that backup. ## How can I exclude cache folders to improve backup speed and reduce storage? **Why exclude cache folders?** Cache folders typically contain temporary files that are not necessary for backups. Excluding them can significantly improve backup speed and reduce storage usage. **How to exclude cache folders:** 1. Open Back in Time. 2. Go to the **Exclude Patterns** settings: - Click the "Exclude" tab in the configuration window. - Click the **Add** button to create a new exclude pattern. 3. Add the following patterns to exclude common cache directories: ```plaintext .var/app/**/[Cc]ache/ .var/app/**/media_cache/ .mozilla/firefox/**/cache/ .config/BraveSoftware/Brave-Browser/Default/Service Worker/CacheStorage/ ``` **Explanation**: - `/**/` matches any directory structure leading to the specified folder. - `[Cc]ache` matches folder names with either uppercase or lowercase "Cache." 4. Decide whether to include or exclude the folder itself: - To exclude only the folder’s content, use `/*` at the end of the pattern: ```plaintext .var/app/**/[Cc]ache/* ``` - To exclude the folder and its contents, omit the `/*`: ```plaintext .var/app/**/[Cc]ache/ ``` **Tips for better results:** - **Check Backup Logs**: After running a backup, review the logs to identify additional folders that may slow down the process. Example log entries for cache files: ```plaintext [E] Skipping file /path/to/cache/file: Too many small files. ``` - **Customize Patterns**: Adjust the patterns to suit your specific applications. For example, modify paths for browsers or other software you use. - **Test Exclude Patterns**: Test your backup after adding patterns to ensure they work as intended. ## How to use extended filesystem attributes (xattr) to exclude files/directories? Please see [Issue #817](https://github.com/bit-team/backintime/issues/817) for details. ## Are Samba shares supported? / Does Samba support hard links? There is no short answer to that. It depends on the configuration of the Samba server and the filesystem of the volume/harddisk it is using. Generally it is not recommended to use Samba shares as backup destination. Use an SSH profile instead. Further reading: - https://superuser.com/q/855946/486099 - https://github.com/bit-team/backintime/issues/1883 If you encounter clear rules about configuring Samba that it works with _Back In Time_ in a reliable way, please let us know the details. We will than integrate it into the documentation. ## How does _Back in Time_ handle open or changed files during backup? **Explanation** Back In Time uses rsync to copy the files and directories specified to be backed up in the configuration. Rsync does not lock any files that are open or being modified and therefore the backup can be copied in an inconsistent state. Rsync only reads a file on time when it goes through it and as a result of this only some changes are captured by rsync. This can affect files such as logs, browser caches, databases or virtual machine images where inconsistencies can even lead to data corruption. **To reduce this risk, the following approaches can be considered:** - **Filesystem snapshots** If using a filesystem like btrfs and ZFS that has a snapshot function this can be used together with Back in Time. Filesystem snapshots provide a read-only copy of a filesystem frozen at a specific point in time, which ensures data integrity even for open/changing files. Configure Back In Time to backup from this filesystem's read-only snapshot. - **Use exclusions** If the filesystem does not have filesystem snapshots available, one solution could be to exclude files that are frequently open or actively changing. The command `lsof` in GNU/Linux presents open files and the processes that opened them as a list. Use this list as base for configuring BIT exclusion list. - **Application specific handling** For applications that opens and modifies files frequently like databases or virtual machines, specific solutions may be needed. Use the databases own backup function to create a consistent copy and include that in the BIT backup. Virtual machines products typically have ability to create snapshots of their state, that can be included in BIT. - **Choose when to perform backup** Perform backup at times where less files are open, for example at night. # Restore ## After Restore I have duplicates with extension ".backup.20131121" This is because *Backup files on restore* in Options was enabled. This is the default setting to prevent overriding files on restore. If you don't need them any more you can delete those files. Open a terminal and run: ```bash find /path/to/files -regextype posix-basic -regex ".*\.backup\.[[:digit:]]\{8\}" ``` Check if this correctly listed all those files you want to delete and than run: ```bash find /path/to/files -regextype posix-basic -regex ".*\.backup\.[[:digit:]]\{8\}" -delete ``` ## Back In Time doesn't find my old backups on my new Computer Back In Time prior to version 1.1.0 had an option called *Auto Host/User/Profile ID* (hidden under *General* > *Advanced*) which will always use the current host- and username for the full backup path. When (re-)installing your computer you probably chose a different host name or username than on your old machine. With *Auto Host/User/Profile ID* activated Back In Time now try to find your backups under the new host- and username underneath the ``/path/to/backintime/`` path. The *Auto Host/User/Profile ID* option is gone in version 1.1.0 and above. It was totally confusing and didn't add any good. You have three options to fix this: - Disable *Auto Host/User/Profile ID* and change *Host* and *User* to match your old machine. - Rename the backups path ``/path/to/backintime/OLDHOSTNAME/OLDUSERNAME/profile_id`` to match your new host- and username. - Upgrade to a more recent version of Back In Time (1.1.0 or above). The *Auto Host/User/Profile ID* option is gone and it also comes with an assistant to restore the config from an old backup on first start. # Schedule ## How does the 'Repeatedly (anacron)' schedule work? In fact *Back In Time* doesn't use anacron anymore. It was to inflexible. But that schedule mimics anacron. BIT will create a crontab entry which will start ``backintime --backup-job`` every 15min (or once an hour if the schedule is set to *weeks*). With the ``--backup-job`` command, BIT will check if the profile is supposed to be run this time or exit immediately. For this it will read the time of the last successful run from ``~/.local/share/backintime/anacron/ID_PROFILENAME``. If this is older than the configured time, it will continue creating a backup. If the backup was successful without errors, BIT will write the current time into ``~/.local/share/backintime/anacron/ID_PROFILENAME`` (even if *Repeatedly (anacron)* isn't chosen). So, if there was an error, BIT will try again at the next quarter hour. ``backintime --backup`` will always create a new backup. No matter how many time elapsed since last successful backup. ## Will a scheduled backup run as soon as the computer is back on? Depends on which schedule you choose: - the schedule ``Repeatedly (anacron)`` will use an anacron-like code. So if your computer is back on it will start the job if the given time is gone till last backup. - with ``When drive get connected (udev)`` *Back In Time* will start a backup as soon as you connect your drive ;-) - old fashion schedules like ``Every Day`` will use cron. This will only start a new backup at the given time. If your computer is off, no backup will be created. ## If I edit my crontab and add additional entries, will that be a problem for BIT as long as I don't touch its entries? What does it look for in the crontab to find its own entries? You can add your own crontab entries as you like. *Back In Time* will not touch them. It will identify its own entries by the comment line ``#Back In Time system entry, this will be edited by the gui:`` and the following command. You should not remove/change that line. If there are no automatic schedules defined *Back In Time* will add an extra comment line ``#Please don't delete these two lines, or all custom backintime entries are going to be deleted next time you call the gui options!`` which will prevent *Back In Time* to remove user defined schedules. ## Can I use a systemd timer instead of cron? While there is no support within *Back In Time* to directly create a systemd timer, users can create a user timer and service units. Templates are provided below. Optionally adjust the value for `OnCalendar=` with a valid setting. See [`man systemd.timer`](https://manpages.debian.org/testing/systemd/systemd.timer.5) for more. **Timer**: ```ini # ~/.config/systemd/user/backintime-backup-job.timer [Unit] Description=Start a backintime backup once daily [Timer] OnCalendar=daily AccuracySec=1m Persistent=true [Install] WantedBy=timers.target ``` **Service**: ```ini # ~/.config/systemd/user/backintime-backup-job.service [Unit] Description=Run backintime backup generation [Service] Type=oneshot ExecStart=/usr/bin/nice -n19 /usr/bin/ionice -c2 -n7 /usr/bin/backintime backup-job ``` # Problems, Errors & Solutions ## OverflowError: Value 1702441408 out of range for UInt32 The _Back In Time_ GUI crashes and this exception appears in its terminal output. Known to happen on restoring (#2084) and removing (#2192) of backups. Assuming it might happen also on creating backups. The current hypothesis the problem was introduced or happens more often since the migration from PyQt version 5 to version 6 (BIT version `1.5.0`). The fix (PR #2099) was released with version `1.6.0`. For users prior to this version, there is a tiny workaround described in that [issue comment](https://github.com/bit-team/backintime/issues/2084#issuecomment-2787602155). ## `SettingsDialog` object has no attribute `cbCopyUnsafeLinks` Wenn adding a file or directory, that is in fact a symlink, to the _Include_ Tab in the _Manage profiles_ dialog, the BIT GUI crash and give the following error in the terminal. ```pytb Traceback (most recent call last): File "/usr/share/backintime/qt/manageprofiles/tab_include.py", line 185, in btn_include_add_clicked self._parent_dialog.cbCopyUnsafeLinks.isChecked() or ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'SettingsDialog' object has no attribute 'cbCopyUnsafeLinks' ``` Introduced in version `1.5.3`. Fixed in `1.6.0`. See issue [#2279](https://github.com/bit-team/backintime/issues/2279). Workaround: Don't use a symlink but the linked target. ## WARNING: A backup is already running _Back In Time_ uses signal files like `worker.lock` to avoid starting the same backup twice. Normally it is deleted as soon as the backup finishes. In some case something went wrong so that _Back In Time_ was forcefully stopped without having the chance to delete this signal file. Since _Back In Time_ does only start a new backup job (for the same profile) if the signal file does not exist, such a file need to be deleted first. But before this is done manually, it must be ensured that _Back In Time_ really is not running anymore. It can be ensured via ```bash ps aux | grep -i backintime ``` If the output shows a running instance of _Back In Time_ it must be waited until it finishes or killed via `kill `. For more details see the developer documentation: [Usage of control files (locks, flocks, logs and others)](doc/maintain/4_Control_files_usage_(locks_flocks_logs_and_others).md) ## _Back in Time_ does not start and shows: The application is already running! (pid: 1234567) This message occurs when _Back In Time_ is either already running or did not finish regularly (e.g. due to a crash) and wasn't able to delete its application lock file. Before deleting that file manually make sure no backintime process is running via `ps aux | grep -i backintime`. Otherwise, kill the process. After that look into the folder `~/.local/share/backintime` for the file `app.lock.pid` and delete it. For more details see the developer documentation: [Usage of control files (locks, flocks, logs and others)](doc/maintain/4_Control_files_usage_(locks_flocks_logs_and_others).md) ## Switching to dark or light mode in the desktop environment is ignored by BIT After restart _Back In Time_ it should adapt to the desktops current used color theme. It happens because Qt does not detect theme modifications out of the box. [Workarounds are known](https://stackoverflow.com/q/75457687), but generate a relatively large amount of code and in our opinion are not worth the effort. ## Version >= 1.2.0 works very slow / Unchanged files are backed up After updating to >= 1.2.0, BiT does a (nearly) full backup because file permissions are handled differently. Before 1.2.0 all destination file permissions were set to `-rw-r--r--`. In 1.2.0 rsync is executed with `--perms` option which tells rsync to preserve the source file permission. That's why so many files seem to be changed. If you don't like the new behavior, you can use "Expert Options" -> "Paste additional options to rsync" to add the value `--no-perms --no-group --no-owner` in that field. ## What happens if I hibernate the computer while a backup is running? *Back In Time* will inhibit automatic suspend/hibernate while a backup/restore is running. If you manually force hibernate this will freeze the current process. It will continue as soon as you wake up the system again. ## What happens if I power down the computer while a backup is running, or if a power outage happens? This will kill the current process. The new backup will stay in ``new_snapshot`` folder. Depending on which state the process was while killing the next scheduled backup can continue the leftover ``new_snapshot`` or it will remove it first and start a new one. ## What happens if there is not enough disk space for the current backup? *Back In Time* will try to create a new backup but rsync will fail when there is not enough space. Depending on ``Continue on errors`` setting the failed backup will be kept and marked ``With Errors`` or it will be removed. By default, *Back In Time* will finally remove the oldest backups until there is more than 1 GiB free space again. ## NTFS Compatibility Although devices formatted with the NTFS file system can generally be used with *Back In Time*, there are some limitations to be aware of. NTFS File systems do not support the following characters in filenames or directories: ```text < (less than) > (greater than) : (colon) " (double quote) / (forward slash) \ (backslash) | (vertical bar or pipe) ? (question mark) * (asterisk) ``` If *Back In Time* tries to copy files where the filename contains those character, an "Invalid argument (22)" error message will be displayed. It is recommended that only devices formatted with Unix style file systems (such as ext4) be used. For more information, refer to [this Microsoft page](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions). ## GUI does not scale on high resolution or 4k monitors The technical details are complex and many components of the operating system are involved. BIT itself is not involved and also not responsible for it. Several approaches might help: - Check your desktop environment or window manager for settings regarding scaling. - Because BIT is using Qt for its GUI, modifying the environment variable `QT_SCALE_FACTOR` or `QT_AUTO_SCREEN_SCALE_FACTOR`. See [this article](https://doc.qt.io/qt-6/highdpi.html) and [Issue #1946](https://github.com/bit-team/backintime/issues/1946) about more details. ## Tray icon or other icons not shown correctly **Status: Fixed in v1.4.0** Missing installations of Qt-supported themes and icons can cause this effect. _Back In Time_ may activate the wrong theme in this case leading to some missing icons. A fix for the next release is in preparation. As clean solution, please check your Linux settings (Appearance, Styles, Icons) and install all themes and icons packages for your preferred style via your package manager. See issues [#1306](https://github.com/bit-team/backintime/issues/1306) and [#1364](https://github.com/bit-team/backintime/issues/1364). ## Non-working password safe and BiT forgets passwords (keyring backend issues) **Status: Fixed in v1.3.3 (mostly) and v1.4.0** _Back in Time_ does only support selected "known-good" backends to set and query passwords from a user-session password safe by using the [`keyring`](https://github.com/jaraco/keyring) library. Enabling a supported keyring requires manual configuration of a configuration file until there is e.g. a settings GUI for this. Symptoms are DEBUG log output (with the command line argument `--debug`) of keyring problems can be recognized by output like: ``` DEBUG: [common/tools.py:829 keyringSupported] No appropriate keyring found. 'keyring.backends...' can't be used with BackInTime DEBUG: [common/tools.py:829 keyringSupported] No appropriate keyring found. 'keyring.backends.chainer' can't be used with BackInTime ``` To diagnose and solve this follow these steps in a terminal: ``` # Show default backend python3 -c "import keyring.util.platform_; print(keyring.get_keyring().__module__)" # List available backends: keyring --list-backends # Find out the config file folder: python3 -c "import keyring.util.platform_; print(keyring.util.platform_.config_root())" # Create a config file named "keyringrc.cfg" in this folder with one of the available backends (listed above) [backend] default-keyring=keyring.backends.kwallet.DBusKeyring ``` See also issue [#1321](https://github.com/bit-team/backintime/issues/1321) ## Outdated ### Segmentation fault on Exit This problem existed at least since version 1.2.1, and should hopefully be fixed with version 1.5.0. For all affected versions, it does not impact the functionality of _Back In Time_ or jeopardize backup integrity. It can be safely ignored. But please report the error when encountered in version 1.5.0 or newer. See also: - [#1768](https://github.com/bit-team/backintime/pull/1768) - [#1095](https://github.com/bit-team/backintime/issues/1095) ### Incompatibility with rsync 3.2.4 or newer **Status: Fixed in v1.3.3** The release (`1.3.2`) and earlier versions of _Back In Time_ are incompatible with `rsync >= 3.2.4` ([#1247](https://github.com/bit-team/backintime/issues/1247)). If you use `rsync >= 3.2.4` and `backintime <= 1.3.2` there is a workaround. Add `--old-args` in [_Expert Options_ / _Additional options to rsync_](https://backintime.readthedocs.io/en/latest/settings.html#expert-options). Note that some GNU/Linux distributions (e.g. Manjaro) using a workaround with environment variable `RSYNC_OLD_ARGS` in their distro-specific packages for _Back In Time_. In that case you may not see any problems. # Hardware-specific Setup ## How to use BIT with an Ugreen NAS? Please see [this blogpost](https://www.ruinelli.ch/how-to-use-backintime-with-an-ugreen-nas) by George Ruinelli @caco3. ## How to use QNAP QTS NAS with BIT over SSH To use *BackInTime* over SSH with a QNAP NAS there is still some work to be done in the terminal. **WARNING**: DON'T use the changes for ``sh`` suggested in ``man backintime``. This will damage the QNAP admin account (and even more). Changing ``sh`` for another user doesn't make sense either because SSH only works with the QNAP admin account! Please test this Tutorial and give some feedback! 1. Activate the SSH prefix: ``PATH=/opt/bin:/opt/sbin:\$PATH`` in ``Expert Options`` 1. Use ``admin`` (default QNAP admin) as remote user. Only this user can connect through SSH. Also activate on the QNAP `SFTP` on the SSH settings page. 1. Path should be something like ``/share/Public/`` 1. Create the public/private key pair for the password-less login with the user you use for *BackInTime* and copy the public key to the NAS. ```bash ssh-keygen -t rsa ssh-copy-id -i ~/.ssh/id_rsa.pub @ ``` To fix the message about not supported ``find PATH -type f -exec`` you need to install ``Entware-ng``. QNAPs QTS is based on Linux but some of its packages have limited functionalities. And so do some of the necessary ones for *BackInTime*. Please follow [this install instruction](https://github.com/Entware-ng/Entware-ng/wiki/Install-on-QNAP-NAS) to install ``Entware-ng`` on your QNAP NAS. Because there is no web interface yet for ``Entware-ng``, you must configure it by SSH on the NAS. Some Packages will be installed by default for example ``findutils``. Login on the NAS and updated the Database and Packages of ``Entware-ng`` with ```bash ssh @ opkg update opkg upgrade ``` Finally install the current packages of ``bash``, ``coreutils`` and ``rsync`` ```bash opkg install bash coreutils rsync ``` Now the error message should be gone and you should be able to take a first backup with *BackInTime*. *BackInTime* changes permissions on the backup path. The owner of the backup has read permission, other users have no access. This way can change with newer versions of *BackInTime* or QNAPs QTS! ## How to use Synology DSM 5 with BIT over SSH **Issue** *BackInTime* cannot use Synology DSM 5 directly because the SSH connection to the NAS refers to a different root file system than SFTP does. With SSH you access the real root, with SFTP you access a fake root (`/volume1`) **Solution** Mount `/volume1/backups` to `/volume1/volume1/backups` **Suggestion** DSM 5 isn't really up to date any more and might be a security risk. It is strongly advised to upgrade to DSM 6! Also the setup with DSM 6 is much easier! 1. Make a new volume named ``volume1`` (should already exist, else create it) 1. Enable User Home Service (Control Panel / User) 1. Make a new share named ``backups`` on ``volume1`` 1. Make a new share named ``volume1`` on ``volume1`` (It must be the same name) 1. Make a new user named ``backup`` 1. Give to user ``backup`` rights Read/Write to share ``backups`` and ``volume1`` and also permission for FTP 1. Enable SSH (Control Panel / Terminal & SNMP / Terminal) 1. Enable SFTP (Control Panel / File Service / FTP / SFTP) 1. Enable rsync service (Control Panel / File Service / rsync) 1. Since DSM 5.1: Enable Backup Service (Backup & Replication / Backup Service) (This seems not to be available/required anymore with DSM 6!) 1. Log on as root by SSH 1. Modify the shell of user ``backup``. Set it to ``/bin/sh`` (``vi /etc/passwd`` then navigate to the line that begins with ``backup``, press :kbd:`I` to enter ``Insert Mode``, replace ``/sbin/nologin`` with ``/bin/sh``, then finally save and exit by pressing :kbd:`ESC` and type ``:wq`` followed by :kbd:`Enter`) This step might have to be repeated after a major update of the Synology DSM! Note: This is quite a dirty hack! It is suggested to upgrade to DSM 6 which doesn't need this any more! 1. Make a new directory ``/volume1/volume1/backups`` ```bash mkdir /volume1/volume1/backups ``` 1. Mount ``/volume1/backups`` on ``/volume1/volume1/backups`` ```bash mount -o bind /volume1/backups /volume1/volume1/backups ``` 1. To auto-mount it make a script ``/usr/syno/etc/rc.d/S99zzMountBind.sh`` ```bash #!/bin/sh start() { /bin/mount -o bind /volume1/backups /volume1/volume1/backups } stop() { /bin/umount /volume1/volume1/backups } case "$1" in start) start ;; stop) stop ;; *) ;; esac ``` Note: If the folder ``/usr/syno/etc/rc.d`` doesn't exist, check if ``/usr/local/etc/rc.d/`` exists. If so, put it there. (After I updated to Synology DSM 6.0beta, the first one did not exist anymore). Make sure the execution flag of the file is checked , else it will not get run at start! To make it executable, run: ``chmod +x /usr/local/etc/rc.d/S99zzMountBind.sh`` 1. On the workstation on which you try to use BIT make SSH keys for user ``backup``, send the public key to the NAS ```bash ssh-keygen -t rsa -f ~/.ssh/backup_id_rsa ssh-add ~/.ssh/backup_id_rsa ssh-copy-id -i ~/.ssh/backup_id_rsa.pub backup@ ssh backup@ ``` 1. You might get the following error: ```bash /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system. ``` 1. If so, copy the public key manually to the NAS as root with ```bash scp ~/.ssh/id_rsa.pub backup@:/var/services/homes/backup/ ssh backup@ cat /var/services/homes/backup/id_rsa.pub >> /var/services/homes/backup/.ssh/authorized_keys # you'll still be asked for your password on these both commands # after this you should be able to login password-less ``` 1. And proceed with the next step 1. If you are still prompted for your password when running ``ssh backup@``, check the permissions of the file ``/var/services/homes/backup/.ssh/authorized_keys``. It should be ``-rw-------``. If this is not the case, run the command ```bash ssh backup@ chmod 600 /var/services/homes/backup/.ssh/authorized_keys ``` 1. Now you can use *BackInTime* to perform your backup to your NAS with the user ``backup``. ## How to use Synology DSM 6 with BIT over SSH 1. Enable User Home Service (Control Panel / User / Advanced). There is no need to create a volume since everything is stored in the home directory. 1. Make a new user named ``backup`` (or use your existing account). Add this user to the user group ``Administrators``. Without this, you will not be able to log in! 1. Enable SSH (Control Panel / Terminal & SNMP / Terminal) 1. Enable SFTP (Control Panel / File Service / FTP / SFTP) 1. Since DSM 5.1: Enable Backup Service (Backup & Replication / Backup Service) (This seems not to be available/required anymore with DSM 6!) (Tests needed!) 1. On DSM 6 you can edit the user-root-dir for sFTP: Control Panel -> File Services -> FTP -> General -> Advanced Settings -> Security Settings -> Change user root directories -> Select User. Now select the user ``backup`` and Change root directory to ``User home`` 1. On the workstation on which you try to use BIT make SSH keys for user ``backup``, send the public key to the NAS ```bash ssh-keygen -t rsa -f ~/.ssh/backup_id_rsa ssh-add ~/.ssh/backup_id_rsa ssh-copy-id -i ~/.ssh/backup_id_rsa.pub backup@ ssh backup@ ``` 1. You might get the following error: ```bash /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system. ``` 1. If so, copy the public key manually to the NAS as root with ```bash scp ~/.ssh/id_rsa.pub backup@:/var/services/homes/backup/ ssh backup@ cat /var/services/homes/backup/id_rsa.pub >> /var/services/homes/backup/.ssh/authorized_keys # you'll still be asked for your password on these both commands # after this you should be able to login password-less ``` 1. And proceed with the next step 1. If you are still prompted for your password when running ``ssh backup@``, check the permissions of the file ``/var/services/homes/backup/.ssh/authorized_keys``. It should be ``-rw-------``. If this is not the case, run the command ```bash ssh backup@ chmod 600 /var/services/homes/backup/.ssh/authorized_keys ``` 1. In *BackInTime* settings dialog leave the *Path* field empty 1. Now you can use *BackInTime* to perform your backup to your NAS with the user ``backup``. ### Using a non-standard port If you want to use the Synology NAS with non-standard SSH/SFTP port (standard is 22), you have to change the Port on total 3 places: 1. Control Panel > Terminal: Port = 1. Control Panel > FTP > SFTP: Port = 1. Backup & Replication > Backup Services > Network Backup Destination: SSH encryption port = Only if all 3 of them are set to the same port, *BackInTime* is able to establish the connection. As a test, one can run the command ```bash rsync -rtDHh --checksum --links --no-p --no-g --no-o --info=progress2 --no-i-r --rsh="ssh -p -o IdentityFile=/home//.ssh/id_rsa" --dry-run --chmod=Du+wx /tmp/ "@:/volume1/Backups/BackinTime" ``` in a terminal (on the client PC). ## How to use Synology DSM 7 with BIT over SSH 1. Enable *User Home Service* (Control Panel > User & Group > Advanced). 1. Make a new user named ``backup`` (or use your existing account) and add this user to the user group ``Administrators``. 1. Enable *SSH* (Control Panel > Terminal & SNMP > Terminal) 1. Enable *SFTP* (Control Panel > File Services > FTP > SFTP) 1. Enable *rsync* (Control Panel > File Services > rsync) 1. Edit the user-root-directory for SFTP: Control Panel > File Services > FTP > General > Advanced Settings > Security Settings > Change user root directories > Select User > select the user ``backup`` > Edit and Change root directory to ``User home`` 1. Make sure the 'homes' shared folder has the default permissions and that non-admin users and groups are not assigned Read or Write permissions on the 'homes' folder. The default permissions are described in [this guide](https://kb.synology.com/DSM/tutorial/default_permissions_of_homes) 1. On the workstation on which you need to use BIT, make an SSH key pair for user ``backup``, and send the public key to the NAS: ```bash ssh-keygen -t rsa -f ~/.ssh/backup_id_rsa ssh-copy-id -i ~/.ssh/backup_id_rsa.pub backup@ ssh backup@ ``` 1. Although not strictly necessary, Synology recommend setting the permissions for the `.ssh` directory and the `authorized_keys` file to `700`, and `600` respectively: ```bash backup@NAS:~$ chmod 700 .ssh backup@NAS:~$ chmod 600 .ssh/authorized_keys ``` 1. In *BackInTime* settings dialog leave the *Path* field empty 1. Now you can use *BackInTime* to perform your backup to your NAS with the user ``backup``. ### Using a non-standard SSH port with a Synology NAS If you want to use the Synology NAS with a non-standard SSH/SFTP port as advised by the Security Advisor package, you have to change the Port in 3 places (the default port number for all three is 22): 1. Control Panel > Terminal & SNMP > Terminal: Port = 1. Control Panel > File Services > FTP > SFTP: Port number = 1. Control Panel > File Services > rsync > SSH encryption port = Only if all 3 are set to the same port is *BackInTime* able to establish the connection (don't forget to set the new port number in the BIT profiles). To sign in with ssh using the new port number: ```bash ssh -p PORT_NUMBER backup@ ``` or, for convenience you can edit or create ``~/.ssh/config`` with the following: ``` Host Port PORT_NUMBER ``` and then use just: ```bash ssh backup@ ``` ### "sshfs: No such file or directory" using BIT, but manually ssh with rsync works The reason (known for DSM version 7) is that the setup of ssh and sftp is customized by Synology. Solution ([Screenshot in Issue #1674](https://github.com/bit-team/backintime/issues/1674#issuecomment-2106059151)): 1. Go to: _Control Panel_ > _File Services_ > _Advanced Settings_ > _Change user root directories_ > _Select User_ 2. Add the name of the user used for SSH on the Synology in that list. 3. At _Change root directory to:_ select _User home_. See also - [Issue #1674](https://github.com/bit-team/backintime/issues/1674) - ["Change the default folder in a Synology NAS" - StackOverflow](https://stackoverflow.com/a/77454561/4865723) ## Synology: use different volume for backup This was tested and related to Synology DSM version 7, but might work with other versions, too. Feel free to report back. If you want to use a different volume as the destination for the backup use these additional steps: 1. Follow all steps under **Howto (like create additional user in the example name of the user 'backup') 2. Create in the Synology DSM GUI in Control panel a new shared folder name it "backup" for example ![Synology DSM7 Basic Setup](doc/images.misc/faq_synology7_separate_dest_volume01.png) 3. Optional in step-2 Enable shared folder encryption (Depending on your needs, don't loose your encryption key) Advantage: backup folder (volume) is encrypted, even in case of theft of your Synology NAs Disadvantage: On each Reboot you need to mount the folder manually ![Synology DSM7 Additional Security Measure](doc/images.misc/faq_synology7_separate_dest_volume02.png) 4. As user root or with sudo edit the file: `/etc/passwd` (Be careful, if you break it, you could break your NAS) - `vi /etc/passwd` - Edit the line for your user backup, so the home dir is on the newly created folder: `backup:x:1038:100:Back in Time User:/volume1/backup:/bin/sh` 5. Continue with your normal setup of BIT ## How to use Western Digital MyBook World Edition with BIT over ssh? Device: *WesternDigital MyBook World Edition (white light) version 01.02.14 (WD MBWE)* The BusyBox that is used by WD in MBWE for serving basic commands like ``cp`` (copy) doesn't support hardlinks. Which is a rudimentary function for BackInTime's way of creating incremental backups. As a work-around you can install Optware on the MBWE. Before proceeding please make a backup of your MBWE. There is a significant chance to break your device and lose all your data. There is good documentation about Optware on http://mybookworld.wikidot.com/optware. 1. You have to login to MBWE's web admin and change to *Advanced Mode*. Under *System | Advanced* you have to enable *SSH Access*. Now you can log in as root over ssh and install Optware (assuming ```` is the address of your MyBook). Type in terminal: ```bash ssh root@ #enter 'welc0me' for password (you should change this by typing 'passwd') wget http://mybookworld.wikidot.com/local--files/optware/setup-whitelight.sh sh setup-whitelight.sh echo 'export PATH=$PATH:/opt/bin:/opt/sbin' >> /root/.bashrc echo 'export PATH=/opt/bin:/opt/sbin:$PATH' >> /etc/profile echo 'PermitUserEnvironment yes' >> /etc/sshd_config /etc/init.d/S50sshd restart /opt/bin/ipkg install bash coreutils rsync nano exit ``` 1. Back in MBWE's web admin go to *Users* and add a new user (```` in this How-to) with *Create User Private Share* set to *Yes*. In terminal: ```bash ssh root@ chown /shares/ chmod 700 /shares/ /opt/bin/nano /etc/passwd #change the line #:x:503:1000:Linux User,,,:/shares:/bin/sh #to #:x:503:1000:Linux User,,,:/shares/:/opt/bin/bash #save and exit by press CTRL+O and CTRL+X exit ``` 1. Next create the ssh-key for your local user. In the terminal ```bash ssh @ mkdir .ssh chmod 700 .ssh echo 'PATH=/opt/bin:/opt/sbin:/usr/bin:/bin:/usr/sbin:/sbin' >> .ssh/environment exit ssh-keygen -t rsa #enter for default path ssh-add ~/.ssh/id_rsa scp ~/.ssh/id_rsa.pub @:./ #enter password from above ssh @ #you will still have to enter your password cat id_rsa.pub >> .ssh/authorized_keys rm id_rsa.pub chmod 600 .ssh/* exit ssh @ #this time you shouldn't been asked for password anymore exit ``` 1. You can test if everything is done by enter this ```bash ssh @ cp --help ``` The output should look like: ```bash Usage: cp [OPTION]... [-T] SOURCE DEST or: cp [OPTION]... SOURCE... DIRECTORY or: cp [OPTION]... -t DIRECTORY SOURCE... Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. Mandatory arguments to long options are mandatory for short options too. -a, --archive same as -dR --preserve=all --backup[=CONTROL] make a backup of each existing destination file -b like --backup but does not accept an argument --copy-contents copy contents of special files when recursive ... (lot more lines with options) ``` But if your output looks like below you are still using the BusyBox and will not be able to run backups with *BackInTime* over ssh: ```bash BusyBox v1.1.1 (2009.12.24-08:39+0000) multi-call binary Usage: cp [OPTION]... SOURCE DEST ``` # Project & Contributing & more ## Why do I need to introduce myself? It helps maintainers understand who you are and how to communicate with you. This saves unnecessary effort on both sides by avoiding misunderstandings that could lead to rejected contributions. It also helps distinguish genuine contributors from accounts submitting low-quality or AI-generated changes merely to inflate commit statistics or stars, without real engagement in the project. Here is a small suggestion and guidance for your introduction: - How long and in what way have you been using BIT? - What experience and skills do you have in software development? - What are your current learning goals? - How did you become aware of this issue? ## Can I contribute without using the software? No, in most cases. Contributors must be users of _Back In Time_. Real contributions require familiarity with the software, its behavior, and workflows. Real contributions come from real usage. ## Can you assign this to me? No. Don't ask. Comment with intent or a plan first. Otherwise its just noise. Your behavior disrespects contributors with real intent, and burden maintainers who work on this project in their free time. Don't waste our time. ## Can I use @ mentions freely in issues or PRs? No. Never. Avoid them in all cases. Mentions trigger notifications and create noise. Maintainers and subscribed contributors already see all activity. ## Can I boost my commit count? No. Doing that can get your account blocked or deleted, because mainters will report you to the abuse team of Microsoft. This project isn't for collecting stars or commits. Maybe watching [Don't Contribute to Open Source](https://www.youtube.com/watch?v=5nY_cy8zcO4) will help you to understand and learn. ## Can I submit AI-generated contributions? No. AI-generated contributions are prohibited. Attempting this will be reported to Microsoft abuse team, and your account may be blocked or deleted. ## Alternative installation options Besides the repositories of the official GNU/Linux distributions, there are other alternative installation options provided and maintained by third parties. Use them at your own risk and please contact that third party maintainers if you encounter problems. **Again**: We strongly recommend not to use 3rd party repositories because of possible security issues. - [@jean-christophe-manciot](https://github.com/jean-christophe-manciot)'s PPA distributing [_Back In Time_ for the latest stable Ubuntu release](https://git.sdxlive.com/PPA/about). See [PPA requirements](https://git.sdxlive.com/PPA/about/#requirements) and [install instructions](https://git.sdxlive.com/PPA/about/#installing-the-ppa). - The Arch User Repository ([AUR](https://aur.archlinux.org/)) does offer [some packages](https://aur.archlinux.org/packages?K=backintime). ## Support for specific package formats (deb, rpm, Flatpack, AppImage, Snaps, PPA, …) We assist and support other projects providing specific distribution packages. Thus, we suggest creating your own repository to manage and maintain such packages. It will be mentioned in our documentation as an alternative source for installation. We do not directly support third-party distribution channels associated with specific GNU/Linux distributions, unofficial repositories (e.g. Arch AUR, Launchpad PPA) or FlatPack & Co. One reasons is our lack of resources and the need to prioritize tasks. Another reasons is that their are distro maintainers with much more experience and skills in packaging. We always recommend using the official repositories of GNU/Linux distributions and contacting their maintainers if _Back In Time_ is unavailable or out dated. ## Is BIT really not supported by Canonical Ubuntu? Ubuntu consists of [several repositories](https://help.ubuntu.com/community/Repositories), each offering different levels of support. The `main` repository is maintained by Canonical and receives regular security updates and bug fixes throughout the 5-year support period of LTS releases. In contrast, the `universe` repository is community-managed, meaning security updates and bug fixes are not guaranteed and depend heavily on community activity and volunteers. Therefore, packages in `universe` may not always be up-to-date with the same but well-maintained packages in Debian GNU/Linux and might miss important fixes. _Back In Time_ is one such package in the `universe` repository. That [package](https://packages.ubuntu.com/search?suite=all&searchon=names&keywords=backintime) is copied from the [Debian GNU/Linux repository](https://packages.debian.org/search?searchon=sourcenames&keywords=backintime). It can be said that _Back In Time_ is not maintained by Canonical Ubuntu, but by volunteers from the Community of Ubuntu. ## Move project to alternative code hoster (e.g. Codeberg, GitLab, …) We also believe that staying with Microsoft GitHub is not a good idea. Microsoft GitHub does not offer any exclusive feature for our project that another hoster could not also provide. But a migration is a matter of time and resources we currently do not have. But it is on our list. And with the current state of discussion we seem to target [Codeberg.org](https://codeberg.org). For more details please see [this thread on the mailing list](https://mail.python.org/archives/list/bit-dev@python.org/message/O5XZ5SPW6WIFBFKWUBHSOUIBKEUIBPNM/). ## How to review a Pull Request Reviewing a Pull Request (PR) isn’t just about the code—it’s also about functionality. Changes can be tested by installing _Back In Time_ and trying them out, even without reading the code. This allows issues to be identified from a user’s perspective. A second pair of eyes helps catch errors, spot overlooked issues, and improve overall quality. Fresh perspectives, knowledge sharing, and better maintainability contribute to the long-term stability of the project. Check PRs labeled with [PR: Waiting for review](https://github.com/bit-team/backintime/pulls?q=is%3Aopen+is%3Apr+label%3A%22PR%3A+Waiting+for+review%22). Checking the [milestone](https://github.com/bit-team/backintime/milestones) assigned to PR can also help gauge their priority and urgency. - Start by carefully reading the PR description to understand the proposed changes. Ask back if something is not clear. - When giving feedback, consider the contributor’s level of experience and skills. Keep it polite and constructive—every beginner could be a future maintainer. To **test functionality**, [check out the PR code locally](https://docs.github.com//pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally) on a virtual machine or your local machine. Running _Back In Time_ in a test environment provides insights, that can be shared as findings, observations, or suggestions for improvement. About **code review**: - Code should follow [project standards](CONTRIBUTING.md#best-practice-and-recommendations) and be structured for long-term maintainability. - Is a PR too large or complex, suggest to breaking it down into smaller parts. - How is the documentation? - Are there unit tests? - Does the changelog need an entry? # Testing & Building ## SSH related tests are skipped They get skipped if no SSH server is available. Please see section [Testing & Building](CONTRIBUTING.md#testing--building) about how to setup a SSH server on your system. ## Setup SSH Server to run unit tests Please see section [Testing - SSH](CONTRIBUTING.md#ssh). backintime-1.6.1/HISTORY.md000066400000000000000000000163571514264426600153360ustar00rootroot00000000000000 # Looking back in time at _Back In Time_ *by Michael Büker, 2024* The development of _Back In Time_ was inspired by [FlyBack](https://en.wikipedia.org/wiki/FlyBack). The history of the _Back In Time_ project, which at the time of this writing already spans nearly 16 years and is best understood in four periods: 1. The **First Era** from 2008 to 2012, releases 0.5 to ~1.0.12 2. The **Second Era** from 2012 to 2019, releases ~1.0.14 to 1.2 3. A **Dark Age** from 2019 to 2022, releases 1.2.0 to 1.3.2 4. The **Third Era** since 2022, since release 1.3.3 These periods correspond roughly to who was maintaining and developing _Back In Time_. Important technical and organizational changes happened at various moments in between. For details, refer to [CHANGES](CHANGES). For a glimpse into the future, see the [Strategy Outline](CONTRIBUTING.md#strategy-outline). # The First Era: 0.5 to ~1.0.12 (2008–2012) ## Maintenance _Back In Time_ was created by **Oprea Dan** and first published on a private blog in late 2008 ([wayback link](https://web.archive.org/web/20081014041759/http://www.le-web.org/2008/10/03/back-in-time-version-05/)). Shortly thereafter, collaborative development started happening on Launchpad. Sometime around 2010, development and publication appears to have moved entirely to Launchpad, with the private blog being discontinued. ## Core functionality At first, _Back In Time_ used `diff` to compare the latest backup with the source, in order to check if a new backup was necessary. If the answer was yes, it would use `cp` to create a new backup. This was changed in version 0.9.2 in early 2009, when `diff` was replaced by `rsync` for the comparison. Copying was still done by `cp`, apparently without special permissions handling. This changed when, shortly thereafter, version 0.9.24 introduced `fileinfo.bz2`, which holds permissions information on all files in a backup. Introduced to allow saving backups on non-Unix-permission-aware filesystems like NTFS, `fileinfo.bz2` is consulted upon restoring a file in order to recreate its original ownership and permissions. ## GUI Initially, _Back In Time_ had only a GNOME GUI. Version 0.9 from early 2009 separated the backend (`backintime-common`) from the GUI, allowing for different frontends. Over the course of 2009, finishing roughly with version 0.9.24, two separate frontends were completed: `backintime-gnome` and `backintime-kde4`. # The Second Era: ~1.0.14 to 1.2 (2012–2019) ## Maintenance Around 2012, **Germar Reitze** took over publication, maintenance and further development from Oprea Dan. In early 2016, starting with version 1.1.10, development and publication moved to Microsoft GitHub, leaving the Launchpad project mostly abandoned (except for translation management and PPA publication). ## Core functionality Development during the Second Era centered largely around remote backup capabilities. In late 2012, version 1.0.12 introduced remote backup locations enabled by `ssh`. In early 2013, version 1.0.22 introduced an optional "full rsync mode". This replaced `cp` with `rsync` for all operations, including full replication of permissions. In late 2013, version 1.0.26 introduced encrypted backup locations enabled by `encfs`. ## GUI In early 2015, version 1.1.0 eliminated the separate `backintime-gnome` and `backintime-kde4` frontends and introduced `backintime-qt4` as the only frontend. # The Dark Age: 1.2.0 to 1.3.2 (2019–2022) In 2019, version 1.2.0 was released. It was the first release since version 1.1.24 in late 2017 and contained many bugfixes accumulated over the previous 1.5 years. Version 1.2.0 introduced a fundamental change: ***"make full-rsync mode default, remove the other mode"***. This meant that files would always be transferred by `rsync` instead of `cp`. Specifically, `rsync` was instructed to retain full ownership and permissions information when transferring the files to the backup (*in addition* to the information stored in `fileinfo.bz2`). This caused bug [#988](https://github.com/bit-team/backintime/issues/988), which broke _Back In Time_'s core functionality for any backup created with version <1.2.0 (unless "full rsync mode" had been enabled): many unchanged files were no longer hardlinked upon transferring, but unnecessarily copied. This led to very long backup times and high disk usage. A related bug with a somewhat smaller impact is [#994](https://github.com/bit-team/backintime/issues/994). As these bugs are currently understood, the underlying reason for the problem is differing ownership/permissions between the files in the source and on the backup drive. Since multiple hardlinks to the same file are, by definition, identical, they cannot have differing permissions. `rsync` fails to handle this case correctly when a new backup is created, leading to the files in question being copied unnecessarily. With many users complaining and trading workarounds on Microsoft GitHub, development soon came to a halt. Some bugs were fixed with version 1.3.0 in 2021, but [#988](https://github.com/bit-team/backintime/issues/988) and [#994](https://github.com/bit-team/backintime/issues/994) remained. # The Third Era: since 1.3.3 (since 2022) In early 2022, an epic discussion on the state of the project arose in [#1232](https://github.com/bit-team/backintime/issues/1232). Many users declared their love for _Back In Time_, and a few were ready to step up and restart development. With help and permission from Germar Reitze, **Christian Buhtz**, **Jürgen Altfeld** and **Michael Büker** formed a new core team. The team first curated and triaged over 200 open issues that had accumulated since 2019. The first release by the new team was version 1.3.3 in early 2023. Early work focused on ensuring compatibility with rsync 3.2.4, fixing keyring issues for SSH operations, system tray functionality in both X11 and Wayland as well as testing, coding style and other modernization to align _Back In Time_ with current Python practices. ## Core functionality Work on fixing [#988](https://github.com/bit-team/backintime/issues/988) and [#994](https://github.com/bit-team/backintime/issues/994) is still ongoing as of this writing. These bugs are largely understood now, but any possible fix could potentially have grave consequences for existing backups, which have not been thoroughly tested for. Given that EncFS suffers from known security issues and is not actively maintained, _Back In Time_ is preparing to deprecate it in the foreseeable future ([#1734](https://github.com/bit-team/backintime/issues/1734)). ## GUI The GUI is slated for a redesign and code refactoring, as it has become complex and convoluted over the years. A commonly requested feature is a terminal user interface (TUI), or an enhancement of the existing command-line interface (CLI), as discussed in [#254](https://github.com/bit-team/backintime/issues/254). The proposal for a web frontend was rejected ([#209](https://github.com/bit-team/backintime/issues/209)), but separate projects offering a web fronted would be supported. backintime-1.6.1/LICENSES.md000066400000000000000000000016061514264426600153710ustar00rootroot00000000000000 The directory [`LICENSES`](LICENSES) contains all relevant license files regarding the _Back In Time_ project. The projects primary license is [GNU General Public License v2.0 or later (`GPL-2.0-or-later`)](https://spdx.org/licenses/GPL-2.0-or-later.html). Copyright and license information are available for each file via [SPDX metadata](https://spdx.dev) following [REUSE.software standard](https://reuse.software). Read the header of each file and the `REUSE.toml` files, or use the `reuse` tool to extract the information. Refer to [`README.md`](README.md) for further information about the project. backintime-1.6.1/LICENSES/000077500000000000000000000000001514264426600150445ustar00rootroot00000000000000backintime-1.6.1/LICENSES/CC0-1.0.txt000066400000000000000000000156101514264426600164510ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. backintime-1.6.1/LICENSES/GPL-2.0-or-later.txt000066400000000000000000000416711514264426600202600ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice backintime-1.6.1/LICENSES/GPL-3.0-or-later.txt000066400000000000000000001035621514264426600202570ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . backintime-1.6.1/LICENSES/MIT.txt000066400000000000000000000020661514264426600162420ustar00rootroot00000000000000MIT License Copyright (c) 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. backintime-1.6.1/README.md000066400000000000000000000160371514264426600151250ustar00rootroot00000000000000 [![Mailing list bit-dev@python.org](doc/maintain/_images/badge_bit-dev.svg)](https://mail.python.org/mailman3/lists/bit-dev.python.org/) [![Mastodon @backintime@fosstodon.org](doc/maintain/_images/badge_mastodon.svg)](https://fosstodon.org/@backintime) [![Build Status](https://app.travis-ci.com/bit-team/backintime.svg)](https://app.travis-ci.com/bit-team/backintime) [![User manual Status](https://readthedocs.org/projects/backintime/badge/?version=latest)](https://backintime.readthedocs.io) [![Translation status](https://translate.codeberg.org/widget/backintime/common/svg-badge.svg)](https://translate.codeberg.org/engage/backintime) [![REUSE status](https://api.reuse.software/badge/github.com/bit-team/backintime)](https://api.reuse.software/info/github.com/bit-team/backintime) # Back In Time _Back In Time_ is a comfortable and well-configurable graphical frontend for incremental backups using [`rsync`](https://rsync.samba.org/), with a command-line version also available. Modified files are transferred, while unchanged files are linked to the new folder using rsync's hard link feature, saving storage space. Restoring is straightforward via file manager, command line or _Back In Time_ itself. It is written in Python3 and available for all major GNU/Linux distributions as command line tool `backintime` and GUI `backintime-qt`. Backups can be scheduled and stored locally or remotely through SSH. More background info in [CONTRIBUTING](CONTRIBUTING.md) and [HISTORY](HISTORY.md). ## Maintenance status The project is in active development since the [new team](#the-team) joined in summer 2022. Development is done voluntarily in spare time so things need to be prioritized. Stick with us, we all ♥️ _Back In Time_. 😁 Current focus is on fixing [major issues](https://github.com/bit-team/backintime/issues?q=is%3Aissue+is%3Aopen+label%3AHigh) instead of implementing new [features](https://github.com/bit-team/backintime/labels/Feature). Stabilize the code base and its test suite is also a matter. Read the [strategy outline](CONTRIBUTING.md#strategy-outline) for details. Please see [CONTRIBUTING](CONTRIBUTING.md) if you are interested in the development and have a look on [open issues](https://github.com/bit-team/backintime/issues) especially those labeled as [good first issues](https://github.com/bit-team/backintime/labels/GOOD%20FIRST%20ISSUE) and [help wanted](https://github.com/bit-team/backintime/issues?q=is%3Aissue+is%3Aopen+label%3AHELP-WANTED). ## The team Since around 2024, [@buhtz](https://buhtz.codeberg.page/), part of the projects third generation of maintainers, has been the sole maintainer. He handles all core tasks, from code analysis and documentation to issue resolution and feature implementation. The work is carried out voluntarily during spare time. The project continues to benefit from an active and engaged community that provides advice, expertise, and contributions, ensuring it thrives and evolves. The project was [reactivated in 2022](https://github.com/bit-team/backintime/issues/1232)) and thanks in large part to @emtiu and @aryoda, who helped relaunch and shape its direction. See [HISTORY](HISTORY.md) for more details. # Index - [Documentation](#documentation) - [Contact & Social](#contact--social) - [Installation](#installation) - [Known Problems and Workarounds](#known-problems-and-workarounds) - [Contributing and other ways to support the project](#contributing-and-other-ways-to-support-the-project) - [Licenses](#licenses) --- # Documentation * [FAQ - Frequently Asked Questions](FAQ.md) * [End user documentation](https://backintime.readthedocs.org/) (not totally up-to-date) * [Source code documentation for developers](https://backintime-dev.readthedocs.org) (**Disabled** and not up-2-tdate. Please open an issue if you need to use it.) # Contact & Social * **Mailing list**: [bit-dev@python.org](https://mail.python.org/mailman3/lists/bit-dev.python.org/) can be used for **any topic**, question and idea related to _Back In Time_. Despite its name it is not restricted to development topics only. * **Fediverse** on **Mastodon**: [@backintime@fosstodon.org](https://fosstodon.org/@backintime) * **Bugs** & **Feature Requests**: [Issues section](https://github.com/bit-team/backintime/issues) * **Email**: [backintime-project@posteo.de](mailto:backintime-project@posteo.de) # Installation _Back In Time_ is included in [many GNU/Linux distributions](https://repology.org/project/backintime/badges). Use their repositories to install it. If you want to contribute or using the latest development version of _Back In Time_ please see section [Build & Install](CONTRIBUTING.md#build--install) in [`CONTRIBUTING.md`](CONTRIBUTING.md). Also the dependencies are described there. # Known Problems and Workarounds In the latest stable release: - [File permissions handling and therefore possible non-differential backups](#file-permissions-handling-and-therefore-possible-non-differential-backups) - [`qt_probing.py` may hang with high CPU usage when running BiT as `root` via `cron`](#qt_probingpy-may-hang-with-high-cpu-usage-when-running-bit-as-root-via-cron) More problems described in [this FAQ section](FAQ.md#problems-errors--solutions). ## File permissions handling and therefore possible non-differential backups - In version 1.2.0, the handling of file permissions changed. - In versions <= 1.1.24 (until 2017) all file permissions were set to `-rw-r--r--` in the backup target. - In versions >= 1.2.0 (since 2019) `rsync` is executed with `--perms` option which tells `rsync` to preserve the source file permission. Therefore backups can be larger and slower, especially the first backup after upgrading to a version >= 1.2.0. If you don't like the new behavior, you can use _Expert Options_ -> _Paste additional options to rsync_ to add `--no-perms --no-group --no-owner` to it. Note that the exact file permissions can still be found in `fileinfo.bz2` and are also considered when restoring files. ## `qt_probing.py` may hang with high CPU usage when running BiT as `root` via `cron` See the related issue [#1592](https://github.com/bit-team/backintime/issues/1592). The only reliable work-around is to delete (or move into another folder) the file `/usr/share/backintime/common/qt_probing.py`: `mv /usr/share/backintime/common/qt_probing.py /usr/share/backintime/` Renaming does *not* work! # Contributing and other ways to support the project See [CONTRIBUTING](CONTRIBUTING.md) file for an overview about the projects workflow and strategy. # Licenses Please read [`LICENSES.md`](LICENSES.md). --- February 2026 --- Copyright © 2008-2024 Oprea Dan, Bart de Koning, Richard Bailey, Germar Reitze, Taylor Raack
Copyright © 2022 Christian Buhtz, Michael Büker, Jürgen Altfeld backintime-1.6.1/REUSE.toml000066400000000000000000000016241514264426600154220ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or go to # and . # See https://reuse.software/faq/#bulk-license version = 1 [[annotations]] path = [ "AUTHORS", "VERSION", "CHANGES", "TRANSLATIONS", "common/config-example-*", "common/test/config", ] SPDX-License-Identifier = "CC0-1.0" SPDX-FileCopyrightText = "© 2008 Back In Time Team" [[annotations]] path = [ "doc/manpages/backintime-config.5", ] SPDX-License-Identifier = "GPL-2.0-or-later" SPDX-FileCopyrightText = "© 2008 Back In Time Team" backintime-1.6.1/VERSION000066400000000000000000000000061514264426600147030ustar00rootroot000000000000001.6.1 backintime-1.6.1/common/000077500000000000000000000000001514264426600151275ustar00rootroot00000000000000backintime-1.6.1/common/applicationinstance.py000066400000000000000000000211771514264426600215410ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """ This module holds the ApplicationInstance class, used to handle the one application instance mechanism. """ import os import fcntl import logger import tools # TODO This class name is a misnomer (there may be more than # one app instance eg. if a restore is running and another # backup starts). # Rename it to eg. LockFileManager # TODO2 When refactoring have a look at "common/flock.py" still implementing # a contxt manager for that problem. class ApplicationInstance: """ Class used to handle one application instance mechanism. Args: pidFile (str): full path of file used to save pid and procname autoExit (bool): automatically call sys.exit if there is an other instance running flock (bool): use file-locks to make sure only one instance is checking at the same time """ def __init__(self, pidFile, autoExit=True, flock=False): self.pidFile = pidFile self.pid = 0 self.procname = '' self.flock = None if flock: self.flockExclusiv() if autoExit: if self.check(True): self.startApplication() def __del__(self): self.flockUnlock() # TODO Rename to is_single_instance() to make the purpose more obvious def check(self, autoExit=False): """Check if the current application is already running. Args: autoExit (bool): Automatically call ``sys.exit()`` if there is another instance running. Returns: bool: ``True`` if this is the only application instance. """ # check if the pidfile exists if not os.path.isfile(self.pidFile): return True self.pid, self.procname = self.readPidFile() # check if the process (PID) that created the pid file still exists if 0 == self.pid: return True if not tools.processAlive(self.pid): return True # check if the process has the same procname # check cmdline for backwards compatibility if self.procname and \ self.procname != tools.processName(self.pid) and \ self.procname != tools.processCmdline(self.pid): return True if autoExit: # exit the application print("The application is already running !") # exit raise an exception so don't put it in a try/except block exit(0) return False def busy(self): """ Check if one application with this instance is currently running. Returns: bool: ``True`` if an other instance is currently running. """ return not self.check() def startApplication(self): """ Called when the single instance starts to save its pid """ pid = os.getpid() procname = tools.processName(pid) try: with open(self.pidFile, 'wt') as f: f.write('{}\n{}'.format(pid, procname)) except OSError as e: logger.error( 'Failed to write PID file %s: [%s] %s' % (e.filename, e.errno, e.strerror)) # The flock is removed here because it shall only ensure serialized # access to the "pidFile" (lock file): Without setting flock in # __init__ another process could also check for the existences of the # "pidFile" in parallel and also create a new one (overwriting the one # created here). self.flockUnlock() def exitApplication(self): """ Called when the single instance exit (remove pid file) """ try: os.remove(self.pidFile) except: pass def flockExclusiv(self): """ Create an exclusive advisory file lock named .flock to block the creation of a second instance while the first instance is still in the process of starting (but has not yet completely started). The purpose is to make 1. the check if the PID lock file already exists 2. and the subsequent creation of the PID lock file an atomic operation by using a blocking "flock" file lock on a second file to avoid that two or more processes check for an existing PID lock file, find none and create a new one (so that only the last creator wins). Dev notes: ---------- buhtz (2023-09): Not sure but just log an ERROR without doing anything else is IMHO not enough. aryoda (2023-12): It seems the purpose of this additional lock file using an exclusive lock is to block the other process to continue until this exclusive lock is released (= serialize execution). Therefore advisory locks are used via fcntl.flock (see: man 2 fcntl) buhtz (2024-05): Have a look at the new :mod:`flock` module providing an flock context manager. """ flock_file_URI = self.pidFile + '.flock' logger.debug('Trying to put an advisory lock on the flock ' f'file {flock_file_URI}') try: self.flock = open(flock_file_URI, 'w') # This opens an advisory lock which which is considered only # if other processes cooperate by explicitly acquiring locks # (which BiT does IMHO). # TODO Does this lock request really block if another processes # already holds a lock (until the lock is released)? # = Is the execution serialized? # Provisional answer: # Yes, fcntl.flock seems to wait until the lock is removed # from the file. # Tested by starting one process in the console via # python3 applicationinstance.py # and then (while the first process is still running) # the same command in a 2nd terminal. # The ApplicationInstance constructor call needs # to be changed for this by adding "False, True" # to trigger an exclusive lock. fcntl.flock(self.flock, fcntl.LOCK_EX) except OSError as e: logger.error('Failed to write flock file %s: [%s] %s' % (e.filename, e.errno, e.strerror)) def flockUnlock(self): """ Remove the exclusive lock. Second instance can now continue but should find it self to be obsolete. """ if self.flock: logger.debug('Trying to remove the advisory lock from the ' f'flock file {self.flock.name}') fcntl.fcntl(self.flock, fcntl.LOCK_UN) self.flock.close() try: os.remove(self.flock.name) except: # an other instance was faster # race condition while using 'if os.path.exists(...)' pass self.flock = None def readPidFile(self): """ Read the pid and procname from the file Returns: tuple: tuple of (pid(int), procname(str)) """ pid = 0 procname = '' try: with open(self.pidFile, 'rt') as f: data = f.read() data = data.split('\n', 1) if data[0].isdigit(): pid = int(data[0]) if len(data) > 1: procname = data[1].strip('\n') except OSError as e: logger.warning( 'Failed to read PID and process name from %s: [%s] %s' % (e.filename, e.errno, e.strerror)) except ValueError as e: logger.warning( 'Failed to extract PID and process name from %s: %s' % (self.pidFile, str(e))) return (pid, procname) if __name__ == '__main__': import time # create application instance appInstance = ApplicationInstance('/tmp/myapp.pid') # do something here print("Start MyApp") time.sleep(5) # sleep 5 seconds print("End MyApp") # remove pid file appInstance.exitApplication() backintime-1.6.1/common/askpass.py000066400000000000000000000022501514264426600171450ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """A helper tool to pipe passwords for SSH/SSHFS/EncFS.""" import os import sys import password import password_ipc import tools import config if __name__ == '__main__': # return password cfg = config.Config() tools.envLoad(cfg.cronEnvFile()) profile_id = os.getenv('ASKPASS_PROFILE_ID', '1') mode = os.getenv('ASKPASS_MODE', 'local') if mode == 'USER': prompt = os.getenv('ASKPASS_PROMPT', None) pw = password.Password(cfg) print(pw.passwordFromUser(None, prompt=prompt)) sys.exit(0) temp_file = os.getenv('ASKPASS_TEMP') if temp_file is None: # normal mode, get password from module password pw = password.Password(cfg) print(pw.password(None, profile_id, mode)) sys.exit(0) # temp mode fifo = password_ipc.FIFO(temp_file) pw = fifo.read(5) if pw: print(pw) backintime-1.6.1/common/backintime000077500000000000000000000026651514264426600171740ustar00rootroot00000000000000#!/bin/sh # SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2017 Matthias Gerstner # SPDX-FileCopyrightText: © 2024 Jürgen Altfeld # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # Location of this script CUR_PATH="$(dirname $(readlink -m $0))" # Was this script started in the source code folder (normally during development)? if [ -f "${CUR_PATH}/backintime.py" ]; then APP_PATH=$CUR_PATH else # CUR_PATH must be /usr/bin (the default installation path of this script) # or another sibling folder of "share" (in case of an alternative installation # folder like "/var/bin" where BiT must be installed into /var/share/backintime then) APP_PATH=$(readlink -m "${CUR_PATH}/../share/backintime/common") fi # -E ignores env vars like PYTHONPATH and PYTHONHOME that may modify # the behavior of the interpreter # -s Don't add user site directory to sys.path # TODO Should we use "$APP_PATH" (quoted) to prevent globbing and word splitting? /usr/bin/python3 -Es $APP_PATH/backintime.py "$@" backintime-1.6.1/common/backintime-askpass000077500000000000000000000015751514264426600206360ustar00rootroot00000000000000#!/bin/sh # SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2017 Matthias Gerstner # SPDX-FileCopyrightText: © 2024 Jürgen Altfeld # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # fixing gray window error # https://launchpad.net/bugs/1493020 export QT_GRAPHICSSYSTEM="native" CUR_PATH="$(dirname $(readlink -m $0))" if [ -f "${CUR_PATH}/askpass.py" ]; then APP_PATH=$CUR_PATH else APP_PATH=$(readlink -m "${CUR_PATH}/../share/backintime/common") fi /usr/bin/python3 -Es $APP_PATH/askpass.py "$@" backintime-1.6.1/common/backintime.desktop000066400000000000000000000012431514264426600206300ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2009 Back In Time team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or go to # and . [Desktop Entry] Version=1.5 Name=Back In Time Password Cache Exec=/bin/sh -c "backintime pw-cache start 2>&1 >/dev/null" Comment=Cache passwords for non-interactive Back In Time cronjobs Icon=gtk-save Terminal=NO Type=Application backintime-1.6.1/common/backintime.py000066400000000000000000000123301514264426600176060ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import subprocess import pathlib from datetime import datetime import tools # Workaround for situations where startApp() is not invoked. # E.g. when using --diagnostics and other argparse.Action tools.initiate_translation(None) import bitbase import config import logger import cli import cliarguments from diagnostics import collect_minimal_diagnostics def takeSnapshotAsync(cfg, checksum=False): """ Fork a new backintime process with 'backup' command which will take a new snapshot in background. Args: cfg (config.Config): config that should be used """ cmd = [] if cfg.ioniceOnUser(): cmd.extend(('ionice', '-c2', '-n7')) cmd.append('backintime') if '1' != cfg.currentProfile(): cmd.extend(('--profile', str(cfg.currentProfile()))) if cfg._LOCAL_CONFIG_PATH is not cfg._DEFAULT_CONFIG_PATH: cmd.extend(('--config', cfg._LOCAL_CONFIG_PATH)) # if cfg._LOCAL_DATA_FOLDER is not cfg._DEFAULT_LOCAL_DATA_FOLDER: # cmd.extend(('--share-path', cfg.DATA_FOLDER_ROOT)) if logger.DEBUG: cmd.append('--debug') if checksum: cmd.append('--checksum') cmd.append('backup') # child process need to start its own ssh-agent because otherwise # it would be lost without ssh-agent if parent will close env = os.environ.copy() for i in ('SSH_AUTH_SOCK', 'SSH_AGENT_PID'): try: del env[i] except: pass subprocess.Popen(cmd, env=env) def encfs_deprecation_warning(): """Warn about encfs deprecation in syslog. See Issue #1734 for details. This function is a workraound and will be removed if #1734 is closed. """ # Don't warn if EncFS isn't installed if not tools.checkCommand('encfs'): return # Timestamp file xdg_state = os.environ.get('XDG_STATE_HOME', None) if xdg_state: xdg_state = pathlib.Path(xdg_state) else: xdg_state = pathlib.Path.home() / '.local' / 'state' fp = xdg_state / 'backintime.encfs-warning.timestamp' if fp.exists(): # Calculate age of that file delta = datetime.now() - datetime.fromtimestamp(fp.stat().st_mtime) # Don't warn if to young if delta.days < 30: return else: # ensure existence fp.parent.mkdir(parents=True, exist_ok=True) logger.error( 'EncFS encrypted profiles are no longer supported in Back In Time. ' 'Existing profiles can be used. New ones can not be created. EncFS ' 'support will be completely removed in a future release (expected ' f'around 2027). For details read: {bitbase.URL_ENCRYPT_TRANSITION}' ) # refresh timestamp fp.touch() def startApp(bin_name: str) -> config.Config | None: """ Start the requested command or return config. Command (e.g. 'backup') is specified via command line argument. Without command the current config is returned instead. Args: bin_name: The binaries name of current application. Returns: Current configuration instance if command is missing. """ parser_agent = cliarguments.ParserAgent( app_name=bitbase.APP_NAME, bin_name=bin_name) syslog_id_suffix = { bitbase.BINARY_NAME_CLI: 'CLI', bitbase.BINARY_NAME_GUI: 'GUI' }[bin_name] logger.openlog(syslog_id_suffix) args = cliarguments.parse_arguments(args=None, agent=parser_agent) # Name, Version, As Root, OS msg = '' for key, val in collect_minimal_diagnostics().items(): msg = f'{msg}; {key}: {val}' logger.debug(msg[2:]) # Add source path to $PATH environ if running from source if tools.runningFromSource(): tools.addSourceToPathEnviron() # Warn about sudo if (os.getenv('SUDO_USER') # exists only if sudo was used and os.getenv('BIT_SUDO_WARNING_PRINTED', 'false') == 'false'): os.putenv('BIT_SUDO_WARNING_PRINTED', 'true') logger.warning( "It looks like you're using 'sudo' to start " f"{config.Config.APP_NAME}. This will cause some trouble. " f"Please use either 'sudo -i {bin_name}' or 'pkexec {bin_name}'.") encfs_deprecation_warning() # Call commands if 'func' in dir(args): args.func(args) return None # No arguments/commands cli.set_quiet(args) cli.print_header() return cli.get_config_and_select_profile( config_path=args.config, data_path=args.share_path, profile=args.profile, # Dev note (buhtz, 2025): There is not a default value in all cases, # because "--checksum" is exclusive to rsync-related commands. checksum=getattr(args, 'checksum', None), check=False) if __name__ == '__main__': startApp(bin_name=bitbase.BINARY_NAME_CLI) backintime-1.6.1/common/bash-completion/000077500000000000000000000000001514264426600202135ustar00rootroot00000000000000backintime-1.6.1/common/bash-completion/backintime000066400000000000000000000070161514264426600222500ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2015 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # extract profile and config arguments _bit_extr_opts() { local c=0 last="" opts="" while [[ $c -le ${COMP_CWORD} ]]; do case "${last}" in --profile|--config) if [[ ${COMP_WORDS[$c]} != -* ]]; then opts="${opts} ${last} ${COMP_WORDS[$c]}" fi ;; esac last=${COMP_WORDS[$c]} c=$[$c+1] done echo "${opts}" } # return a list of all snapshots _bit_snapshots_list() { backintime$(_bit_extr_opts) --quiet show | awk '{print $2}' } _backintime() { local cur prev actions opts pw_cache_commands local cur_action='' pos_action=0 c=0 COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts="--profile --quiet --config --version --license \ --help --debug --checksum --no-crontab --delete \ --local-backup --no-local-backup --only-new \ --diagnostics --last --path --background" actions="backup show unmount \ pw-cache remove restore check-config \ prune shutdown" pw_cache_commands="start stop restart reload status" # extract the current action while [[ $c -le $[${COMP_CWORD} - 1] ]]; do case ${actions} in *"${COMP_WORDS[$c]}"*) cur_action="${COMP_WORDS[$c]}" pos_action=${c} break ;; esac c=$[${c}+1] done case "${cur_action}" in restore) if [[ ${cur} != -* ]]; then #which positional argument is $cur? case $[${COMP_CWORD}-${pos_action}] in #first arg is a filename 1) _filedir return 0 ;; #second arg is a dirname 2) _filedir -d return 0 ;; #third arg is snapshot-id 3) COMPREPLY=( $(compgen -W "$(_bit_snapshots_list)" -- ${cur}) ) return 0 ;; esac fi ;; remove|remove-and-do-not-ask-again) if [[ ${cur} != -* ]]; then #snapshot-ids COMPREPLY=( $(compgen -W "$(_bit_snapshots_list)" -- ${cur}) ) return 0 else #other args COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 fi ;; esac case "${prev}" in --config|decode|restore) if [[ ${cur} != -* ]]; then _filedir return 0 fi ;; pw-cache) if [[ ${cur} != -* ]]; then COMPREPLY=( $(compgen -W "${pw_cache_commands}" -- ${cur}) ) return 0 fi ;; *) if [[ -z "${cur_action}" ]]; then opts="${opts} ${actions}" fi COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; esac } complete -F _backintime backintime complete -F _backintime backintime-qt backintime-1.6.1/common/bcolors.py000066400000000000000000000014251514264426600171460ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2015-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import sys if sys.stdout.isatty(): HEADER = '\033[95m' # light magenta OKBLUE = '\033[94m' # light blue OKGREEN = '\033[92m' # light green WARNING = '\033[93m' # light yellow FAIL = '\033[91m' # light red CRITICAL = '\033[31m' # dark red ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' else: HEADER = '' OKBLUE = '' OKGREEN = '' WARNING = '' FAIL = '' CRITICAL = '' ENDC = '' BOLD = '' UNDERLINE = '' backintime-1.6.1/common/bitbase.py000066400000000000000000000111611514264426600171120ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Basic constants used in multiple modules. See also bitlicense.py for additional constants and logic.""" import os from enum import Enum from pathlib import Path # |-------------| # | Application | # |-------------| # Used as a label in the GUI. Not sure if this should be translatable. APP_NAME = 'Back In Time' BINARY_NAME_BASE = 'backintime' BINARY_NAME_CLI = f'{BINARY_NAME_BASE}' BINARY_NAME_GUI = f'{BINARY_NAME_BASE}-qt' PACKAGE_NAME_CLI = f'{BINARY_NAME_BASE}-common' PACKAGE_NAME_GUI = f'{BINARY_NAME_BASE}-qt' # |-----------------| # | Several strings | # |-----------------| # Used in about dialog to add language independent translator credits TRANSLATION_CREDITS_MISC = ( 'Launchpad translators ', 'https://www.reddit.com/r/translator', 'Several mailing lists in Debian (@lists.debian.org) & Ubuntu ' '(@lists.ubuntu.com) especially the user related lists', ) # |-------------------------------| # | Online resources & references | # |-------------------------------| # See issue #1734 and #1735 URL_ENCRYPT_TRANSITION = 'https://github.com/bit-team/backintime' \ '/blob/-/doc/ENCRYPT_TRANSITION.md' URL_SOURCE = 'https://github.com/bit-team/backintime' URL_WEBSITE = URL_SOURCE URL_FAQ = f'{URL_WEBSITE}/blob/-/FAQ.md' URL_ISSUES = f'{URL_WEBSITE}/issues' URL_ISSUES_CREATE_NEW = f'{URL_ISSUES}/new' URL_CHANGELOG = f'{URL_WEBSITE}/blob/dev/CHANGES' URL_TRANSLATION = 'https://translate.codeberg.org/engage/backintime' URL_USER_MANUAL = 'https://backintime.readthedocs.io' # |---------------------| # | Directories & files | # |---------------------| FILENAME_CONFIG = 'config' _DIR_DOC_PATH_BASE = Path('/') / 'usr' / 'share' / 'doc' USER_MANUAL_LOCAL_PATH = _DIR_DOC_PATH_BASE / PACKAGE_NAME_CLI \ / 'manual' / 'index.html' USER_MANUAL_LOCAL_AVAILABLE = USER_MANUAL_LOCAL_PATH.exists() CHANGELOG_LOCAL_PATH = _DIR_DOC_PATH_BASE / PACKAGE_NAME_CLI / 'CHANGES' CHANGELOG_LOCAL_AVAILABLE = CHANGELOG_LOCAL_PATH.exists() CHANGELOG_DEBIAN_GZ = _DIR_DOC_PATH_BASE / PACKAGE_NAME_CLI / 'changelog.gz' DIR_CALLBACK_EXAMPLES = _DIR_DOC_PATH_BASE / PACKAGE_NAME_CLI \ / 'user-callback-examples' DEFAULT_CALLBACK = DIR_CALLBACK_EXAMPLES / 'user-callback.default' # Names used for backup directories (or symlinks to them) indicating a specific # state. DIR_NAME_LAST_SNAPSHOT = 'last_snapshot' DIR_NAME_NEWSNAPSHOT = 'new_snapshot' DIR_NAME_SAVETOCONTINUE = 'save_to_continue' DIR_SSH_KEYS = Path.home() / '.ssh' # |-------------------| # | Enums & constants | # |-------------------| # Used in context of CLI and argument parsing RETURN_OK = 0 RETURN_ERR = 1 RETURN_NO_CFG = 2 class TimeUnit(Enum): """Describe time units used in context of scheduling.""" HOUR = 10 # Config.HOUR DAY = 20 # Config.DAY WEEK = 30 # Config.WEEK MONTH = 40 # Config.MONTH YEAR = 80 # Config.YEAR class ScheduleMode(Enum): """Describe schedule mode. 0 = Disabled 1 = at every boot 2 = every 5 minute 4 = every 10 minute 7 = every 30 minute 10 = every hour 12 = every 2 hours 14 = every 4 hours 16 = every 6 hours 18 = every 12 hours 19 = custom defined hours 20 = every day 25 = daily anacron 27 = when drive get connected 30 = every week 40 = every month 80 = every year """ DISABLED = 0 AT_EVERY_BOOT = 1 MINUTES_5 = 2 MINUTES_10 = 4 MINUTES_30 = 7 HOUR = 10 HOUR_1 = 10 HOURS_2 = 12 HOURS_4 = 14 HOURS_6 = 16 HOURS_12 = 18 CUSTOM_HOUR = 19 DAY = 20 REPEATEDLY = 25 UDEV = 27 WEEK = 30 MONTH = 40 YEAR = 80 HOURLY_BACKUPS = ( ScheduleMode.HOUR, ScheduleMode.HOUR_1, ScheduleMode.HOURS_2, ScheduleMode.HOURS_4, ScheduleMode.HOURS_6, ScheduleMode.HOURS_12, ScheduleMode.CUSTOM_HOUR) # |------| # | Misc | # |------| # Indicator if BIT is running in root mode IS_IN_ROOT_MODE = os.geteuid() == 0 # About transition of encryption feature and the removal of EncFS (see #1734). # The warnings and deprecation messages are gradually increased in intensity # and clarity. This constant is the currently desired stage of intensity. The # last shown intensity is stored in the state data file. If they don't fit, the # message is displayed. ENCFS_MSG_STAGE = 3 backintime-1.6.1/common/bitlicense.py000066400000000000000000000042561514264426600176310ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Constants and logic related to license and copyright information. That module is separated from bitbase.py because it contain translatable strings but bitbase is not able to provide it.""" from pathlib import Path import bitbase COPYRIGHT = 'Copyright © 2008-2024 ' \ 'Oprea Dan, Bart de Koning, Richard Bailey, Germar Reitze\n' \ 'Copyright © 2022 ' \ 'Christian Buhtz, Michael Büker, Jürgen Altfeld' URL_GPL_TWO = 'https://spdx.org/licenses/GPL-2.0-or-later.html' def get_gpl_short_text(href: str = None) -> str: """Short description of primary license. The string is used in the AboutDialog and when using --license on shell. Dev note (buhtz, 2025-03): That string is untranslated on purpose. It is legally relevant, and no one should be given the opportunity to change the string—whether intentionally or accidentally. """ gpl = 'GNU General Public License v2.0 or later (GPL-2.0-or-later)' if href: gpl = f'{gpl}' return f'The application is released under {gpl}.' TXT_LICENSES = _( 'All licenses used in this project are located in the {dir_link} ' 'directory. To extract per-file license and copyright information ' 'using SPDX metadata, refer to {readme_link}.') def _determine_licenses_dir() -> str | None: for pkg in (bitbase.PACKAGE_NAME_GUI, bitbase.PACKAGE_NAME_CLI, bitbase.BINARY_NAME_GUI, bitbase.BINARY_NAME_CLI, bitbase.BINARY_NAME_BASE): for path in (Path('/usr/share/doc'), Path('/usr/share/licenses')): fp = path / pkg / 'LICENSES' if fp.is_dir(): return fp # it might be a source repo fp = Path.cwd().parent / 'LICENSES' if fp.is_dir(): return fp return None DIR_LICENSES = _determine_licenses_dir() backintime-1.6.1/common/cli.py000066400000000000000000000225341514264426600162560ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import sys import atexit import tools import daemon import snapshots import bcolors import config import logger import bitbase from typing import Optional from version import __version__ def restore(cfg, snapshot_id=None, what=None, where=None, **kwargs): if what is None: what = input('File to restore: ') what = os.path.abspath(os.path.expanduser(what)) if where is None: where = input('Restore to (empty for original path): ') if where: where = os.path.abspath(os.path.expanduser(where)) snapshotsList = snapshots.listSnapshots(cfg) sid = selectSnapshot( snapshotsList, cfg, snapshot_id, 'SnapshotID to restore') print('') RestoreDialog(cfg, sid, what, where, **kwargs).run() def remove(cfg, snapshot_ids=None, force=None): snapshotsList = snapshots.listSnapshots(cfg) if not snapshot_ids: snapshot_ids = (None,) sids = [ selectSnapshot(snapshotsList, cfg, sid, 'SnapshotID to remove') for sid in snapshot_ids ] if not force: print('Do you really want to remove these backups?') for sid in sids: print(sid.displayName) if not 'yes' == input('(no/yes): '): return s = snapshots.Snapshots(cfg) for sid in sids: s.remove(sid) def checkConfig(cfg, crontab=True): import mount from exceptions import MountException def announceTest(): print() print(frame(test)) def failed(): print(test + ': ' + bcolors.FAIL + 'failed' + bcolors.ENDC) def okay(): print(test + ': ' + bcolors.OKGREEN + 'done' + bcolors.ENDC) def errorHandler(msg): print(bcolors.WARNING + 'WARNING: ' + bcolors.ENDC + msg) cfg.setErrorHandler(errorHandler) mode = cfg.snapshotsMode() if cfg.SNAPSHOT_MODES[mode][0] is not None: # preMountCheck test = 'Run mount tests' announceTest() mnt = mount.Mount(cfg = cfg, tmp_mount = True) try: mnt.preMountCheck(mode = mode, first_run = True) except MountException as ex: failed() print(str(ex)) return False okay() # okay, let's try to mount test = 'Mount' announceTest() try: hash_id = mnt.mount(mode=mode, check=False) except MountException as ex: failed() print(str(ex)) return False okay() test = 'Check/prepare backup path' announceTest() snapshots_mountpoint = cfg.get_snapshots_mountpoint(tmp_mount=True) ret = tools.validate_and_prepare_snapshots_path( path=snapshots_mountpoint, host_user_profile=cfg.hostUserProfile(), mode=mode, copy_links=cfg.copyLinks(), error_handler=cfg.notifyError) if not ret: failed() return False okay() # umount if not cfg.SNAPSHOT_MODES[mode][0] is None: test = 'Unmount' announceTest() try: mnt.umount(hash_id=hash_id) except MountException as ex: failed() print(str(ex)) return False okay() test = 'Check config' announceTest() if not cfg.checkConfig(): failed() return False okay() if crontab: test = 'Install crontab' announceTest() try: cfg.setup_automation() except Exception as exc: failed() print(str(exc)) return False okay() return True def selectSnapshot(snapshotsList, cfg, snapshot_id=None, msg='SnapshotID'): """ check if given snapshot is valid. If not print a list of all snapshots and ask to choose one """ len_snapshots = len(snapshotsList) if not snapshot_id is None: try: sid = snapshots.SID(snapshot_id, cfg) if sid in snapshotsList: return sid else: print('SnapshotID %s not found.' % snapshot_id) except ValueError: try: index = int(snapshot_id) return snapshotsList[index] except (ValueError, IndexError): print('Invalid SnaphotID index: %s' % snapshot_id) snapshot_id = None columns = (terminalSize()[1] - 25) // 26 + 1 rows = len_snapshots // columns if len_snapshots % columns > 0: rows += 1 print('SnapshotID\'s:') for row in range(rows): line = [] for column in range(columns): index = row + column * rows if index > len_snapshots - 1: continue line.append('{i:>4}: {s}'.format(i=index, s=snapshotsList[index])) print(' '.join(line)) print('') while snapshot_id is None: try: index = int(input(msg + ' (0 - %d): ' % (len_snapshots - 1))) snapshot_id = snapshotsList[index] except (ValueError, IndexError): print('Invalid Input') continue return snapshot_id def terminalSize(): """ get terminal size """ for fd in (sys.stdin, sys.stdout, sys.stderr): try: import fcntl import termios import struct return [ int(x) for x in struct.unpack( 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) ] except ImportError: pass return [24, 80] def frame(msg, size=32): ret = ' +' + '-' * size + '+\n' ret += ' |' + msg.center(size) + '|\n' ret += ' +' + '-' * size + '+' return ret class RestoreDialog: def __init__(self, cfg, sid, what, where, **kwargs): self.config = cfg self.sid = sid self.what = what self.where = where self.kwargs = kwargs self.logFile = self.config.restoreLogFile() if os.path.exists(self.logFile): os.remove(self.logFile) def callback(self, line, *_args): if not line: return print(line) with open(self.logFile, mode='a', encoding='utf-8') as log: log.write(line + '\n') def run(self): s = snapshots.Snapshots(self.config) s.restore( self.sid, self.what, self.callback, self.where, **self.kwargs) print('\nLog saved to %s' % self.logFile) class BackupJobDaemon(daemon.Daemon): def __init__(self, func, args): super(BackupJobDaemon, self).__init__() self.func = func self.args = args def run(self): self.func(self.args, False) def set_quiet(args): """ Redirect :py:data:`sys.stdout` to ``/dev/null`` if ``--quiet`` was set on commandline. Return the original :py:data:`sys.stdout` file object which can be used to print absolute necessary information. Args: args (argparse.Namespace): previously parsed arguments Returns: sys.stdout: default sys.stdout """ force_stdout = sys.stdout if args.quiet: # do not replace with subprocess.DEVNULL - will not work sys.stdout = open(os.devnull, 'w') atexit.register(sys.stdout.close) atexit.register(force_stdout.close) return force_stdout def print_header(): """Print application name, version and legal notes.""" print( f'\n{bitbase.APP_NAME}\n' f'Version: {__version__}\n' '\n' 'Back In Time comes with ABSOLUTELY NO WARRANTY.\n' 'This is free software, and you are welcome to redistribute it\n' "under certain conditions; type `backintime --license' for details.\n" '\n' ) def get_config_and_select_profile( config_path: str, data_path: str, profile: str, checksum: Optional[bool] = None, check: bool = True) -> config.Config: """Load config and change to profile selected on commandline. Args: config_path: Path to config file. data_path: Path to "share_path". profile: Name or ID of the profile. checksum: Use checksum option. check: If ``True`` check if config is valid. Returns: Current config with requested profile selected. Raises: SystemExit: 1 if ``profile`` or ``profile_id`` is no valid profile. 2 if ``check`` is ``True`` and config is not configured """ cfg = config.Config( config_path=config_path, data_path=data_path) if profile: if profile.isdigit(): if not cfg.setCurrentProfile(int(profile)): logger.error(f'Profile-ID not found: {profile}') sys.exit(bitbase.RETURN_ERR) else: if not cfg.setCurrentProfileByName(profile): logger.error(f'Profile not found: {profile}') sys.exit(bitbase.RETURN_ERR) if check and not cfg.isConfigured(): logger.error(f'{cfg.APP_NAME} is not configured!') sys.exit(bitbase.RETURN_NO_CFG) if checksum is not None: cfg.forceUseChecksum = checksum return cfg backintime-1.6.1/common/cliarguments.py000066400000000000000000001013041514264426600201750ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Split from backintime.py """Module about CLI argument parsing and parsers. A note about conventions: - Help text starts with lower letter, with the exception of names. - Help text ends not with a period. Example (good): --help show this help Example (don't): --help Show this help. """ import sys import argparse import json import re import tools # Workaround for situations where startApp() is not invoked. # E.g. when using --diagnostics and other argparse.Action tools.initiate_translation(None) import bitbase # noqa: E402 import bitlicense # noqa: E402 import diagnostics # noqa: E402 import logger # noqa: E402 import clicommands # noqa: E402 from argparse import (ArgumentParser, # noqa: E402 Namespace, Action, ) from pathlib import Path # noqa: E402 from version import __version__ # noqa: E402 def _license_info() -> tuple[str, str]: """Collect license info. The projects primary license is extracted from SPDX head of the current file. Additional licenses in use are extracted from the filenames in LICENSES directory. This info is combined and returned as two strings. Returns: Primary or project license and additional licenses. """ # Extract the SPDX license info from current file. # interpreted as primary/project license # REUSE-IgnoreStart prim = re.search( r'SPDX-License-Identifier:\s(:?.*)', Path(__file__).read_text(encoding='utf-8') ) # REUSE-IgnoreEnd try: result = prim.groups()[0] except (AttributeError, IndexError): result = None # all used licenses licenses = None if bitlicense.DIR_LICENSES: licenses = [ f.with_suffix('').name for f in bitlicense.DIR_LICENSES.iterdir()] if result: licenses.remove(result) licenses = ', '.join(licenses) # combine result = (result, licenses) # any errors? if not result[0]: result = ( f'Unable to extract license info from {__file__}', result[1]) logger.error(result[0]) if not result[1]: result = ( result[0], 'Unable to extract licenses from LICENSES ' f'directory "{bitlicense.DIR_LICENSES}".') logger.error(result[1]) return result class ParserAgent: """Create and manage all parsers.""" def __init__(self, app_name: str, bin_name: str ): # Name of the application e.g. "Back In Time" self.app_name = app_name # Name of the binary e.g. "backintime" self.bin_name = bin_name # Mapping the command names to their handler functions self._cmd_func_dict = { 'backup': clicommands.backup, 'check-config': clicommands.check_config, 'pw-cache': clicommands.pw_cache, 'remove': clicommands.remove, 'restore': clicommands.restore, 'shutdown': clicommands.shutdown, 'prune': clicommands.prune, 'show': clicommands.show_backups, 'unmount': clicommands.unmount, # Deprecated commands (#2124) 'decode': clicommands.decode, 'backup-job': clicommands.backup_job, 'smart-remove': clicommands.smart_remove, 'remove-and-do-not-ask-again': clicommands.remove_and_donot_ask_again, # See #2120 'benchmark-cipher': clicommands.benchmark_cipher, # See #2130 for this five commands 'snapshots-path': clicommands.snapshots_path, 'last-snapshot': clicommands.last_snapshot, 'last-snapshot-path': clicommands.last_snapshot_path, 'snapshots-list': clicommands.snapshots_list, 'snapshots-list-path': clicommands.snapshots_list_path, } # Public parsers indexed by their (command) name self.parsers = {} # Helper self._command_subparsers = None # ??? self._aliases = [] # Used as epilog for command parses self._reusable_parsers = {} # Start creating all parsers, etc self._create_reusable_parsers() self._create_main_parser() self._create_command_parsers() def _build_epilog(self): # Create with "Text ASCII Generator" by "patorjk" # https://patorjk.com/software/taag # Font used is "Mini" logo = '\n'.join([ r' _ ___ ___', r' |_) _. _ | | ._ | o ._ _ _ Version:', rf' |_) (_| (_ |< _|_ | | | | | | | (/_ {__version__}' ]) prj_license, add_licenses = _license_info() epi = '\n'.join([ logo, '', f' Project : {bitbase.URL_WEBSITE}', f' User Manual : {bitbase.URL_USER_MANUAL}', ' Copyright : see file LICENSES.md', f' Project License : {prj_license}', f'Additional Licenses : {add_licenses}', ]) return epi def _create_reusable_parsers(self): self._create_common_parser() self._create_profile_parser() self._create_snapshots_only_parser() # deprecated self._create_rsync_only_parser() @property def main_parser(self) -> ArgumentParser: """The main parser""" return self.parsers['main'] def _create_main_parser(self): """Main argument parser""" parser = ArgumentParser( prog=self.bin_name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'] ], description=f'command-line interface (CLI) for {self.app_name}, ' 'to create and manage incremental backups', epilog=self._build_epilog(), # because of ASCII art in epilog formatter_class=argparse.RawTextHelpFormatter, allow_abbrev=False ) self.parsers['main'] = parser parser.add_argument( '-v', '--version', action='version', version='%(prog)s ' + __version__, help="show %(prog)s's version number") parser.add_argument( '--license', action=ActionPrintLicense, nargs=0, help="show %(prog)s's license details") parser.add_argument( '--diagnostics', action=ActionPrintDiagnostics, nargs=0, help='show helpful info (in JSON format) for better support in ' 'case of issues') def _create_common_parser(self) -> ArgumentParser: """Common arguments used independent from commands""" parser = ArgumentParser(add_help=False) parser.add_argument( '--config', metavar='PATH', type=str, action='store', help='read config from %(metavar)s ' '(Default: $XDG_CONFIG_HOME/backintime/config)') parser.add_argument( '--share-path', metavar='PATH', type=str, action='store', # Hide because deprecated (#2125) help=argparse.SUPPRESS # help='Write runtime data (locks, messages, log and ' # 'mountpoints) to %(metavar)s.' ) parser.add_argument( '--quiet', action='store_true', help='be quiet and suppress messages on stdout') parser.add_argument( '--debug', action='store_true', default=False, help='increase verbosity') self._reusable_parsers['common'] = parser def _create_profile_parser(self): """Parser used by commands with profile selection involved.""" parser = ArgumentParser(add_help=False) # Allow only one of "--profile" or "--profile-id" profile_group = parser.add_mutually_exclusive_group() profile_group.add_argument( '--profile', '-p', metavar='NAME|ID', type=str, action='store', help='select profile by name or id' ) # Deprecated (#2125) profile_group.add_argument( '--profile-id', metavar='ID', type=int, action='store', help=argparse.SUPPRESS) self._reusable_parsers['profile'] = parser def _create_snapshots_only_parser(self): """Arguments used only by commands - snapshots-path - snapshots-list-path - last-snapshot-path """ parser = ArgumentParser(add_help=False) parser.add_argument( '--keep-mount', action='store_true', help="Don't unmount on exit.") self._reusable_parsers['snapshots'] = parser def _create_rsync_only_parser(self): """Arguments used only by rsync related commands: - backup - restore """ parser = ArgumentParser(add_help=False) parser.add_argument( '--checksum', action='store_true', help='force to use checksum for checking if ' 'files have been changed') self._reusable_parsers['rsync'] = parser def _create_cmd_backup(self): name = 'backup' nargs = 0 self._aliases.append((name, nargs)) self._aliases.append(('b', nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['rsync'], self._reusable_parsers['common'], ], help='create new backup, if scheduled and not on battery', description='Create a new backup, but only if the profile is ' 'scheduled and if the machine is not running on ' 'battery.' ) parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( '--background', action='store_true', default=False, help='run in background via daemonization', ) self.parsers[name] = parser def _create_cmd_backup_job(self): name = 'backup-job' nargs = 0 self._aliases.append((name, nargs)) desc = 'Take a new snapshot in background only if the profile is ' \ 'scheduled and the machine is not on battery. This is used ' \ 'by cron jobs.' parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['common'], self._reusable_parsers['profile'], self._reusable_parsers['rsync'] ], help='take new backup in background', description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_benchmark_ciphier(self): name = 'benchmark-cipher' nargs = '?' self._aliases.append((name, nargs)) desc = 'Show a benchmark of all ciphers for ssh transfer.' parser = self._command_subparsers.add_parser( name, help=None, # suppress help output description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser parser.add_argument( 'FILE_SIZE', type=int, action='store', default=40, nargs='?', help='File size used for benchmark.') def _create_cmd_check_config(self): name = 'check-config' parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['common'], ], help='check full configuration', description='Check configuration of all profiles and ' 'install crontab entries.' ) parser.add_argument( '--no-crontab', action='store_true', help='Do not install crontab entries.') parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_decode(self): name = 'decode' nargs = '*' self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='decode paths in encrypted profiles', description="Decode paths with 'encfsctl decode'." ) parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( 'PATH', type=str, action='store', nargs='*', help='Decode PATH. If no PATH is specified on command line ' 'a list of filenames will be read from stdin.') self.parsers[name] = parser def _create_cmd_last_snapshot(self): name = 'last-snapshot' nargs = 0 self._aliases.append((name, nargs)) desc = 'Show the ID of the last snapshot.' parser = self._command_subparsers.add_parser( name, help=None, description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_last_snapshot_path(self): name = 'last-snapshot-path' nargs = 0 self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[self._reusable_parsers['snapshots']], ) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_pw_cache(self): name = 'pw-cache' nargs = '*' self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[self._reusable_parsers['common']], help='control Password Cache', description='Control Password Cache for non-interactive cronjobs.') parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( 'ACTION', action='store', choices=['start', 'stop', 'restart', 'reload', 'status'], nargs='?', help='command to send to Password Cache daemon') self.parsers[name] = parser def _create_cmd_remove(self): name = 'remove' nargs = '*' self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='remove a backup', description='Remove a backup.') parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( 'BACKUP_ID', type=str, action='store', nargs='*', help='ID of backup to be removed') parser.add_argument( '--skip-confirmation', action='store_true', default=False, help='skip confirmation question; be careful!' ) self.parsers[name] = parser def _create_cmd_remove_and_donot_ask_again(self): name = 'remove-and-do-not-ask-again' nargs = '*' self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['common'], self._reusable_parsers['profile'] ], help=name, # On purpose, because the command name is to long. # Otherwise print_usage_without_deprecations() won't # work. description="Remove backup and don't ask for confirmation " "before." ) parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( 'BACKUP_ID', type=str, action='store', nargs='*', help='ID of snapshots which should be removed.') self.parsers[name] = parser def _create_cmd_restore(self): name = 'restore' nargs = '*' self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['rsync'], self._reusable_parsers['common'], ], help='restores backup or files or folders from them', description='Restores entire backups or selected files and ' 'folders from them.' ) parser.set_defaults(func=self._cmd_func_dict[name]) backup_group = parser.add_mutually_exclusive_group() parser.add_argument( 'WHAT', type=str, action='store', nargs='?', help='restore file or directory WHAT') parser.add_argument( 'WHERE', type=str, action='store', nargs='?', help='restore to WHERE; empty argument will default to ' 'original destination') parser.add_argument( 'BACKUP_ID', type=str, action='store', nargs='?', help='specific ID or an integer as index (0=last backup; -1=very ' 'first backup)') parser.add_argument( '--delete', action='store_true', help='Restore and delete newer files which are not in the ' 'snapshot. WARNING: deleting files in filesystem root could ' 'break your whole system!!!') backup_group.add_argument( '--local-backup', action='store_true', help='Create backup files before changing local files.') backup_group.add_argument( '--no-local-backup', action='store_true', help='Temporarily disable creation of backup files before ' 'changing local files. This can be switched off permanently ' 'in Settings, too.') parser.add_argument( '--only-new', action='store_true', help='Only restore files which do not exist or are newer than ' 'those in destination. Using "rsync --update" option.') self.parsers[name] = parser def _create_cmd_shutdown(self): name = 'shutdown' parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='shutdown after backup', description='Shut down the computer after the backup is finished.' ) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_smart_remove(self): name = 'smart-remove' desc = 'Remove snapshots based on "Smart Removal" pattern.' parser = self._command_subparsers.add_parser( name, help=desc, description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_prune(self): name = 'prune' parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='prune backups based on configured "Remove & ' 'Retention" rules', description='Remove and keep backups based on "Remove & ' 'Retention" policy.' ) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_snapshots_list(self): name = 'snapshots-list' nargs = 0 self._aliases.append((name, nargs)) desc = 'Show a list of snapshot IDs.' parser = self._command_subparsers.add_parser( name, parents=[self._reusable_parsers['snapshots']], help=None, description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_snapshots_list_path(self): name = 'snapshots-list-path' nargs = 0 self._aliases.append((name, nargs)) desc = "Show the paths to snapshots." parser = self._command_subparsers.add_parser( name, parents=[self._reusable_parsers['snapshots']], help=None, description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_snapshots_path(self): name = 'snapshots-path' nargs = 0 self._aliases.append((name, nargs)) desc = 'Show the path where snapshots are stored.' parser = self._command_subparsers.add_parser( name, parents=[self._reusable_parsers['snapshots']], help=None, # suppress help output description=desc) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_show(self): name = 'show' parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='show information about backups', description="List backup ID's (default) or paths (--path) or " "just the last (--last)", allow_abbrev=False ) parser.set_defaults(func=self._cmd_func_dict[name]) parser.add_argument( '--path', action='store_true', default=False, help='list backup paths instead of their ID') parser.add_argument( '--last', action='store_true', default=False, help='show the last (youngest) backup only') self.parsers[name] = parser def _create_cmd_unmount(self): name = 'unmount' nargs = 0 self._aliases.append((name, nargs)) parser = self._command_subparsers.add_parser( name, parents=[ self._reusable_parsers['profile'], self._reusable_parsers['common'], ], help='unmount the profile', description='Unmount the profile.' ) parser.set_defaults(func=self._cmd_func_dict[name]) self.parsers[name] = parser def _create_cmd_aliase_switches(self): # define aliases for all commands with trailing -- # DEPRECATED and REMOVE it group = self.parsers['main'].add_mutually_exclusive_group() for alias, nargs in self._aliases: arg = f'-{alias}' if len(alias) != 1: arg = f'-{arg}' logger.debug(f'COMANND ALIAS: "{alias}" -> "{arg}"', self) group.add_argument( arg, nargs=nargs, action=PseudoAliasAction, # Don't show that alias in help (-h | --help) output help=argparse.SUPPRESS ) def _create_command_parsers(self): self._command_subparsers = self.parsers['main'].add_subparsers( title='Commands', dest='command') self._create_cmd_backup() self._create_cmd_backup_job() self._create_cmd_show() self._create_cmd_restore() self._create_cmd_remove() self._create_cmd_remove_and_donot_ask_again() self._create_cmd_prune() self._create_cmd_smart_remove() self._create_cmd_unmount() self._create_cmd_shutdown() self._create_cmd_benchmark_ciphier() self._create_cmd_check_config() self._create_cmd_decode() self._create_cmd_pw_cache() self._create_cmd_last_snapshot() self._create_cmd_last_snapshot_path() self._create_cmd_snapshots_list() self._create_cmd_snapshots_list_path() self._create_cmd_snapshots_path() self._create_cmd_aliase_switches() def print_usage_without_deprecations(parser): """Hidde commands form the parsers help output, print it and exit. This is a workaround because argparse can suppress arguments but not commands (subparsers). The help output contain a online list of commands. This line is the one that gets manipulated here. Commands: {backup,backup-job,check-config,...,unmount} A second location where a command appears is the line-by-line help output. Commands: backup Bla bla foo bar """ text = parser.format_help().splitlines() # for idx, t in enumerate(text): # print(f'{idx=} {t=}') deprecated_cmds = [ 'benchmark-cipher', 'snapshots-path', 'last-snapshot', 'last-snapshot-path', 'snapshots-list', 'snapshots-list-path', 'backup-job', 'smart-remove', 'remove-and-do-not-ask-again', 'decode', ] def _remove_cmds_from_cmd_list(line: str): """Remove all deprecated commands from that one line like this: {backup,backup-job,check-config,...,unmount} Usually there are two of this lines in a help-usage-output. """ for cmd in deprecated_cmds: # replace "cmd" between delemiters with "," pattern = r'(?<=[{,])' + re.escape(cmd) + r'(?=[,}])' line = re.sub(pattern, ',', line) # clean up to much "," line = re.sub(r',+', ',', line) line = re.sub(r'{,', '{', line) line = re.sub(r',}', '}', line) return line rex = re.compile(r'.*{.*}.*') line_idx_to_remove = [] for idx, line in enumerate(text[:]): # Remove commands from the one-line-list if rex.match(line): text[idx] = _remove_cmds_from_cmd_list(line) continue # Line-by-line command description? for cmd in deprecated_cmds: pattern = r'\s+' + re.escape(cmd) + r'(?=\s|$)' if re.match(pattern, line): line_idx_to_remove.append(idx) continue # remove lines with deprecated commands for idx in reversed(line_idx_to_remove): del text[idx] print('\n'.join(text)) sys.exit(0) def parse_arguments(args: Namespace, agent: ParserAgent) -> Namespace: """Parse arguments given on commandline. Args: args: Namespace that should be enhanced or ``None``. Returns: New parsed Namespace. """ def join(args, sub_args): """ Add new arguments to existing Namespace. Args: args (argparse.Namespace): main Namespace that should get new arguments sub_args (argparse.Namespace): second Namespace which have new arguments that should be merged into ``args`` """ for key, value in vars(sub_args).items(): # Only add new values if it isn't set already or if there really IS # a value if getattr(args, key, None) is None or value: setattr(args, key, value) # First parse the main parser without subparsers # otherwise positional args in subparsers will be to greedy # but only if -h or --help is not involved because otherwise # help will not work for subcommands main_parser = agent.main_parser sub = [] if '-h' not in sys.argv and '--help' not in sys.argv: for i in main_parser._actions: if isinstance(i, argparse._SubParsersAction): # Remove subparsers main_parser._remove_action(i) sub.append(i) else: # Manipulate the main parsers output only (not the subparsers) if sys.argv[1] in ['-h', '--help']: print_usage_without_deprecations(main_parser) args, unknown_args = main_parser.parse_known_args(args) # Read subparsers again for i in sub: main_parser._add_action(i) # Parse it again for unknown args if unknown_args: sub_args, unknown_args = main_parser.parse_known_args(unknown_args) join(args, sub_args) # Finally parse only the command parser, otherwise we miss some arguments # from command if (unknown_args and 'command' in args and args.command in agent.parsers): cmd_parser = agent.parsers[args.command] sub_args, unknown_args = cmd_parser.parse_known_args(unknown_args) join(args, sub_args) try: logger.DEBUG = args.debug except AttributeError: pass args_dict = vars(args) used_args = { key: args_dict[key] for key in filter(lambda key: args_dict[key] is not None, args_dict) } logger.debug(f'Argument(s) used: {used_args}') # Deprecated (#2125) if args.profile_id: clicommands.show_deprecation_message('--profile-id') args.profile = str(args.profile_id) if args.share_path: clicommands.show_deprecation_message('--share-path') # Report unknown arguments but not if we run aliasParser next because we # will parse again in there. if unknown_args and not ('func' in args and args.func is alias_parser): main_parser.error(f'Unknown argument(s): {unknown_args}') return args class ActionPrintLicense(argparse.Action): """Print license details.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): text_gpl = bitlicense.get_gpl_short_text() text_licenses = bitlicense.TXT_LICENSES.format( dir_link=bitlicense.DIR_LICENSES, readme_link=bitlicense.DIR_LICENSES.parent / 'LICENSES.md') print(f'{text_gpl}\n{text_licenses}') sys.exit(bitbase.RETURN_OK) class ActionPrintDiagnostics(argparse.Action): """See `collect_diagnostics()` for details.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): data = diagnostics.collect_diagnostics() print(json.dumps(data, indent=4)) sys.exit(bitbase.RETURN_OK) def alias_parser(args: Namespace): """Call commands which where given with leading -- for backwards compatibility. Args: args: Previously parsed arguments """ if not args.quiet: logger.info(f"Run command '{args.alias}' instead of argument " f"'{args.replace}' due to backwards compatibility.") msg = ( f'The command alias "{args.replace}" is deprecated and will be ' 'removed from Back In Time in the foreseeable future, without any ' 'replacement.') # ToDo: Switch this later to ERROR logger.warning(msg) argv = [w.replace(args.replace, args.alias) for w in sys.argv[1:]] new_args = parse_arguments( argv, agent=ParserAgent(bitbase.APP_NAME, 'backintime') ) if 'func' in dir(new_args): new_args.func(new_args) class PseudoAliasAction(Action): """Translate '--COMMAND' into 'COMMAND' for backwards compatibility. """ def __call__(self, parser, namespace, values, option_string=None): """ Args: parser (argparse.ArgumentParser): NotImplemented namespace (argparse.Namespace): Namespace that should get modified values: NotImplemented option_string: NotImplemented """ dest = self.dest.replace('_', '-') if self.dest == 'b': replace = '-b' alias = 'backup' else: replace = f'--{dest}' alias = dest setattr(namespace, 'func', alias_parser) setattr(namespace, 'replace', replace) setattr(namespace, 'alias', alias) backintime-1.6.1/common/clicommands.py000066400000000000000000000417411514264426600200010ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Split from backintime.py """Module about CLI commands""" import sys import argparse from datetime import datetime from time import sleep import tools # Workaround for situations where startApp() is not invoked. # E.g. when using --diagnostics and other argparse.Action tools.initiate_translation(None) import logger import snapshots import sshtools import password import encfstools import cli import config import bitbase import mount from exceptions import MountException from applicationinstance import ApplicationInstance from shutdownagent import ShutdownAgent def _deprecation_msg(cmd_flag: str, replacement: str) -> str: if not replacement: replacement = 'A replacement is not planned.' kind = 'flag' if cmd_flag[0] == '-' else 'command' return ( f'The {kind} "{cmd_flag}" is deprecated and will be removed from Back ' f'In Time in the foreseeable future. {replacement} Feel free to ' 'contact the project team if you have any questions or suggestions.') def show_deprecation_message(cmd_flag: str): """Centralize management of deprecation message regarding CLI commands and flags. As an exception the deprecation messages for flag-aliases (e.g. '--backup' for 'backup') are managed in `cliargument.alias_parser()`. """ # 'None' means no replacement planned. replacement = { 'benchmark-cipher': None, 'snapshots-path': None, 'snapshots-list': 'Use "show" instead.', 'snapshots-list-path': 'Use "show --path" instead.', 'last-snapshot': 'Use "show --last" instead.', 'last-snapshot-path': 'Use "show --last --path" instead.', 'backup-job': 'Use "backup --background" instead.', 'smart-remove': 'Use "prune" instead.', 'remove-and-do-not-ask-again': 'Use "remove --skip-confirmation" instead.', '--profile-id': 'Use "--profile" instead.', '--share-path': None, 'decode': None, }[cmd_flag] msg = _deprecation_msg(cmd_flag, replacement) # ToDo: Switch this later to ERROR logger.warning(msg) def _get_config(args: argparse.Namespace) -> config.Config: """A dirty little helper. Feel free to refactor.""" return cli.get_config_and_select_profile( config_path=args.config, data_path=args.share_path, profile=args.profile, checksum=getattr(args, 'checksum', None) ) def backup(args: argparse.Namespace, force: bool = True): """ Command for force taking a new snapshot. Args: args (argparse.Namespace): previously parsed arguments force (bool): take the snapshot even if it wouldn't need to or would be prevented (e.g. running on battery) Raises: SystemExit: 0 if successful, 1 if not """ # Run backup in background? if args.background: # "Force" will be False cli.BackupJobDaemon(_do_backup, args).start() else: _do_backup(args, force) def _do_backup(args: argparse.Namespace, force: bool): """ Command for force taking a new snapshot. Args: args (argparse.Namespace): previously parsed arguments force (bool): take the snapshot even if it wouldn't need to or would be prevented (e.g. running on battery) Raises: SystemExit: 0 if successful, 1 if not """ cli.set_quiet(args) cli.print_header() cfg = _get_config(args) tools.envLoad(cfg.cronEnvFile()) ret = snapshots.Snapshots(cfg).backup(force) sys.exit(int(ret)) def backup_job(args: argparse.Namespace): """ Command for taking a new snapshot in background. Mainly used for cronjobs. This will run the snapshot inside a daemon and detach from it. It will return immediately back to commandline. Args: args: Previously parsed arguments Raises: SystemExit: 0 """ show_deprecation_message('backup-job') args.background = True backup(args) def benchmark_cipher(args: argparse.Namespace): """ Command for transferring a file with scp to remote host with all available ciphers and print its speed and time. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ show_deprecation_message('benchmark-cipher') cli.set_quiet(args) cli.print_header() cfg = _get_config(args) if cfg.snapshotsMode() in ('ssh', 'ssh_encfs'): ssh = sshtools.SSH(cfg) ssh.benchmarkCipher(args.FILE_SIZE) sys.exit(bitbase.RETURN_OK) # else logger.error( f"SSH is not configured for profile '{cfg.profileName()}'!") sys.exit(bitbase.RETURN_ERR) def check_config(args: argparse.Namespace): """Check the config file. In case of no errors application exists with 0, otherwise 1. Args: args: Previously parsed arguments. Raises: SystemExit: 0 if config is okay, 1 if not. """ force_stdout = cli.set_quiet(args) cli.print_header() cfg = _get_config(args) msg = f'\nConfig {cfg._LOCAL_CONFIG_PATH} profile ' \ f"'{cfg.profileName()}'" if cli.checkConfig(cfg, crontab=not args.no_crontab): print(f'{msg} is fine.', file=force_stdout) sys.exit(bitbase.RETURN_OK) # else print(f'{msg} has errors.', file=force_stdout) sys.exit(bitbase.RETURN_ERR) def decode(args: argparse.Namespace): """Decoding paths given paths with 'encfsctl'. Will listen on stdin if no path was given. Args: args: Previously parsed arguments Raises: SystemExit: 0 """ show_deprecation_message('decode') force_stdout = cli.set_quiet(args) cfg = _get_config(args) if cfg.snapshotsMode() not in ('local_encfs', 'ssh_encfs'): logger.error(f"Profile '{cfg.profileName()}' is not encrypted.") sys.exit(bitbase.RETURN_ERR) _mount(cfg) decoder = encfstools.Decode(cfg) if not args.PATH: while True: try: path = input() except EOFError: break if not path: break print(decoder.path(path), file=force_stdout) else: print('\n'.join(decoder.list(args.PATH)), file=force_stdout) decoder.close() _umount(cfg) sys.exit(bitbase.RETURN_OK) def _last_snapshot_base(args: argparse.Namespace, path_info: bool): """Print info about the very last (youngest) snapshot in current profile. Args: args: Previously parsed arguments Raises: SystemExit: 0 """ force_stdout = cli.set_quiet(args) cfg = _get_config(args) _mount(cfg) sid = snapshots.lastSnapshot(cfg) if sid: # Path or ID label = 'SnapshotPath' if path_info else 'SnapshotID' data = sid.path() if path_info else sid msg = f'{data}' if args.quiet else f'{label}: {data}' print(msg, file=force_stdout) else: logger.error(f"There are no snapshots in '{cfg.profileName()}'") if not getattr(args, 'keep_mount', None): _umount(cfg) sys.exit(bitbase.RETURN_OK) def last_snapshot(args: argparse.Namespace): """Print the very last (youngest) snapshot in current profile. Args: args: Previously parsed arguments Raises: SystemExit: 0 """ show_deprecation_message('last-snapshot') _last_snapshot_base(args=args, path_info=False) def last_snapshot_path(args: argparse.Namespace): """Print the path of the very last (youngest) snapshot in current profile. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ show_deprecation_message('last-snapshot-path') _last_snapshot_base(args=args, path_info=True) def pw_cache(args: argparse.Namespace): """Startpassword cache daemon. Args: args: Previously parsed arguments Raises: SystemExit: 0 if daemon is running, 1 if not. """ force_stdout = cli.set_quiet(args) cli.print_header() cfg = _get_config(args) ret = bitbase.RETURN_OK daemon = password.Password_Cache(cfg) if args.ACTION and args.ACTION != 'status': # call action method getattr(daemon, args.ACTION)() elif args.ACTION == 'status': print(f'{cfg.APP_NAME} Password Cache: ', end=' ', file=force_stdout) if daemon.status(): print(f'{cli.bcolors.OKGREEN}running{cli.bcolors.ENDC}', file=force_stdout) ret = bitbase.RETURN_OK else: print(f'{cli.bcolors.FAIL}not running{cli.bcolors.ENDC}', file=force_stdout) ret = bitbase.RETURN_ERR else: daemon.run() sys.exit(ret) def remove(args: argparse.Namespace): """Remove snapshots. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ cli.set_quiet(args) cli.print_header() cfg = _get_config(args) _mount(cfg) cli.remove( cfg=cfg, snapshot_ids=args.BACKUP_ID, force=args.skip_confirmation) _umount(cfg) sys.exit(bitbase.RETURN_OK) def remove_and_donot_ask_again(args): """Removing snapshots without asking (BE CAREFUL!). Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ show_deprecation_message('remove-and-do-not-ask-again') args.skip_confirmation = True remove(args=args) def restore(args: argparse.Namespace): """Restore files from snapshots. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ cli.set_quiet(args) cli.print_header() cfg = _get_config(args) _mount(cfg) if cfg.backupOnRestore() and not args.no_local_backup: isbackup = True else: isbackup = args.local_backup cli.restore(cfg, args.BACKUP_ID, args.WHAT, args.WHERE, delete=args.delete, backup=isbackup, only_new=args.only_new) _umount(cfg) sys.exit(bitbase.RETURN_OK) def shutdown(args: argparse.Namespace): """Shut down the computer after the current snapshot has finished. Args: args: Previously parsed arguments Raises: SystemExit: 0 if successful; 1 if it failed either because there is no active snapshot for this profile or shutdown is not supported. """ cli.set_quiet(args) cli.print_header() cfg = _get_config(args) sd = ShutdownAgent() if not sd.can_shutdown(): logger.warning('Shutdown is not supported.') sys.exit(bitbase.RETURN_ERR) instance = ApplicationInstance(cfg.takeSnapshotInstanceFile(), False) profile = '='.join((cfg.currentProfile(), cfg.profileName())) if not instance.busy(): logger.info('Skip shutdown because there is no active bacukp ' f'for profile {profile}.') sys.exit(bitbase.RETURN_ERR) print(f'Shutdown is waiting for the running backup in profile {profile} ' 'to end.\nPress CTRL+C to interrupt shutdown.\n') sd.activate_shutdown = True try: while instance.busy(): logger.debug('Backup is still active. Wait for shutdown.') sleep(5) except KeyboardInterrupt: print('Shutdown interrupted.') else: logger.info('Shuting down now.') sd.shutdown() sys.exit(bitbase.RETURN_OK) def snapshots_path(args: argparse.Namespace): """Print the full snapshot path of current profile. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ show_deprecation_message('snapshots-path') force_stdout = cli.set_quiet(args) cfg = _get_config(args) if args.keep_mount: _mount(cfg) msg = '{}' if args.quiet else 'SnapshotsPath: {}' print(msg.format(cfg.snapshotsFullPath()), file=force_stdout) sys.exit(bitbase.RETURN_OK) def _snapshots_list_base(args: argparse.Namespace, path_info: bool): """Print infos about a list of all snapshots in current profile. Args: args: Ppreviously parsed arguments Raises: SystemExit: 0 """ force_stdout = cli.set_quiet(args) cfg = _get_config(args) _mount(cfg) if path_info: msg = '{}' if args.quiet else 'SnapshotPath: {}' else: msg = '{}' if args.quiet else 'SnapshotID: {}' # Use snapshots.listSnapshots instead of iterSnapshots because of sorting if path_info: data = [ sid.path() for sid in snapshots.listSnapshots(cfg, reverse=False)] else: data = list(snapshots.listSnapshots(cfg, reverse=False)) for sid_info in data: print(msg.format(sid_info), file=force_stdout) if not data: logger.error(f"There are no snapshots in '{cfg.profileName()}'") if not args.keep_mount: _umount(cfg) sys.exit(bitbase.RETURN_OK) def snapshots_list(args: argparse.Namespace): """Print a list of all snapshots in current profile. Args: args: Ppreviously parsed arguments Raises: SystemExit: 0 """ show_deprecation_message('snapshots-list') _snapshots_list_base(args=args, path_info=False) def snapshots_list_path(args: argparse.Namespace): """Print a list of all snapshots paths in current profile. Args: args: Previously parsed arguments. Raises: SystemExit: 0 """ show_deprecation_message('snapshots-list-path') _snapshots_list_base(args=args, path_info=True) def show_backups(args: argparse.Namespace): """Command 'show'. Args: args: Parsed command-line arguments. Raises: SystemExit: With errors or no backups available `bitbase.RETURN_ERR` (1), otherwise `bitbase.RETURN_OK' (0). """ cfg = _get_config(args) _mount(cfg) # raw data backups = snapshots.get_backup_ids_and_paths( cfg=cfg, descending=True, include_new=False) if args.last: backups = backups[-1:] if args.path: # Path def _element(e): return str(e[1]) else: # ID def _element(e): return e[0] # one line for each ID/Path result = '\n'.join( map(_element, backups) ) print(result) _umount(cfg) if not backups: logger.error(f'No backups in profile "{cfg.profileName()}"') sys.exit(bitbase.RETURN_ERR) sys.exit(bitbase.RETURN_OK) def smart_remove(args: argparse.Namespace): show_deprecation_message('smart-remove') prune(args) def prune(args: argparse.Namespace): """Run Remove & Retention (aka Smart-Removal). Args: args: Previously parsed arguments. Raises: SystemExit: 0 if okay. 2 if Remove & Retention is not configured. """ cli.set_quiet(args) cli.print_header() cfg = _get_config(args) sn = snapshots.Snapshots(cfg) enabled, \ keep_all, \ keep_one_per_day, \ keep_one_per_week, \ keep_one_per_month = cfg.smartRemove() if enabled: _mount(cfg) del_snapshots = sn.smartRemoveList(datetime.today(), keep_all, keep_one_per_day, keep_one_per_week, keep_one_per_month) logger.info(f'{len(del_snapshots)} backups are marked for removal.') sn.smartRemove(del_snapshots, log=logger.info) _umount(cfg) sys.exit(bitbase.RETURN_OK) # else logger.error('Remove & Retention is not configured.') sys.exit(bitbase.RETURN_NO_CFG) def unmount(args): """Unmount all filesystems. Args: args: Previously parsed arguments Raises: SystemExit: 0 """ cli.set_quiet(args) cfg = _get_config(args) _mount(cfg) _umount(cfg) sys.exit(bitbase.RETURN_OK) def _mount(cfg: config.Config): """Mount external filesystems of current selected profile. Args: cfg: Config to identify the current profile. """ try: hash_id = mount.Mount(cfg=cfg).mount() except MountException as ex: logger.error(str(ex)) sys.exit(bitbase.RETURN_ERR) else: cfg.setCurrentHashId(hash_id) def _umount(cfg: config.Config): """Unmount external filesystems of current selected profile. Args: cfg: Config to identify the current profile. """ try: mount.Mount(cfg=cfg).umount(cfg.current_hash_id) except MountException as ex: logger.error(str(ex)) backintime-1.6.1/common/config-example-local000066400000000000000000000046371514264426600210520ustar00rootroot00000000000000profile1.snapshots.automatic_backup_day=1 profile1.snapshots.automatic_backup_mode=0 profile1.snapshots.automatic_backup_time=0 profile1.snapshots.automatic_backup_weekday=7 profile1.snapshots.backup_on_restore.enabled=true profile1.snapshots.bwlimit.enabled=false profile1.snapshots.bwlimit.value=3000 profile1.snapshots.continue_on_errors=true profile1.snapshots.copy_links=false profile1.snapshots.copy_unsafe_links=false profile1.snapshots.cron.ionice=true profile1.snapshots.cron.nice=true profile1.snapshots.custom_backup_time=8,12,18,23 profile1.snapshots.dont_remove_named_snapshots=true profile1.snapshots.exclude.1.value=.gvfs profile1.snapshots.exclude.10.value=/proc/* profile1.snapshots.exclude.11.value=/sys/* profile1.snapshots.exclude.12.value=/dev/* profile1.snapshots.exclude.13.value=/run/* profile1.snapshots.exclude.2.value=.cache* profile1.snapshots.exclude.3.value=[Cc]ache* profile1.snapshots.exclude.4.value=.thumbnails* profile1.snapshots.exclude.5.value=[Tt]rash* profile1.snapshots.exclude.6.value=*.backup* profile1.snapshots.exclude.7.value=*~ profile1.snapshots.exclude.8.value=/home/USER/Ubuntu One profile1.snapshots.exclude.9.value=.dropbox* profile1.snapshots.exclude.size=13 profile1.snapshots.include.1.type=0 profile1.snapshots.include.1.value=/home/USER profile1.snapshots.include.size=1 profile1.snapshots.local_encfs.path= profile1.snapshots.log_level=3 profile1.snapshots.min_free_space.enabled=true profile1.snapshots.min_free_space.unit=20 profile1.snapshots.min_free_space.value=1 profile1.snapshots.mode=local profile1.snapshots.no_on_battery=false profile1.snapshots.notify.enabled=true profile1.snapshots.path=/mnt/backup profile1.snapshots.path.auto=true profile1.snapshots.path.host=HOST profile1.snapshots.path.profile=1 profile1.snapshots.path.user=USER profile1.snapshots.preserve_acl=false profile1.snapshots.preserve_xattr=false profile1.snapshots.remove_old_snapshots.enabled=true profile1.snapshots.remove_old_snapshots.unit=80 profile1.snapshots.remove_old_snapshots.value=10 profile1.snapshots.smart_remove=false profile1.snapshots.smart_remove.keep_all=2 profile1.snapshots.smart_remove.keep_one_per_day=7 profile1.snapshots.smart_remove.keep_one_per_month=24 profile1.snapshots.smart_remove.keep_one_per_week=4 profile1.snapshots.use_checksum=false profile1.snapshots.user_backup.ionice=false profile1.snapshots.warn_free_space.unit=10 profile1.snapshots.warn_free_space.value=10240 profiles.version=1 backintime-1.6.1/common/config-example-ssh000066400000000000000000000053261514264426600205510ustar00rootroot00000000000000profile1.snapshots.automatic_backup_day=1 profile1.snapshots.automatic_backup_mode=0 profile1.snapshots.automatic_backup_time=0 profile1.snapshots.automatic_backup_weekday=7 profile1.snapshots.backup_on_restore.enabled=true profile1.snapshots.bwlimit.enabled=false profile1.snapshots.bwlimit.value=3000 profile1.snapshots.continue_on_errors=true profile1.snapshots.copy_links=false profile1.snapshots.copy_unsafe_links=false profile1.snapshots.cron.ionice=true profile1.snapshots.cron.nice=true profile1.snapshots.custom_backup_time=8,12,18,23 profile1.snapshots.dont_remove_named_snapshots=true profile1.snapshots.exclude.1.value=.gvfs profile1.snapshots.exclude.10.value=/proc/* profile1.snapshots.exclude.11.value=/sys/* profile1.snapshots.exclude.12.value=/dev/* profile1.snapshots.exclude.13.value=/run/* profile1.snapshots.exclude.2.value=.cache* profile1.snapshots.exclude.3.value=[Cc]ache* profile1.snapshots.exclude.4.value=.thumbnails* profile1.snapshots.exclude.5.value=[Tt]rash* profile1.snapshots.exclude.6.value=*.backup* profile1.snapshots.exclude.7.value=*~ profile1.snapshots.exclude.8.value=/home/USER/Ubuntu One profile1.snapshots.exclude.9.value=.dropbox* profile1.snapshots.exclude.size=13 profile1.snapshots.include.1.type=0 profile1.snapshots.include.1.value=/home/USER profile1.snapshots.include.size=1 profile1.snapshots.local_encfs.path= profile1.snapshots.log_level=3 profile1.snapshots.min_free_space.enabled=true profile1.snapshots.min_free_space.unit=20 profile1.snapshots.min_free_space.value=1 profile1.snapshots.mode=ssh profile1.snapshots.no_on_battery=false profile1.snapshots.notify.enabled=true profile1.snapshots.path= profile1.snapshots.path.auto=true profile1.snapshots.path.host=HOST profile1.snapshots.path.profile=1 profile1.snapshots.path.user=USER profile1.snapshots.preserve_acl=false profile1.snapshots.preserve_xattr=false profile1.snapshots.remove_old_snapshots.enabled=true profile1.snapshots.remove_old_snapshots.unit=80 profile1.snapshots.remove_old_snapshots.value=10 profile1.snapshots.smart_remove=false profile1.snapshots.smart_remove.keep_all=2 profile1.snapshots.smart_remove.keep_one_per_day=7 profile1.snapshots.smart_remove.keep_one_per_month=24 profile1.snapshots.smart_remove.keep_one_per_week=4 profile1.snapshots.ssh.cipher=default profile1.snapshots.ssh.host=REMOTE_HOST profile1.snapshots.ssh.password.save=false profile1.snapshots.ssh.password.use_cache=true profile1.snapshots.ssh.path= profile1.snapshots.ssh.port=22 profile1.snapshots.ssh.private_key_file=/home/USER/.ssh/id_dsa profile1.snapshots.ssh.user=USER profile1.snapshots.use_checksum=false profile1.snapshots.user_backup.ionice=false profile1.snapshots.warn_free_space.unit=10 profile1.snapshots.warn_free_space.value=10240 profiles.version=1 backintime-1.6.1/common/config.py000066400000000000000000002163151514264426600167560ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Configuration handling and logic. This module and its `Config` class contain the application logic handling the configuration of Back In Time. The handling of the configuration file itself is separated in the module :py:mod:`configfile`. Development notes: Some of the methods have code comments starting with `#? ` instead of `# `. These special comments are used to generate the manpage `backintime-config`. The script `create-manpage-backintime-config.py` parses this module for that. """ import os import sys import datetime import socket import random import getpass import shlex # Workaround: Mostly relevant on TravisCI but not exclusively. # While unittesting and without regular invocation of BIT the GNU gettext # class-based API isn't setup yet. # The bigger problem with config.py is that it do use translatable strings. # Strings like this do not belong into a config file or its context. try: _('Warning') except NameError: _ = lambda val: val import bitbase import tools import configfile import encode import logger import sshtools import encfstools import gocryptfstools import password import pluginmanager import schedule from storagesize import StorageSize, SizeUnit from exceptions import PermissionDeniedByPolicy class Config(configfile.ConfigFileWithProfiles): APP_NAME = bitbase.APP_NAME CONFIG_VERSION = 6 """Latest or highest possible version of Back in Time's config file.""" NONE = bitbase.ScheduleMode.DISABLED AT_EVERY_BOOT = bitbase.ScheduleMode.AT_EVERY_BOOT _5_MIN = bitbase.ScheduleMode.MINUTES_5 _10_MIN = bitbase.ScheduleMode.MINUTES_10 _30_MIN = bitbase.ScheduleMode.MINUTES_30 HOUR = bitbase.ScheduleMode.HOUR _1_HOUR = bitbase.ScheduleMode.HOUR_1 _2_HOURS = bitbase.ScheduleMode.HOURS_2 _4_HOURS = bitbase.ScheduleMode.HOURS_4 _6_HOURS = bitbase.ScheduleMode.HOURS_6 _12_HOURS = bitbase.ScheduleMode.HOURS_12 CUSTOM_HOUR = bitbase.ScheduleMode.CUSTOM_HOUR DAY = bitbase.ScheduleMode.DAY REPEATEDLY = bitbase.ScheduleMode.REPEATEDLY UDEV = bitbase.ScheduleMode.UDEV WEEK = bitbase.ScheduleMode.WEEK MONTH = bitbase.ScheduleMode.MONTH YEAR = bitbase.ScheduleMode.YEAR HOURLY_BACKUPS = bitbase.HOURLY_BACKUPS DEFAULT_RUN_NICE_FROM_CRON = True DEFAULT_RUN_NICE_ON_REMOTE = False DEFAULT_RUN_IONICE_FROM_CRON = True DEFAULT_RUN_IONICE_FROM_USER = False DEFAULT_RUN_IONICE_ON_REMOTE = False DEFAULT_RUN_NOCACHE_ON_LOCAL = False DEFAULT_RUN_NOCACHE_ON_REMOTE = False DEFAULT_SSH_PREFIX = 'PATH=/opt/bin:/opt/sbin:\\$PATH' DEFAULT_REDIRECT_STDOUT_IN_CRON = True DEFAULT_REDIRECT_STDERR_IN_CRON = False DEFAULT_OFFSET = 0 ENCODE = encode.Bounce() PLUGIN_MANAGER = pluginmanager.PluginManager() def __init__(self, config_path=None, data_path=None): """Back In Time configuration (and much more then this). Args: config_path (str): Full path to the config file (default: `~/.config/backintime/config`). data_path (str): It is $XDG_DATA_HOME (default: `~/.local/share`). """ # Note: The main profiles name here is translated using the systems # current locale because the language code in the config file wasn't # read yet. configfile.ConfigFileWithProfiles.__init__(self, _('Main profile')) self._unsaved_profiles = [] self._GLOBAL_CONFIG_PATH = '/etc/backintime/config' HOME_FOLDER = os.path.expanduser('~') DATA_FOLDER = '.local/share' CONFIG_FOLDER = '.config' BIT_FOLDER = 'backintime' self._DEFAULT_LOCAL_DATA_FOLDER = os.path.join(HOME_FOLDER, DATA_FOLDER, BIT_FOLDER) self._LOCAL_CONFIG_FOLDER = os.path.join(HOME_FOLDER, CONFIG_FOLDER, BIT_FOLDER) self._MOUNT_ROOT = os.path.join(DATA_FOLDER, BIT_FOLDER, 'mnt') if data_path: self.DATA_FOLDER_ROOT = data_path self._LOCAL_DATA_FOLDER = os.path.join(data_path, DATA_FOLDER, BIT_FOLDER) self._LOCAL_MOUNT_ROOT = os.path.join(data_path, self._MOUNT_ROOT) else: self.DATA_FOLDER_ROOT = HOME_FOLDER self._LOCAL_DATA_FOLDER = self._DEFAULT_LOCAL_DATA_FOLDER self._LOCAL_MOUNT_ROOT = os.path.join(HOME_FOLDER, self._MOUNT_ROOT) tools.makeDirs(self._LOCAL_CONFIG_FOLDER) tools.makeDirs(self._LOCAL_DATA_FOLDER) tools.makeDirs(self._LOCAL_MOUNT_ROOT) self._DEFAULT_CONFIG_PATH = os.path.join(self._LOCAL_CONFIG_FOLDER, 'config') if config_path is None: self._LOCAL_CONFIG_PATH = self._DEFAULT_CONFIG_PATH else: self._LOCAL_CONFIG_PATH = os.path.abspath(config_path) self._LOCAL_CONFIG_FOLDER = os.path.dirname(self._LOCAL_CONFIG_PATH) # Load global config file self.load(self._GLOBAL_CONFIG_PATH) # Append local config file self.append(self._LOCAL_CONFIG_PATH) # Get the version of the config file # or assume the highest config version if it isn't set. currentConfigVersion \ = self.intValue('config.version', self.CONFIG_VERSION) if currentConfigVersion < self.CONFIG_VERSION: if currentConfigVersion < 5: logger.error( 'The config file version is 4 or lower. This config was ' 'made with a version of Back In Time that is out dated. ' 'Because of that upgrading config to the current version ' 'is not possible. The latest Back In Time version ' 'supporting upgrade the config file was v1.5.2.', self) sys.exit(2) if currentConfigVersion < 6: logger.info('Update to config version 6', self) # remap some keys for profile in self.profiles(): # make a 'schedule' domain for everything relating schedules self.remapProfileKey('snapshots.automatic_backup_anacron_period', 'schedule.repeatedly.period', profile) self.remapProfileKey('snapshots.automatic_backup_anacron_unit', 'schedule.repeatedly.unit', profile) self.remapProfileKey('snapshots.automatic_backup_day', 'schedule.day', profile) self.remapProfileKey('snapshots.automatic_backup_mode', 'schedule.mode', profile) self.remapProfileKey('snapshots.automatic_backup_time', 'schedule.time', profile) self.remapProfileKey('snapshots.automatic_backup_weekday', 'schedule.weekday', profile) self.remapProfileKey('snapshots.custom_backup_time', 'schedule.custom_time', profile) # we don't have 'full rsync mode' anymore self.remapProfileKey('snapshots.full_rsync.take_snapshot_regardless_of_changes', 'snapshots.take_snapshot_regardless_of_changes', profile) # remap 'qt4' keys self.remapKeyRegex(r'qt4', 'qt') # remove old gnome and kde keys self.removeKeysStartsWith('gnome') self.removeKeysStartsWith('kde') self.save() self.current_hash_id = 'local' self.pw = None self.forceUseChecksum = False self.setupUdev = tools.SetupUdev() language_used = tools.initiate_translation(self.language()) # Development note (2023-08 by buhtz): # Not the best location for a variable like this. self.language_used = language_used """ISO-639 language code of the used language. See `tools._determine_current_used_language_code()` for details.""" # Workaround self.default_profile_name = _('Main profile') # ToDo Those hidden labels exist to speed up their translation. # See: https://github.com/bit-team/backintime/issues/ # 1735#issuecomment-2197646518 _HIDDEN_NEW_MODE_LABELS = ( _('Local (EncFS encrypted)'), _('SSH (EncFS encrypted)') ) self.SNAPSHOT_MODES = { # mode: ( # , # 'ComboBox Text', # need_pw|lbl_pw_1, # need_2_pw|lbl_pw_2 # ), 'local': ( None, _('Local'), False, False), 'local_gocryptfs': ( gocryptfstools.GocryptfsMount, _('Local encrypted') + ' (via gocryptfs)', _('Encryption'), False ), 'ssh': ( sshtools.SSH, _('SSH'), _('SSH private key'), False), 'local_encfs': ( encfstools.EncFS_mount, 'DEPRECATED - Local encrypted (via EncFS)', _('Encryption'), False ), 'ssh_encfs': ( encfstools.EncFS_SSH, 'DEPRECATED - SSH encrypted (via EncFS)', _('SSH private key'), _('Encryption') ), } # Deprecated: #2176 self.SSH_CIPHERS = { 'default': 'Default', 'aes128-ctr': 'AES128-CTR', 'aes192-ctr': 'AES192-CTR', 'aes256-ctr': 'AES256-CTR', 'arcfour256': 'ARCFOUR256', 'arcfour128': 'ARCFOUR128', 'aes128-cbc': 'AES128-CBC', '3des-cbc': '3DES-CBC', 'blowfish-cbc': 'Blowfish-CBC', 'cast128-cbc': 'Cast128-CBC', 'aes192-cbc': 'AES192-CBC', 'aes256-cbc': 'AES256-CBC', 'arcfour': 'ARCFOUR' } def save(self): self._unsaved_profiles = [] self.setIntValue('config.version', self.CONFIG_VERSION) return super().save(self._LOCAL_CONFIG_PATH) def is_profile_unsaved(self, profile_id: str) -> bool: return profile_id in self._unsaved_profiles def is_current_profile_unsaved(self) -> bool: return self.is_profile_unsaved(self.currentProfile()) def checkConfig(self): profiles = self.profiles() for profile_id in profiles: profile_name = self.profileName(profile_id) snapshots_path = self.snapshotsPath(profile_id) logger.debug(f'Check profile {profile_name}', self) # check snapshots path if not snapshots_path: self.notifyError( '{}\n{}'.format( _('Profile: "{name}"').format(name=profile_name), _('Backup directory is not valid.') ) ) return False # check include include_list = self.include(profile_id) if not include_list: self.notifyError( '{}\n{}'.format( _('Profile: "{name}"').format(name=profile_name), _('At least one directory must be selected ' 'for backup.') ) ) return False snapshots_path2 = snapshots_path + '/' for item in include_list: if item[1] != 0: continue path = item[0] if path == snapshots_path: self.notifyError( '{}\n{}\n{}'.format( _('Profile: "{name}"').format(name=profile_name), _('Directory: {path}').format(path=path), _('This directory cannot be included in the ' 'backup as it is part of the backup ' 'destination itself.') ) ) return False if len(path) >= len(snapshots_path2): if path[: len(snapshots_path2)] == snapshots_path2: self.notifyError( '{}\n{}\n{}'.format( _('Profile: "{name}"').format( name=profile_name), _('Directory: {path}').format(path=path), _('This directory cannot be included in the ' 'backup as it is part of the backup ' 'destination itself.') ) ) return False # check warn free space if (self.warnFreeSpaceEnabled(profile_id) and self.minFreeSpaceEnabled(profile_id)): warn = self.warnFreeSpace(profile_id) _enabled, min_free = self.minFreeSpaceAsStorageSize(profile_id) if warn < min_free: self.notifyError( '{}\n{}\n{}'.format( _('Profile: "{name}"').format(name=profile_name), _('The value for "Remove oldest backup if the ' 'free space is less than" ({val_one}) must be ' 'less than or equal the threshold for "Warn if ' 'free disk space falls below" ({val_two}).' ).format(val_one=min_free, val_two=warn), _('Please adjust the settings so that the backup ' 'removal limit is not higher than the ' 'warning limit.') )) return False return True def host(self): return socket.gethostname() def get_snapshots_mountpoint(self, profile_id=None, mode=None, tmp_mount=False): """Return the profiles snapshot path in form of a mount point.""" if profile_id is None: profile_id = self.currentProfile() if mode is None: mode = self.snapshotsMode(profile_id) if mode == 'local': return self.get_snapshots_path(profile_id) # else: ssh/local_encfs/ssh_encfs/local_gocryptfs symlink = f'{profile_id}_{os.getpid()}' if tmp_mount: symlink = f'tmp_{symlink}' return os.path.join(self._LOCAL_MOUNT_ROOT, symlink) def snapshotsPath(self, profile_id=None, mode=None, tmp_mount=False): """Return the snapshot path (backup destination) as a mount point. That method is a surrogate for `self.get_snapshots_mountpoint()`. """ return self.get_snapshots_mountpoint( profile_id=profile_id, mode=mode, tmp_mount=tmp_mount) def snapshotsFullPath(self, profile_id = None): """ Returns the full path for the snapshots: .../backintime/machine/user/profile_id/ """ host, user, profile = self.hostUserProfile(profile_id) return os.path.join(self.snapshotsPath(profile_id), 'backintime', host, user, profile) def get_snapshots_path(self, profile_id): """Return the value of the snapshot path (backup destination) field.""" return self.profileStrValue('snapshots.path', '', profile_id) def set_snapshots_path(self, value, profile_id=None): """Sets the snapshot path to value.""" if profile_id is None: profile_id = self.currentProfile() self.setProfileStrValue('snapshots.path', value, profile_id) # def is_mode_encrypted(self, profile_id=None): # mode = self.snapshotsMode(profile_id) # return mode in ('local_encfs', 'ssh_encfs') def snapshotsMode(self, profile_id=None): #? Use mode (or backend) for this snapshot. Look at 'man backintime' #? section 'Modes'.;local|local_encfs|ssh|ssh_encfs|local_gocryptfs return self.profileStrValue('snapshots.mode', 'local', profile_id) def setSnapshotsMode(self, value, profile_id = None): self.setProfileStrValue('snapshots.mode', value, profile_id) def setCurrentHashId(self, hash_id): self.current_hash_id = hash_id def hashCollision(self): #?Internal value used to prevent hash collisions on mountpoints. Do not change this. return self.intValue('global.hash_collision', 0) def incrementHashCollision(self): value = self.hashCollision() + 1 self.setIntValue('global.hash_collision', value) def systray(self) -> str: #?Color of systray icon.;auto,dark,light return self.strValue('global.systray', 'auto') def set_systray(self, value: str) -> None: self.setStrValue('global.systray', value) def language(self) -> str: #?Language code (ISO 639) used to translate the user interface. #?If empty the operating systems current local is used. If 'en' the #?translation is not active and the original English source strings #?are used. It is the same if the value is unknown. return self.strValue('global.language', '') def setLanguage(self, language: str): self.setStrValue('global.language', language if language else '') # SSH def sshSnapshotsPath(self, profile_id = None): #?Snapshot path on remote host. If the path is relative (no leading '/') #?it will start from remote Users homedir. An empty path will be replaced #?with './'.;absolute or relative path return self.profileStrValue('snapshots.ssh.path', '', profile_id) def sshSnapshotsFullPath(self, profile_id = None): """ Returns the full path for the snapshots: .../backintime/machine/user/profile_id/ """ path = self.sshSnapshotsPath(profile_id) if not path: path = './' host, user, profile = self.hostUserProfile(profile_id) return os.path.join(path, 'backintime', host, user, profile) def setSshSnapshotsPath(self, value, profile_id = None): self.setProfileStrValue('snapshots.ssh.path', value, profile_id) return True def sshHost(self, profile_id = None): #?Remote host used for mode 'ssh' and 'ssh_encfs'.;IP or domain address return self.profileStrValue('snapshots.ssh.host', '', profile_id) def setSshHost(self, value, profile_id = None): self.setProfileStrValue('snapshots.ssh.host', value, profile_id) def sshPort(self, profile_id = None): #?SSH Port on remote host.;0-65535 return self.profileIntValue('snapshots.ssh.port', '22', profile_id) def setSshPort(self, value, profile_id = None): self.setProfileIntValue('snapshots.ssh.port', value, profile_id) def sshCipher(self, profile_id = None): #?Cipher that is used for encrypting the SSH tunnel. Depending on the #?environment (network bandwidth, cpu and hdd performance) a different #?cipher might be faster.;default | aes192-cbc | aes256-cbc | aes128-ctr | #? aes192-ctr | aes256-ctr | arcfour | arcfour256 | arcfour128 | aes128-cbc | #? 3des-cbc | blowfish-cbc | cast128-cbc return self.profileStrValue('snapshots.ssh.cipher', 'default', profile_id) def setSshCipher(self, value, profile_id = None): self.setProfileStrValue('snapshots.ssh.cipher', value, profile_id) def sshUser(self, profile_id = None): #?Remote SSH user;;local users name return self.profileStrValue('snapshots.ssh.user', getpass.getuser(), profile_id) def setSshUser(self, value, profile_id = None): self.setProfileStrValue('snapshots.ssh.user', value, profile_id) def sshHostUserPortPathCipher(self, profile_id = None): host = self.sshHost(profile_id) port = self.sshPort(profile_id) user = self.sshUser(profile_id) path = self.sshSnapshotsPath(profile_id) cipher = self.sshCipher(profile_id) if not path: path = './' return (host, port, user, path, cipher) def sshPrivateKeyFile(self, profile_id=None) -> None | bool | str: """The field can have three states: 1. Field does not exists: Fresh profile. Provide a default value. 2. Field exist but is empty: Using keys is disabled. 3. Field has a path: """ val = self.profileStrValue('snapshots.ssh.private_key_file', None, profile_id) # Using keys is disabled if val == '': return False return val def sshPrivateKeyFile_enabled(self, profile_id=None): return self.sshPrivateKeyFile(profile_id) is not False def setSshPrivateKeyFile(self, value, profile_id=None): self.setProfileStrValue('snapshots.ssh.private_key_file', value, profile_id) def sshProxyHost(self, profile_id=None): #?Proxy host used to connect to remote host.;;IP or domain address return self.profileStrValue('snapshots.ssh.proxy_host', '', profile_id) def setSshProxyHost(self, value, profile_id=None): self.setProfileStrValue('snapshots.ssh.proxy_host', value, profile_id) def sshProxyPort(self, profile_id=None): #?Proxy host port used to connect to remote host.;0-65535 return self.profileIntValue('snapshots.ssh.proxy_host_port', '22', profile_id) def setSshProxyPort(self, value, profile_id = None): self.setProfileIntValue('snapshots.ssh.proxy_host_port', value, profile_id) def sshProxyUser(self, profile_id=None): #?Remote SSH user;;the local users name return self.profileStrValue('snapshots.ssh.proxy_user', getpass.getuser(), profile_id) def setSshProxyUser(self, value, profile_id=None): self.setProfileStrValue('snapshots.ssh.proxy_user', value, profile_id) def sshMaxArgLength(self, profile_id = None): #?Maximum command length of commands run on remote host. This can be tested #?for all ssh profiles in the configuration #?with 'python3 /usr/share/backintime/common/ssh_max_arg.py LENGTH'.\n #?0 = unlimited;0, >700 value = self.profileIntValue('snapshots.ssh.max_arg_length', 0, profile_id) if value and value < 700: raise ValueError('SSH max arg length %s is too low to run commands' % value) return value def setSshMaxArgLength(self, value, profile_id = None): self.setProfileIntValue('snapshots.ssh.max_arg_length', value, profile_id) def sshCheckCommands(self, profile_id = None): #?Check if all commands (used during takeSnapshot) work like expected #?on the remote host. return self.profileBoolValue('snapshots.ssh.check_commands', True, profile_id) def setSshCheckCommands(self, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.check_commands', value, profile_id) def sshCheckPingHost(self, profile_id = None): #?Check if the remote host is available before trying to mount. return self.profileBoolValue('snapshots.ssh.check_ping', True, profile_id) def setSshCheckPingHost(self, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.check_ping', value, profile_id) def sshDefaultArgs(self, profile_id = None): """ Default arguments used for ``ssh`` and ``sshfs`` commands. Returns: list: arguments for ssh """ # keep connection alive args = ['-o', 'ServerAliveInterval=240'] # disable ssh banner args += ['-o', 'LogLevel=Error'] # specifying key file here allows to override for potentially # conflicting .ssh/config key entry if self.sshPrivateKeyFile_enabled(profile_id): key_file = self.sshPrivateKeyFile(profile_id) if key_file: args += ['-o', f'IdentityFile={key_file}'] return args def sshCommand(self, cmd=None, custom_args=None, port=True, cipher=True, user_host=True, ionice=True, nice=True, quote=False, prefix=True, profile_id=None): """ Return SSH command with all arguments. Args: cmd (list): command that should run on remote host custom_args (list): additional arguments paste to the command port (bool): use port from config cipher (bool): use cipher from config user_host (bool): use user@host from config ionice (bool): use ionice if configured nice (bool): use nice if configured quote (bool): quote remote command prefix (bool): use prefix from config before remote command profile_id (str): profile ID that should be used in config Returns: list: ssh command with chosen arguments """ # Refactor: Use of assert is discouraged in productive code. # Raise Exceptions instead. assert cmd is None or isinstance(cmd, list), "cmd '{}' is not list instance".format(cmd) assert custom_args is None or isinstance(custom_args, list), "custom_args '{}' is not list instance".format(custom_args) ssh = ['ssh'] ssh += self.sshDefaultArgs(profile_id) # Proxy (aka Jump host) if self.sshProxyHost(profile_id): ssh += ['-J', '{}@{}:{}'.format( self.sshProxyUser(profile_id), self.sshProxyHost(profile_id), self.sshProxyPort(profile_id) )] # remote port if port: ssh += ['-p', str(self.sshPort(profile_id))] # cipher used to transfer data c = self.sshCipher(profile_id) if c != 'default': # Using cipher is deprecated (#2143) and will be removed (#2176) # in foreseen future. logger.critical( 'Using a configured cipher in Back In Time is deprecated. ' f'Configured cipher: "{c}". Behavior will be removed in a ' 'future release. Configure the cipher using the SSH client ' 'config file instead. First remove key "profile.snapshots' '.ssh.cipher=" from Back In Time\'s config file ' '("~/.config/backintime/config").' ) if cipher: ssh += ['-o', f'Ciphers={c}'] # custom arguments if custom_args: ssh += custom_args # user@host if user_host: ssh.append('{}@{}'.format(self.sshUser(profile_id), self.sshHost(profile_id))) # quote the command running on remote host if quote and cmd: ssh.append("'") # run 'ionice' on remote host if ionice and self.ioniceOnRemote(profile_id) and cmd: ssh += ['ionice', '-c2', '-n7'] # run 'nice' on remote host if nice and self.niceOnRemote(profile_id) and cmd: ssh += ['nice', '-n19'] # run prefix on remote host if prefix and cmd and self.sshPrefixEnabled(profile_id): ssh += self.sshPrefixCmd(profile_id, cmd_type=type(cmd)) # add the command if cmd: ssh += cmd # close quote if quote and cmd: ssh.append("'") logger.debug(f'SSH command: {ssh}', self) return ssh # EncFS def localEncfsPath(self, profile_id = None): #?Where to save snapshots in mode 'local_encfs'.;absolute path return self.profileStrValue('snapshots.local_encfs.path', '', profile_id) def setLocalEncfsPath(self, value, profile_id = None): self.setProfileStrValue('snapshots.local_encfs.path', value, profile_id) # gocryptfs def localGocryptfsPath(self, profile_id = None): #?Where to save snapshots in mode 'local_gocryptfs'.;absolute path return self.profileStrValue('snapshots.local_gocryptfs.path', '', profile_id) def setLocalGocryptfsPath(self, value, profile_id = None): self.setProfileStrValue('snapshots.local_gocryptfs.path', value, profile_id) def passwordSave(self, profile_id = None, mode = None): if mode is None: mode = self.snapshotsMode(profile_id) #?Save password to system keyring (gnome-keyring or kwallet). #? must be the same as \fIprofile.snapshots.mode\fR return self.profileBoolValue('snapshots.%s.password.save' % mode, False, profile_id) def setPasswordSave(self, value, profile_id = None, mode = None): if mode is None: mode = self.snapshotsMode(profile_id) self.setProfileBoolValue('snapshots.%s.password.save' % mode, value, profile_id) def passwordUseCache(self, profile_id = None, mode = None): if mode is None: mode = self.snapshotsMode(profile_id) #?Cache password in RAM so it can be read by cronjobs. #?Security issue: root might be able to read that password, too. #? must be the same as \fIprofile.snapshots.mode\fR;;true return self.profileBoolValue('snapshots.%s.password.use_cache' % mode, True, profile_id) def setPasswordUseCache(self, value, profile_id = None, mode = None): if mode is None: mode = self.snapshotsMode(profile_id) self.setProfileBoolValue('snapshots.%s.password.use_cache' % mode, value, profile_id) def password(self, parent=None, profile_id=None, mode=None, pw_id=1, only_from_keyring=False): if self.pw is None: self.pw = password.Password(self) if profile_id is None: profile_id = self.currentProfile() if mode is None: mode = self.snapshotsMode(profile_id) return self.pw.password( parent, profile_id, mode, pw_id, only_from_keyring) def setPassword(self, password_value, profile_id=None, mode=None, pw_id=1): if self.pw is None: self.pw = password.Password(self) if profile_id is None: profile_id = self.currentProfile() if mode is None: mode = self.snapshotsMode(profile_id) self.pw.setPassword(password_value, profile_id, mode, pw_id) def modeNeedPassword(self, mode, pw_id = 1): need_pw = self.SNAPSHOT_MODES[mode][pw_id + 1] if need_pw is False: return False return True def keyringServiceName(self, profile_id = None, mode = None, pw_id = 1): if mode is None: mode = self.snapshotsMode(profile_id) if pw_id > 1: return 'backintime/%s_%s' % (mode, pw_id) return 'backintime/%s' % mode def keyringUserName(self, profile_id = None): if profile_id is None: profile_id = self.currentProfile() return 'profile_id_%s' % profile_id def hostUserProfileDefault(self, profile_id=None): host = socket.gethostname() user = getpass.getuser() profile = profile_id if profile is None: profile = self.currentProfile() return (host, user, profile) def hostUserProfile(self, profile_id = None): default_host, default_user, default_profile = self.hostUserProfileDefault(profile_id) #?Set Host for snapshot path;;local hostname host = self.profileStrValue('snapshots.path.host', default_host, profile_id) #?Set User for snapshot path;;local username user = self.profileStrValue('snapshots.path.user', default_user, profile_id) #?Set Profile-ID for snapshot path;1-99999;current Profile-ID profile = self.profileStrValue('snapshots.path.profile', default_profile, profile_id) return (host, user, profile) def setHostUserProfile(self, host, user, profile, profile_id = None): self.setProfileStrValue('snapshots.path.host', host, profile_id) self.setProfileStrValue('snapshots.path.user', user, profile_id) self.setProfileStrValue('snapshots.path.profile', profile, profile_id) def include(self, profile_id=None): #?Include this file or folder. must be a counter starting with 1;absolute path:: #?Specify if \fIprofile.snapshots.include..value\fR is a folder (0) or a file (1).;0|1;0 return self.profileListValue(key='snapshots.include', type_key=('str:value', 'int:type'), default=[], profile_id=profile_id) def setInclude(self, values, profile_id = None): self.setProfileListValue('snapshots.include', ('str:value', 'int:type'), values, profile_id) def exclude(self, profile_id = None): """ Gets the exclude patterns """ #?Exclude this file or folder. must be a counter #?starting with 1;file, folder or pattern (relative or absolute) return self.profileListValue('snapshots.exclude', 'str:value', [], profile_id) def setExclude(self, values, profile_id = None): self.setProfileListValue('snapshots.exclude', 'str:value', values, profile_id) def excludeBySizeEnabled(self, profile_id = None): #?Enable exclude files by size. return self.profileBoolValue('snapshots.exclude.bysize.enabled', False, profile_id) def excludeBySize(self, profile_id = None): #?Exclude files bigger than value in MiB. #?With 'Full rsync mode' disabled this will only affect new files #?because for rsync this is a transfer option, not an exclude option. #?So big files that has been backed up before will remain in snapshots #?even if they had changed. return self.profileIntValue('snapshots.exclude.bysize.value', 500, profile_id) def setExcludeBySize(self, enabled, value, profile_id = None): self.setProfileBoolValue('snapshots.exclude.bysize.enabled', enabled, profile_id) self.setProfileIntValue('snapshots.exclude.bysize.value', value, profile_id) def tag(self, profile_id = None): #?!ignore this in manpage return self.profileStrValue('snapshots.tag', str(random.randint(100, 999)), profile_id) def scheduleMode(self, profile_id = None): #?Which schedule used for crontab. The crontab entry will be #?generated with 'backintime check-config'.\n #? 0 = Disabled\n 1 = at every boot\n 2 = every 5 minute\n #? 4 = every 10 minute\n 7 = every 30 minute\n10 = every hour\n #?12 = every 2 hours\n14 = every 4 hours\n16 = every 6 hours\n #?18 = every 12 hours\n19 = custom defined hours\n20 = every day\n #?25 = daily anacron\n27 = when drive get connected\n30 = every week\n #?40 = every month\n80 = every year #?;0|1|2|4|7|10|12|14|16|18|19|20|25|27|30|40|80;0 value = self.profileIntValue('schedule.mode', Config.NONE.value, profile_id) return bitbase.ScheduleMode(value) def setScheduleMode(self, value, profile_id = None): if isinstance(value, bitbase.ScheduleMode): value = value.value self.setProfileIntValue('schedule.mode', value, profile_id) def schedule_offset(self, profile_id = None): return self.profileIntValue('schedule.offset', Config.DEFAULT_OFFSET, profile_id) def set_schedule_offset(self, value, profile_id = None): self.setProfileIntValue('schedule.offset', value, profile_id) def scheduleDebug(self, profile_id = None): #?Enable debug output to system log for schedule mode. return self.profileBoolValue('schedule.debug', False, profile_id) def setScheduleDebug(self, value, profile_id = None): self.setProfileBoolValue('schedule.debug', value, profile_id) def scheduleTime(self, profile_id = None): #?Position-coded number with the format "hhmm" to specify the hour #?and minute the cronjob should start (eg. 2015 means a quarter #?past 8pm). Leading zeros can be omitted (eg. 30 = 0030). #?Only valid for #?\fIprofile.schedule.mode\fR = 20 (daily), 30 (weekly), #?40 (monthly) and 80 (yearly);0-2400 return self.profileIntValue('schedule.time', 0, profile_id) def scheduleHourMinute(self, profile_id: str = None ) -> tuple[int, int]: the_time = self.scheduleTime(profile_id) return (the_time // 100, the_time % 100) def setScheduleTime(self, value, profile_id = None): self.setProfileIntValue('schedule.time', value, profile_id) def scheduleDay(self, profile_id = None): #?Which day of month the cronjob should run? Only valid for #?\fIprofile.schedule.mode\fR >= 40;1-28 return self.profileIntValue('schedule.day', 1, profile_id) def setScheduleDay(self, value, profile_id = None): self.setProfileIntValue('schedule.day', value, profile_id) def scheduleWeekday(self, profile_id = None): #?Which day of week the cronjob should run? Only valid for #?\fIprofile.schedule.mode\fR = 30;1 = monday \- 7 = sunday return self.profileIntValue('schedule.weekday', 7, profile_id) def setScheduleWeekday(self, value, profile_id = None): self.setProfileIntValue('schedule.weekday', value, profile_id) def customBackupTime(self, profile_id = None): #?Custom hours for cronjob. Only valid for #?\fIprofile.schedule.mode\fR = 19 #?;comma separated int (8,12,18,23) or */3;8,12,18,23 return self.profileStrValue('schedule.custom_time', '8,12,18,23', profile_id) def setCustomBackupTime(self, value, profile_id = None): self.setProfileStrValue('schedule.custom_time', value, profile_id) def scheduleRepeatedPeriod(self, profile_id = None): #?How many units to wait between new snapshots with anacron? Only valid #?for \fIprofile.schedule.mode\fR = 25|27 return self.profileIntValue('schedule.repeatedly.period', 1, profile_id) def setScheduleRepeatedPeriod(self, value, profile_id = None): self.setProfileIntValue('schedule.repeatedly.period', value, profile_id) def scheduleRepeatedUnit(self, profile_id = None): #?Units to wait between new snapshots with anacron.\n #?10 = hours\n20 = days\n30 = weeks\n40 = months\n #?Only valid for \fIprofile.schedule.mode\fR = 25|27; #?10|20|30|40;20 value = self.profileIntValue('schedule.repeatedly.unit', bitbase.TimeUnit.DAY.value, profile_id) return bitbase.TimeUnit(value) def setScheduleRepeatedUnit(self, value, profile_id = None): if isinstance(value, bitbase.TimeUnit): value = value.value self.setProfileIntValue('schedule.repeatedly.unit', value, profile_id) def removeOldSnapshots(self, profile_id = None): #?Remove all snapshots older than value + unit return (self.profileBoolValue('snapshots.remove_old_snapshots.enabled', True, profile_id), #?Snapshots older than this times units will be removed self.profileIntValue('snapshots.remove_old_snapshots.value', 10, profile_id), #?20 = days\n30 = weeks\n80 = years;20|30|80;80 bitbase.TimeUnit(self.profileIntValue('snapshots.remove_old_snapshots.unit', bitbase.TimeUnit.YEAR, profile_id))) def keepOnlyOneSnapshot(self, profile_id = None): #?NOT YET IMPLEMENTED. Remove all snapshots but one. return self.profileBoolValue('snapshots.keep_only_one_snapshot.enabled', False, profile_id) def setKeepOnlyOneSnapshot(self, value, profile_id = None): self.setProfileBoolValue('snapshots.keep_only_one_snapshot.enabled', value, profile_id) def removeOldSnapshotsEnabled(self, profile_id = None): return self.profileBoolValue('snapshots.remove_old_snapshots.enabled', True, profile_id) def removeOldSnapshotsDate(self, profile_id=None): enabled, value, unit = self.removeOldSnapshots(profile_id) if not enabled: return datetime.date(1, 1, 1) return _remove_old_snapshots_date(value, unit) def setRemoveOldSnapshots(self, enabled, value, unit, profile_id = None): self.setProfileBoolValue('snapshots.remove_old_snapshots.enabled', enabled, profile_id) self.setProfileIntValue('snapshots.remove_old_snapshots.value', value, profile_id) self.setProfileIntValue('snapshots.remove_old_snapshots.unit', unit, profile_id) def warnFreeSpaceEnabled(self, profile_id=None): value = self.profileIntValue('snapshots.warn_free_space.value', 0, profile_id) return value > 0 def warnFreeSpace(self, profile_id=None) -> StorageSize: value = self.profileIntValue('snapshots.warn_free_space.value', 0, profile_id) unit = self.profileIntValue('snapshots.warn_free_space.unit', SizeUnit.MIB, profile_id) return StorageSize(value, SizeUnit(unit)) def setWarnFreeSpaceDisabled(self, profile_id=None): self.setWarnFreeSpace(value=StorageSize(0, SizeUnit.MIB), profile_id=profile_id) def setWarnFreeSpace(self, value: StorageSize, profile_id=None): self.setProfileIntValue('snapshots.warn_free_space.value', value.value(), profile_id) self.setProfileIntValue('snapshots.warn_free_space.unit', value.unit.value, profile_id) def minFreeSpace(self, profile_id = None): #?Remove snapshots until \fIprofile.snapshots.min_free_space.value\fR #?free space is reached. return ( self.profileBoolValue('snapshots.min_free_space.enabled', True, profile_id), #?Keep at least value + unit free space.;1-99999 self.profileIntValue('snapshots.min_free_space.value', 1, profile_id), #?10 = MB\n20 = GB;10|20;20 SizeUnit(self.profileIntValue('snapshots.min_free_space.unit', SizeUnit.GIB, profile_id)) ) def minFreeSpaceAsStorageSize(self, profile_id = None): enabled, value, unit = self.minFreeSpace(profile_id) return ( enabled, StorageSize(value, SizeUnit(unit)) ) def minFreeSpaceEnabled(self, profile_id = None): return self.profileBoolValue('snapshots.min_free_space.enabled', False, profile_id) def setMinFreeSpace(self, enabled, value, unit, profile_id = None): self.setProfileBoolValue('snapshots.min_free_space.enabled', enabled, profile_id) self.setProfileIntValue('snapshots.min_free_space.value', value, profile_id) self.setProfileIntValue('snapshots.min_free_space.unit', unit, profile_id) def setMinFreeSpaceWithStorageSize(self, enabled, value: StorageSize, profile_id = None): self.setMinFreeSpace( enabled=enabled, value=value.value(), unit=value.unit.value, profile_id=profile_id ) def minFreeInodes(self, profile_id = None): #?Keep at least value % free inodes.;1-15 return self.profileIntValue('snapshots.min_free_inodes.value', 2, profile_id) def minFreeInodesEnabled(self, profile_id = None): #?Remove snapshots until \fIprofile.snapshots.min_free_inodes.value\fR #?free inodes in % is reached. return self.profileBoolValue('snapshots.min_free_inodes.enabled', False, profile_id) def setMinFreeInodes(self, enabled, value, profile_id = None): self.setProfileBoolValue('snapshots.min_free_inodes.enabled', enabled, profile_id) self.setProfileIntValue('snapshots.min_free_inodes.value', value, profile_id) def dontRemoveNamedSnapshots(self, profile_id = None): #?Keep snapshots with names during smart_remove. return self.profileBoolValue('snapshots.dont_remove_named_snapshots', True, profile_id) def setDontRemoveNamedSnapshots(self, value, profile_id = None): self.setProfileBoolValue('snapshots.dont_remove_named_snapshots', value, profile_id) def smartRemove(self, profile_id = None): #?Run smart_remove to clean up old snapshots after a new snapshot was created. return (self.profileBoolValue('snapshots.smart_remove', False, profile_id), #?Keep all snapshots for X days. self.profileIntValue('snapshots.smart_remove.keep_all', 2, profile_id), #?Keep one snapshot per day for X days. self.profileIntValue('snapshots.smart_remove.keep_one_per_day', 7, profile_id), #?Keep one snapshot per week for X weeks. self.profileIntValue('snapshots.smart_remove.keep_one_per_week', 4, profile_id), #?Keep one snapshot per month for X month. self.profileIntValue('snapshots.smart_remove.keep_one_per_month', 24, profile_id)) def setSmartRemove(self, value, keep_all, keep_one_per_day, keep_one_per_week, keep_one_per_month, profile_id = None): self.setProfileBoolValue('snapshots.smart_remove', value, profile_id) self.setProfileIntValue('snapshots.smart_remove.keep_all', keep_all, profile_id) self.setProfileIntValue('snapshots.smart_remove.keep_one_per_day', keep_one_per_day, profile_id) self.setProfileIntValue('snapshots.smart_remove.keep_one_per_week', keep_one_per_week, profile_id) self.setProfileIntValue('snapshots.smart_remove.keep_one_per_month', keep_one_per_month, profile_id) def smartRemoveRunRemoteInBackground(self, profile_id = None): #?If using mode SSH or SSH-encrypted, run smart_remove in background on remote machine return self.profileBoolValue('snapshots.smart_remove.run_remote_in_background', False, profile_id) def setSmartRemoveRunRemoteInBackground(self, value, profile_id = None): self.setProfileBoolValue('snapshots.smart_remove.run_remote_in_background', value, profile_id) def notify(self, profile_id = None): #?Display notifications (errors, warnings) through libnotify. return self.profileBoolValue('snapshots.notify.enabled', True, profile_id) def setNotify(self, value, profile_id = None): self.setProfileBoolValue('snapshots.notify.enabled', value, profile_id) def backupOnRestore(self, profile_id = None): #?Rename existing files before restore into FILE.backup.YYYYMMDD return self.profileBoolValue('snapshots.backup_on_restore.enabled', True, profile_id) def setBackupOnRestore(self, value, profile_id = None): self.setProfileBoolValue('snapshots.backup_on_restore.enabled', value, profile_id) def niceOnCron(self, profile_id = None): #?Run cronjobs with 'nice \-n19'. This will give BackInTime the #?lowest CPU priority to not interrupt any other working process. return self.profileBoolValue('snapshots.cron.nice', self.DEFAULT_RUN_NICE_FROM_CRON, profile_id) def setNiceOnCron(self, value, profile_id = None): self.setProfileBoolValue('snapshots.cron.nice', value, profile_id) def ioniceOnCron(self, profile_id = None): #?Run cronjobs with 'ionice \-c2 \-n7'. This will give BackInTime the #?lowest IO bandwidth priority to not interrupt any other working process. return self.profileBoolValue('snapshots.cron.ionice', self.DEFAULT_RUN_IONICE_FROM_CRON, profile_id) def setIoniceOnCron(self, value, profile_id = None): self.setProfileBoolValue('snapshots.cron.ionice', value, profile_id) def ioniceOnUser(self, profile_id = None): #?Run BackInTime with 'ionice \-c2 \-n7' when taking a manual snapshot. #?This will give BackInTime the lowest IO bandwidth priority to not #?interrupt any other working process. return self.profileBoolValue('snapshots.user_backup.ionice', self.DEFAULT_RUN_IONICE_FROM_USER, profile_id) def setIoniceOnUser(self, value, profile_id = None): self.setProfileBoolValue('snapshots.user_backup.ionice', value, profile_id) def niceOnRemote(self, profile_id = None): #?Run rsync and other commands on remote host with 'nice \-n19' return self.profileBoolValue('snapshots.ssh.nice', self.DEFAULT_RUN_NICE_ON_REMOTE, profile_id) def setNiceOnRemote(self, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.nice', value, profile_id) def ioniceOnRemote(self, profile_id = None): #?Run rsync and other commands on remote host with 'ionice \-c2 \-n7' return self.profileBoolValue('snapshots.ssh.ionice', self.DEFAULT_RUN_IONICE_ON_REMOTE, profile_id) def setIoniceOnRemote(self, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.ionice', value, profile_id) def nocacheOnLocal(self, profile_id = None): #?Run rsync on local machine with 'nocache'. #?This will prevent files from being cached in memory. return self.profileBoolValue('snapshots.local.nocache', self.DEFAULT_RUN_NOCACHE_ON_LOCAL, profile_id) def setNocacheOnLocal(self, value, profile_id = None): self.setProfileBoolValue('snapshots.local.nocache', value, profile_id) def nocacheOnRemote(self, profile_id = None): #?Run rsync on remote host with 'nocache'. #?This will prevent files from being cached in memory. return self.profileBoolValue('snapshots.ssh.nocache', self.DEFAULT_RUN_NOCACHE_ON_REMOTE, profile_id) def setNocacheOnRemote(self, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.nocache', value, profile_id) def redirectStdoutInCron(self, profile_id = None): #?redirect stdout to /dev/null in cronjobs return self.profileBoolValue('snapshots.cron.redirect_stdout', self.DEFAULT_REDIRECT_STDOUT_IN_CRON, profile_id) def redirectStderrInCron(self, profile_id = None): #?redirect stderr to /dev/null in cronjobs;;self.DEFAULT_REDIRECT_STDERR_IN_CRON if self.isConfigured(profile_id): default = True else: default = self.DEFAULT_REDIRECT_STDERR_IN_CRON return self.profileBoolValue('snapshots.cron.redirect_stderr', default, profile_id) def setRedirectStdoutInCron(self, value, profile_id = None): self.setProfileBoolValue('snapshots.cron.redirect_stdout', value, profile_id) def setRedirectStderrInCron(self, value, profile_id = None): self.setProfileBoolValue('snapshots.cron.redirect_stderr', value, profile_id) def bwlimitEnabled(self, profile_id = None): #?Limit rsync bandwidth usage over network. Use this with mode SSH. #?For mode Local you should rather use ionice. return self.profileBoolValue('snapshots.bwlimit.enabled', False, profile_id) def bwlimit(self, profile_id = None): #?Bandwidth limit in KB/sec. return self.profileIntValue('snapshots.bwlimit.value', 3000, profile_id) def setBwlimit(self, enabled, value, profile_id = None): self.setProfileBoolValue('snapshots.bwlimit.enabled', enabled, profile_id) self.setProfileIntValue('snapshots.bwlimit.value', value, profile_id) def noSnapshotOnBattery(self, profile_id = None): #?Don't take snapshots if the Computer runs on battery. return self.profileBoolValue('snapshots.no_on_battery', False, profile_id) def setNoSnapshotOnBattery(self, value, profile_id = None): self.setProfileBoolValue('snapshots.no_on_battery', value, profile_id) def preserveAcl(self, profile_id = None): #?Preserve ACL. The source and destination systems must have #?compatible ACL entries for this option to work properly. return self.profileBoolValue('snapshots.preserve_acl', False, profile_id) def setPreserveAcl(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.preserve_acl', value, profile_id) def preserveXattr(self, profile_id = None): #?Preserve extended attributes (xattr). return self.profileBoolValue('snapshots.preserve_xattr', False, profile_id) def setPreserveXattr(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.preserve_xattr', value, profile_id) def copyUnsafeLinks(self, profile_id = None): #?This tells rsync to copy the referent of symbolic links that point #?outside the copied tree. Absolute symlinks are also treated like #?ordinary files. return self.profileBoolValue('snapshots.copy_unsafe_links', False, profile_id) def setCopyUnsafeLinks(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.copy_unsafe_links', value, profile_id) def copyLinks(self, profile_id = None): #?When symlinks are encountered, the item that they point to #?(the reference) is copied, rather than the symlink. return self.profileBoolValue('snapshots.copy_links', False, profile_id) def setCopyLinks(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.copy_links', value, profile_id) def oneFileSystem(self, profile_id = None): #?Use rsync's "--one-file-system" to avoid crossing filesystem #?boundaries when recursing. return self.profileBoolValue('snapshots.one_file_system', False, profile_id) def setOneFileSystem(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.one_file_system', value, profile_id) def rsyncOptionsEnabled(self, profile_id = None): #?Past additional options to rsync return self.profileBoolValue('snapshots.rsync_options.enabled', False, profile_id) def rsyncOptions(self, profile_id = None): #?rsync options. Options must be quoted e.g. \-\-exclude-from="/path/to/my exclude file" return self.profileStrValue('snapshots.rsync_options.value', '', profile_id) def setRsyncOptions(self, enabled, value, profile_id = None): self.setProfileBoolValue('snapshots.rsync_options.enabled', enabled, profile_id) self.setProfileStrValue('snapshots.rsync_options.value', value, profile_id) def sshPrefixEnabled(self, profile_id = None): #?Add prefix to every command which run through SSH on remote host. return self.profileBoolValue('snapshots.ssh.prefix.enabled', False, profile_id) def sshPrefix(self, profile_id = None): #?Prefix to run before every command on remote host. Variables need to be escaped with \\$FOO. #?This doesn't touch rsync. So to add a prefix for rsync use #?\fIprofile.snapshots.rsync_options.value\fR with #?--rsync-path="FOO=bar:\\$FOO /usr/bin/rsync" return self.profileStrValue('snapshots.ssh.prefix.value', self.DEFAULT_SSH_PREFIX, profile_id) def setSshPrefix(self, enabled, value, profile_id = None): self.setProfileBoolValue('snapshots.ssh.prefix.enabled', enabled, profile_id) self.setProfileStrValue('snapshots.ssh.prefix.value', value, profile_id) def sshPrefixCmd(self, profile_id=None, cmd_type=str): """Return the config value of sshPrefix if enabled. Dev note by buhtz (2024-04): Good opportunity to refactor. To much implicit behavior in it. """ if cmd_type == list: if self.sshPrefixEnabled(profile_id): return shlex.split(self.sshPrefix(profile_id)) return [] if cmd_type == str: if self.sshPrefixEnabled(profile_id): return self.sshPrefix(profile_id).strip() + ' ' return '' raise TypeError(f'Unable to handle type {cmd_type}.') def continueOnErrors(self, profile_id = None): #?Continue on errors. This will keep incomplete snapshots rather than #?deleting and start over again. return self.profileBoolValue('snapshots.continue_on_errors', True, profile_id) def setContinueOnErrors(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.continue_on_errors', value, profile_id) def useChecksum(self, profile_id = None): #?Use checksum to detect changes rather than size + time. return self.profileBoolValue('snapshots.use_checksum', False, profile_id) def setUseChecksum(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.use_checksum', value, profile_id) def logLevel(self, profile_id = None): #?Log level used during takeSnapshot.\n1 = Error\n2 = Changes\n3 = Info;1-3 return self.profileIntValue('snapshots.log_level', 3, profile_id) def setLogLevel(self, value, profile_id = None): return self.setProfileIntValue('snapshots.log_level', value, profile_id) def takeSnapshotRegardlessOfChanges(self, profile_id = None): #?Create a new snapshot regardless if there were changes or not. return self.profileBoolValue('snapshots.take_snapshot_regardless_of_changes', False, profile_id) def setTakeSnapshotRegardlessOfChanges(self, value, profile_id = None): return self.setProfileBoolValue('snapshots.take_snapshot_regardless_of_changes', value, profile_id) def globalFlock(self): #?Prevent multiple snapshots (from different profiles or users) to be run at the same time return self.boolValue('global.use_flock', False) def setGlobalFlock(self, value): self.setBoolValue('global.use_flock', value) def appInstanceFile(self): return os.path.join(self._LOCAL_DATA_FOLDER, 'app.lock') def fileId(self, profile_id=None): if profile_id is None: profile_id = self.currentProfile() if profile_id == '1': return '' return profile_id def takeSnapshotLogFile(self, profile_id = None): return os.path.join(self._LOCAL_DATA_FOLDER, "takesnapshot_%s.log" % self.fileId(profile_id)) def takeSnapshotMessageFile(self, profile_id = None): return os.path.join(self._LOCAL_DATA_FOLDER, "worker%s.message" % self.fileId(profile_id)) def takeSnapshotProgressFile(self, profile_id = None): return os.path.join(self._LOCAL_DATA_FOLDER, "worker%s.progress" % self.fileId(profile_id)) def takeSnapshotInstanceFile(self, profile_id=None): return os.path.join( self._LOCAL_DATA_FOLDER, "worker%s.lock" % self.fileId(profile_id)) def takeSnapshotUserCallback(self): return os.path.join(self._LOCAL_CONFIG_FOLDER, "user-callback") def passwordCacheFolder(self): return os.path.join(self._LOCAL_DATA_FOLDER, "password_cache") def passwordCachePid(self): return os.path.join(self.passwordCacheFolder(), "PID") def passwordCacheFifo(self): return os.path.join(self.passwordCacheFolder(), "FIFO") def passwordCacheInfo(self): return os.path.join(self.passwordCacheFolder(), "info") def cronEnvFile(self): return os.path.join(self._LOCAL_DATA_FOLDER, "cron_env") def anacronSpool(self): # ~/.local/share/backintime/anacron return os.path.join(self._LOCAL_DATA_FOLDER, 'anacron') def anacronSpoolFile(self, profile_id=None): """Return the timestamp file related to the current profile. Despite the methods name anacron is not involved. But the anacron behavior is imitated by Back In Time. This timestamp files are an element of this behavior. """ # ~/.local/share/backintime/anacron/1_Main_profile return os.path.join(self.anacronSpool(), self.anacronJobIdentify(profile_id)) def anacronJobIdentify(self, profile_id=None): if not profile_id: profile_id = self.currentProfile() profile_name = self.profileName(profile_id) # "Main profile" -> "1_Main_profile" return profile_id + '_' + profile_name.replace(' ', '_') def udevRulesPath(self): return os.path.join('/etc/udev/rules.d', '99-backintime-%s.rules' % getpass.getuser()) def restoreLogFile(self, profile_id = None): return os.path.join(self._LOCAL_DATA_FOLDER, "restore_%s.log" % self.fileId(profile_id)) def restoreInstanceFile(self, profile_id=None): return os.path.join( self._LOCAL_DATA_FOLDER, "restore%s.lock" % self.fileId(profile_id)) def lastSnapshotSymlink(self, profile_id = None): return os.path.join(self.snapshotsFullPath(profile_id), bitbase.DIR_NAME_LAST_SNAPSHOT) def encfsconfigBackupFolder(self, profile_id = None): return os.path.join(self._LOCAL_DATA_FOLDER, 'encfsconfig_backup_%s' % self.fileId(profile_id)) def isConfigured(self, profile_id=None) -> bool: """Checks if the program is configured. It is assumed as configured if a snapshot path (backup destination) is and include files/directories (backup source) are given. """ path = self.snapshotsPath(profile_id) includes = self.include(profile_id) if bool(path and includes): return True logger.debug(f'Profile ({profile_id=}) is not configured because ' f'backup path is "{bool(path)}" and/or includes ' f'are "{bool(includes)}".', self) return False def canBackup(self, profile_id=None): """Checks if snapshots_path exists. """ if not self.isConfigured(profile_id): return False path = self.snapshotsFullPath(profile_id) if not os.path.exists(path): logger.warning(f'Snapshot path does not exists: {path}', self) return False if not os.path.isdir(path): logger.warning(f'Snapshot path is not a directory: {path}', self) return False return True def backupScheduled(self, profile_id = None): """Check if the profile is supposed to be run this time. Returns: (bool): The answer. """ if self.scheduleMode(profile_id) not in ( bitbase.ScheduleMode.REPEATEDLY, bitbase.ScheduleMode.UDEV): return True last_time = tools.readTimeStamp(self.anacronSpoolFile(profile_id)) if not last_time: return True return tools.elapsed_at_least( start=last_time, end=datetime.datetime.now(), value=self.scheduleRepeatedPeriod(profile_id), unit=self.scheduleRepeatedUnit(profile_id) ) def setup_automation(self): """Update schedule and event base automated backup job execution. This affects crontab and udev rules. """ self._setup_schedule_based_automation() self._setup_event_based_automation() def _setup_event_based_automation(self): """Update udev rules for event based automated profiles.""" self.setupUdev.clean() profile_ids = self.profile_ids_automated_via_udev_evnts() if not len(profile_ids): return for pid in profile_ids: backup_mode = self.snapshotsMode(pid) if backup_mode == 'local': dest_path = self.snapshotsFullPath(pid) elif backup_mode == 'local_gocryptfs': dest_path = self.localGocryptfsPath(pid) elif backup_mode == 'local_encfs': dest_path = self.localEncfsPath(pid) else: logger.error( f"Udev scheduling doesn't work with mode {backup_mode}", self) self.notifyError(_( "Udev schedule doesn't work with mode {mode}") .format(mode=backup_mode)) return # Add rule schedule.add_udev_rule( pid=pid, udev_setup=self.setupUdev, dest_path=dest_path, exec_command=self._cron_cmd(pid), notify_callback=self.notifyError) # Save Udev rules try: if self.setupUdev.isReady and self.setupUdev.save(): logger.debug('Udev rules added successfully', self) except PermissionDeniedByPolicy as err: logger.error(str(err), self) self.notifyError(str(err)) return False def _setup_schedule_based_automation(self): """Update the current users crontab file based on profile settings. The crontab files is read, all entries related to Back In Time are removed and after it added again for each profile based on the profile settings. The difference between a backintime related entry created by Back In Time itself or by the user manually is determined by a comment before each entry. See :data:`schedule._MARKER` and :func:`schedule.remove_bit_from_crontab()` for details. Returns: bool: ``True`` if successful or ``False`` on errors. """ # Lines of current users crontab file org_crontab_lines = schedule.read_crontab() # Remove all auto-generated BIT entries from crontab crontab_lines = schedule.remove_bit_from_crontab(org_crontab_lines) # Add a new entry to existing crontab content based on the current # snapshot profile and its schedule settings. crontab_lines = schedule.append_bit_to_crontab( crontab_lines, self.profiles_cron_lines()) # Crontab modified? if crontab_lines == org_crontab_lines: return if schedule.write_crontab(crontab_lines) is False: logger.error('Failed to write new crontab.') self.notifyError(_('Failed to write new crontab.')) return if not schedule.is_cron_running(): logger.error( 'Cron is not running despite the crontab command being ' 'available. Scheduled backup jobs will not run.') self.notifyError(_( 'Cron is not running, even though the crontab command is ' 'available. Scheduled backup jobs will not run. ' 'Cron might be installed but not enabled. Try running the two ' 'commands "systemctl enable cron" and ' '"systemctl start cron", or consult the support channels of ' 'the currently used GNU/Linux distribution for assistance.')) def profile_ids_automated_via_cron_schedule(self): """Return list of profile ids configured to time based automation using cron rules.""" return list(filter( lambda pid: bitbase.ScheduleMode(self.scheduleMode(pid)) not in (bitbase.ScheduleMode.DISABLED, bitbase.ScheduleMode.UDEV), self.profiles() )) def profile_ids_automated_via_udev_evnts(self): """Return list of profile ids configured to event based automation using udev.""" return list(filter( lambda pid: bitbase.ScheduleMode(self.scheduleMode(pid)) == bitbase.ScheduleMode.UDEV, self.profiles() )) def profiles_cron_lines(self): """Return a list of crontab lines for each of the existing profiles. Return: list: The list of crontab lines. """ profile_ids = self.profile_ids_automated_via_cron_schedule() return [self._cron_line(pid) for pid in profile_ids] def _cron_line(self, profile_id) -> str: """Return a cron line for the specified profile. Returns: `None` in case of errors or profile is not configured for scheduling. """ schedule_mode = self.scheduleMode(profile_id) schedule_mode = bitbase.ScheduleMode(schedule_mode) hour, minute = self.scheduleHourMinute(profile_id) day = self.scheduleDay(profile_id) weekday = self.scheduleWeekday(profile_id) offset = str(self.schedule_offset(profile_id)) return schedule.create_cron_line( schedule_mode=schedule_mode, cron_command=self._cron_cmd(profile_id), hour=hour, minute=minute, day=day, weekday=weekday, offset=offset, custom_backup_time=self.customBackupTime(profile_id), repeat_unit=bitbase.TimeUnit( self.scheduleRepeatedUnit(profile_id)), pid=profile_id, notify_callback=self.notifyError) def _cron_cmd(self, profile_id): """Generates the command used in the crontab file based on the settings for the current profile. Returns: str: The crontab line. """ # Get full path of the Back In Time binary cmd = tools.which('backintime') + ' ' # The "--profile-id" argument is used only for profiles different from # first profile if profile_id != '1': cmd += '--profile %s ' % profile_id # User defined path to config file if not self._LOCAL_CONFIG_PATH is self._DEFAULT_CONFIG_PATH: cmd += '--config %s ' % self._LOCAL_CONFIG_PATH # Enable debug output if self.scheduleDebug(profile_id): cmd += '--debug ' # command cmd += 'backup --background' # Redirect stdout to nirvana if self.redirectStdoutInCron(profile_id): cmd += ' >/dev/null' # Redirect stderr ... if self.redirectStderrInCron(profile_id): if self.redirectStdoutInCron(profile_id): # ... to stdout cmd += ' 2>&1' else: # ... to nirvana cmd += ' 2>/dev/null' # IO priority: low (-n7) in "best effort" class (-c2) if self.ioniceOnCron(profile_id) and tools.checkCommand('ionice'): cmd = tools.which('ionice') + ' -c2 -n7 ' + cmd # CPU priority: very low if self.niceOnCron(profile_id) and tools.checkCommand('nice'): cmd = tools.which('nice') + ' -n19 ' + cmd return cmd def addProfile(self, name: str) -> str | None: pid = super().addProfile(name) if pid: self._unsaved_profiles.append(pid) return pid def _remove_old_snapshots_date(value, unit): """Dev note (buhtz, 2025-01): The function exist to decople that code from Config class and make it testable to investigate its behavior. See issue #1943 for further reading. """ if unit == Config.DAY: date = datetime.date.today() date = date - datetime.timedelta(days=value) return date if unit == Config.WEEK: date = datetime.date.today() # Always beginning (Monday) of the week date = date - datetime.timedelta(days=date.weekday() + 7 * value) return date if unit == Config.YEAR: date = datetime.date.today() return date.replace(day=1, year=date.year - value) return datetime.date(1, 1, 1) backintime-1.6.1/common/configfile.py000066400000000000000000000603631514264426600176160ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import collections import re import logger class ConfigFile: """Store options in a plain text file in form of: key=value """ def __init__(self): self.dict = {} self.errorHandler = None self.questionHandler = None def setErrorHandler(self, handler): """ Register a function that should be called for notifying errors. handler (method): callable function """ self.errorHandler = handler def setQuestionHandler(self, handler): """ Register a function that should be called for asking questions. handler (method): callable function """ self.questionHandler = handler def clearHandlers(self): """ Reset error and question handlers. """ self.errorHandler = None self.questionHandler = None def notifyError(self, message): """ Call previously registered function to show an error. Args: message (str): error message that should be shown """ if self.errorHandler is None: return self.errorHandler(message) def askQuestion(self, message): """ Call previously registered function to ask a question. Args: message (str): question that should be shown """ if self.questionHandler is None: return False return self.questionHandler(message) def save(self, filename): """ Save all options to file. Args: filename (str): full path Returns: bool: ``True`` if successful """ def numsort(key): """ Sort int in keys in numeric order instead of alphabetical by adding leading zeros to int's """ return re.sub(r'\d+', lambda m: m.group(0).zfill(6), key) try: with open(filename, mode='wt', encoding='utf-8') as f: keys = list(self.dict.keys()) keys.sort(key=numsort) for key in keys: f.write("%s=%s\n" % (key, self.dict[key])) except OSError as e: logger.error('Failed to save config: %s' % str(e), self) self.notifyError( '{}: {}'.format(_('Failed to save config'), str(e))) return False return True def load(self, filename, **kwargs): """ Reset current options and load new options from file. Args: filename (str): full path """ self.dict = {} self.append(filename, **kwargs) def append(self, filename, maxsplit=1): """ Load options from file and append them to current options. Args: filename (str): full path maxsplit (int): split lines only n times on '=' """ lines = [] if not os.path.isfile(filename): return try: with open(filename, mode='rt', encoding='utf-8') as f: lines = f.readlines() except OSError as e: logger.error('Failed to load config: %s' % str(e), self) self.notifyError( '{}: {}'.format(_('Failed to load config'), str(e))) for line in lines: items = line.strip('\n').split('=', maxsplit) if len(items) == 2: self.dict[items[0]] = items[1] def remapKey(self, old_key, new_key): """ Remap keys to a new key name. Args: old_key (str): old key name new_key (str): new key name """ if old_key != new_key: if old_key in self.dict: if new_key not in self.dict: self.dict[new_key] = self.dict[old_key] del self.dict[old_key] def remapKeyRegex(self, pattern, replace): """ Remap keys to a new key name using :py:func:`re.sub`. Args: pattern (str): part of key name that should be replaced replace (:py:class:`str`, method): string or a callable function which will be used to replace all matches of ``pattern``. """ c = re.compile(pattern) for key in list(self.dict): newKey = c.sub(replace, key) if key != newKey: self.remapKey(key, newKey) def hasKey(self, key): """ ``True`` if key is set. Args: key (str): string used as key Returns: bool: ``True`` if the ``key`` is set """ return key in self.dict def strValue(self, key, default=''): """ Return a 'str' instance of key's value. Args: key (str): Key identifying the value in the config file. default (str): Default value if ``key`` is not present. Returns: str: Value of ``key`` or ``default``. """ if key in self.dict: return self.dict[key] else: return default def setStrValue(self, key, value): """ Set a string value for key. Args: key (str): string used as key value (str): store this value """ self.dict[key] = value def intValue(self, key, default=0): """ Return a 'int' instance of key's value. Args: key (str): string used as key default (int): return this if ``key`` is not set Returns: int: value of ``key`` or ``default`` if ``key`` is not set. """ try: return int(self.dict[key]) except Exception: return default def setIntValue(self, key, value): """ Set an integer value for key. Args: key (str): string used as key value (int): store this option """ self.setStrValue(key, str(value)) def boolValue(self, key, default=False): """ Return a 'bool' instance of key's value. Args: key (str): string used as key default (bool): return this if key is not set Returns: bool: value of 'key' or 'default' if 'key' is not set. """ try: val = self.dict[key] if "1" == val or "TRUE" == val.upper(): return True return False except Exception: return default def setBoolValue(self, key, value): """ Set a bool value for key. Args: key (str): string used as key value (bool): store this option """ if value: self.setStrValue(key, 'true') else: self.setStrValue(key, 'false') def listValue(self, key, type_key='str:value', default=[]): """ Return a list of values Size of the list must be stored in key.size Args: key (str): used base-key type_key (str): pattern of 'value-type:value-name'. See examples below. default (list): default value Returns: list: value of ``key`` or ``default`` if ``key`` is not set. ``type_key`` pattern examples:: 'str:value' => return str values from key.value 'int:type' => return int values from key.type 'bool:enabled' => return bool values from key.enabled ('str:value', 'int:type') => return tuple of values """ def typeKeySplit(tk): t, k = '', '' if isinstance(tk, str): t, k = tk.split(':', maxsplit=1) return (t, k) def value(key, tk): t, k = typeKeySplit(tk) if t in ('str', 'int', 'bool'): func = getattr(self, '%sValue' % t) return func('%s.%s' % (key, k)) raise TypeError('Invalid type_key: %s' % tk) size = self.intValue('%s.size' % key, -1) if size < 0: return default ret = [] for i in range(1, size + 1): if isinstance(type_key, str): if not self.hasKey('%s.%s.%s' % (key, i, typeKeySplit(type_key)[1])): continue ret.append(value('%s.%s' % (key, i), type_key)) elif isinstance(type_key, tuple): if not self.hasKey('%s.%s.%s' % (key, i, typeKeySplit(type_key[0])[1])): continue items = [] for tk in type_key: items.append(value('%s.%s' % (key, i), tk)) ret.append(tuple(items)) else: raise TypeError('Invalid type_key: %s' % type_key) return ret def setListValue(self, key, type_key, value): """ Set a list of values. Size of the list will be stored in key.size Args: key (str): used base-key type_key (str): pattern of 'value-type:value-name'. See examples below. value (list): that should be stored ``type_key`` pattern examples:: 'str:value' => return str values from key.value 'int:type' => return int values from key.type 'bool:enabled' => return bool values from key.enabled ('str:value', 'int:type') => return tuple of values """ def setValue(key, tk, v): t = '' if isinstance(tk, str): t, k = tk.split(':', maxsplit=1) if t in ('str', 'int', 'bool'): func = getattr(self, 'set%sValue' % t.capitalize()) return func('%s.%s' % (key, k), v) raise TypeError('Invalid type_key: %s' % tk) if not isinstance(value, (list, tuple)): raise TypeError('value has wrong type: %s' % value) old_size = self.intValue('%s.size' % key, -1) self.setIntValue('%s.size' % key, len(value)) for i, v in enumerate(value, start=1): if isinstance(type_key, str): setValue('%s.%s' % (key, i), type_key, v) elif isinstance(type_key, tuple): for iv, tk in enumerate(type_key): if len(v) > iv: setValue('%s.%s' % (key, i), tk, v[iv]) else: self.removeKey('%s.%s.%s' % (key, i, tk.split(':')[1])) else: raise TypeError('Invalid type_key: %s' % type_key) if len(value) < old_size: for i in range(len(value) + 1, old_size + 1): if isinstance(type_key, str): self.removeKey( '%s.%s.%s' % (key, i, type_key.split(':')[1])) elif isinstance(type_key, tuple): for tk in type_key: self.removeKey( '%s.%s.%s' % (key, i, tk.split(':')[1])) def removeKey(self, key): """ Remove key from options. Args: key (str): string used as key """ if key in self.dict: del self.dict[key] def removeKeysStartsWith(self, prefix): """ Remove key from options which start with given prefix. Args: prefix (str): prefix for keys (key starts with this string) that should be removed """ removeKeys = [] for key in self.dict.keys(): if key.startswith(prefix): removeKeys.append(key) for key in removeKeys: del self.dict[key] def keys(self): return list(self.dict.keys()) class ConfigFileWithProfiles(ConfigFile): """ Store options in profiles as 'profileX.key=value' Args: default_profile_name (str): default name of the first profile. """ def __init__(self, default_profile_name=''): ConfigFile.__init__(self) self.default_profile_name = default_profile_name self.current_profile_id = '1' self.setCurrentProfile(self.current_profile_id) def load(self, filename): """ Reset current options and load new options from file. Args: filename (str): full path """ self.current_profile_id = '1' super(ConfigFileWithProfiles, self).load(filename) def append(self, filename): """Load options from file and append them to current options. Args: filename (str): full path """ super(ConfigFileWithProfiles, self).append(filename) found = False profiles = self.profiles() for profile_id in profiles: if profile_id == self.current_profile_id: found = True break if not found and profiles: self.current_profile_id = profiles[0] if self.intValue('profiles.version') <= 0: rename_keys = [] for key in self.dict.keys(): if key.startswith('profile.0.'): rename_keys.append(key) for old_key in rename_keys: new_key = 'profile1.' + old_key[10:] self.dict[new_key] = self.dict[old_key] del self.dict[old_key] if self.intValue('profiles.version') != 1: self.setIntValue('profiles.version', 1) def profiles(self): """ List of all available profile IDs. Profile IDs are strings! Returns: list: List with strings of profile IDs as strings. """ return self.strValue(key='profiles', default='1').split(':') def profilesSortedByName(self): """ List of available profile IDs alphabetically sorted by their names. Profile IDs are strings! Returns: list: all available profile IDs as strings """ profiles_unsorted = self.profiles() if len(profiles_unsorted) <= 1: return profiles_unsorted profiles_dict = {} for profile_id in profiles_unsorted: profiles_dict[self.profileName(profile_id).upper()] = profile_id # sort the dictionary by key (the profile name) profiles_sorted = collections.OrderedDict( sorted(profiles_dict.items())) # return the names as a list return list(profiles_sorted.values()) def currentProfile(self): """ Currently selected profile ID. Profile IDs are strings! Returns: str: profile ID """ return self.current_profile_id def setCurrentProfile(self, profile_id): """ Change the current profile. Args: profile_id (str, int): valid profile ID Returns: bool: ``True`` if successful """ if isinstance(profile_id, int): profile_id = str(profile_id) profiles = self.profiles() for i in profiles: if i == profile_id: profile_name = self.profileName(profile_id) self.current_profile_id = profile_id logger.changeProfile(profile_id, profile_name) logger.debug( f'Change current profile to {profile_name}({profile_id})', self) return True return False def setCurrentProfileByName(self, name): """ Change the current profile by a given name. Args: name (str): valid profile name Returns: bool: ``True`` if successful """ # Find the profile_id to this name... for profile_id in self.profiles(): if self.profileName(profile_id) == name: # ...and set current profile by this id. return self.setCurrentProfile(profile_id) return False def profileExists(self, profile_id): """ ``True`` if the profile exists. Args: profile_id (str, int): profile ID Returns: bool: ``True`` if ``profile_id`` exists. """ if isinstance(profile_id, int): profile_id = str(profile_id) return profile_id in self.profiles() def profileExistsByName(self, name) -> bool: """ ``True`` if the profile exists. Args: name (str): profile name Returns: bool: ``True`` if ``name`` exists. """ profiles = self.profiles() for profile_id in profiles: if self.profileName(profile_id) == name: return True return False def profileName(self, profile_id=None): """Name of the profile. Args: profile_id (str, int): Valid profile ID Returns: str: Name of profile. """ if isinstance(profile_id, int): profile_id = str(profile_id) if profile_id is None: profile_id = self.current_profile_id if profile_id == '1': default = self.default_profile_name else: default = 'Profile %s' % profile_id return self.profileStrValue('name', default, profile_id) def addProfile(self, name: str) -> str | None: """Add a new profile if the name is not already in use. Args: name (str): Profile name. Returns: str: The new profile ID or None if profile with same name already exists. """ if self.profileExistsByName(name): self.notifyError( _('Profile "{name}" already exists.').format(name=name)) return None profiles = self.profiles() pid = self._next_unused_id() profiles.append(self._next_unused_id()) self.setStrValue('profiles', ':'.join(profiles)) self.setProfileStrValue('name', name, pid) return pid def _next_unused_id(self): pid = 1 existing_pids = self.profiles() while True: if str(pid) in existing_pids: pid += 1 else: break return str(pid) def removeProfile(self, profile_id=None): """ Remove profile and all its keys and values. Args: profile_id (str, int): valid profile ID Returns: bool: ``True`` if successful """ if isinstance(profile_id, int): profile_id = str(profile_id) if profile_id is None: profile_id = self.current_profile_id profiles = self.profiles() if len(profiles) <= 1: self.notifyError(_("The last profile cannot be removed.")) return False found = False index = 0 for profile in profiles: if profile == profile_id: self.removeKeysStartsWith(self.profileKey('', profile_id)) del profiles[index] self.setStrValue('profiles', ':'.join(profiles)) found = True break index = index + 1 if not found: return False if self.current_profile_id == profile_id: self.current_profile_id = '1' return True def setProfileName(self, name, profile_id=None): """ Change the name of the profile. Args: name (str): new profile name profile_id (str, int): valid profile ID Returns: bool: ``True`` if successful. """ if isinstance(profile_id, int): profile_id = str(profile_id) if profile_id is None: profile_id = self.current_profile_id profiles = self.profiles() for profile in profiles: if self.profileName(profile) == name: if profile[0] != profile_id: self.notifyError(_( 'Profile "{name}" already exists.').format(name=name)) return False self.setProfileStrValue('name', name, profile_id) return True def profileKey(self, key, profile_id=None): """ Prefix for keys with profile. e.g. 'profile1.key' Args: key (str): Key identifier. profile_id (str, int): Valid profile ID. Returns: str: Key with prefix 'profile1.key' """ if isinstance(profile_id, int): profile_id = str(profile_id) if profile_id is None: profile_id = self.current_profile_id return 'profile' + profile_id + '.' + key def removeProfileKey(self, key, profile_id=None): """ Remove the key from profile. Args: key (str): key name profile_id (str, int): valid profile ID """ self.removeKey(self.profileKey(key, profile_id)) def removeProfileKeysStartsWith(self, prefix, profile_id=None): """ Remove the keys starting with prefix from profile. Args: prefix (str): prefix for keys (key starts with this string) that should be removed. profile_id (str, int): valid profile ID """ self.removeKeysStartsWith(self.profileKey(prefix, profile_id)) def remapProfileKey(self, oldKey, newKey, profileId=None): """ Remap profile keys to a new key name. Args: oldKey (str): old key name newKey (str): new key name profileId (str, int): valid profile ID """ self.remapKey(self.profileKey(oldKey, profileId), self.profileKey(newKey, profileId)) def hasProfileKey(self, key, profile_id=None): """ ``True`` if key is set in profile. Args: key (str): string used as key profile_id (str, int): valid profile ID Returns: bool: ``True`` if ``key`` is set. """ return self.profileKey(key, profile_id) in self.dict def profileStrValue(self, key, default='', profile_id=None): """Return the value of ``key`` related to ``profile_id``. Returns: str: The value. """ return self.strValue(self.profileKey(key, profile_id), default) def setProfileStrValue(self, key, value, profile_id=None): self.setStrValue(self.profileKey(key, profile_id), value) def profileIntValue(self, key, default=0, profile_id=None): return self.intValue(self.profileKey(key, profile_id), default) def setProfileIntValue(self, key, value, profile_id=None): self.setIntValue(self.profileKey(key, profile_id), value) def profileBoolValue(self, key, default=False, profile_id=None): return self.boolValue(self.profileKey(key, profile_id), default) def setProfileBoolValue(self, key, value, profile_id=None): self.setBoolValue(self.profileKey(key, profile_id), value) def profileListValue(self, key, type_key='str:value', default=[], profile_id=None): return self.listValue( self.profileKey(key, profile_id), type_key, default) def setProfileListValue(self, key, type_key, value, profile_id=None): self.setListValue(self.profileKey(key, profile_id), type_key, value) backintime-1.6.1/common/configure000077500000000000000000000246171514264426600170500ustar00rootroot00000000000000#!/bin/sh # SPDX-FileCopyrightText: © 2009 Oprea Dan # SPDX-FileCopyrightText: © 2013 Germar Reitze # SPDX-FileCopyrightText: © 2022 Jürgen Altfeld # SPDX-FileCopyrightText: © 2022 Christian Buhtz # SPDX-FileCopyrightText: © 2023 Kian-Meng Ang # SPDX-FileCopyrightText: © 2023 Fabio Fantoni # SPDX-FileCopyrightText: © 2024 Tejas Guruswamy # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # This is the configuration file for the Read the Docs service. # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details. # Clean up if [ -e Makefile ]; then rm Makefile; fi # Tmp files MAKEFILE="$(mktemp)" UNINSTALL_FILES="$(mktemp)" UNINSTALL_DIRS="$(mktemp)" # set default options PYTHON="/usr/bin/python3" USR_BIN_FILES="backintime backintime-askpass" usage () { echo "Usage:" echo "$0 [--python | --python3 | --python=PYTHON_BINARY]" echo "" echo "--python" echo "\tuse 'python' to start Python3" echo "--python3" echo "\tuse 'python3' to start Python3" echo "--python=PYTHON_BINARY" echo "\tuse PYTHON_BINARY to start Python3" } addInstallFiles () { file=$1 dest=$2 mode=$3 if [ -z "$mode" ]; then mode=644 fi for i in $(ls $file); do addInstallFile "$i" "$dest" "$mode" done } addInstallFile () { file=$1 dest=$2 mode=$3 if [ -z "$mode" ]; then mode=644 fi printf "\tinstall --mode=$mode $file \$(DEST)$dest\n" >> ${MAKEFILE} addUninstallFile "$file" "$dest" } addSymlink () { dst=$1 src=$2 printf "\tln --symbolic --force $dst \$(DEST)$src\n" >> ${MAKEFILE} addUninstallFile "$src" } addInstallFileRename () { file=$1 dest=$2 mode=$3 if [ -z "$mode" ]; then mode=644 fi printf "\tinstall --mode=$mode $file \$(DEST)$dest\n" >> ${MAKEFILE} addUninstallFileRename "$dest" } addUninstallFile () { if [ $# -eq 2 ]; then file=$(basename "$1") dest=$2 path="\$(DEST)$dest/$file" else path="\$(DEST)$1" fi printf "\trm -f $path\n" >> ${UNINSTALL_FILES} } addUninstallFileRename () { file=$1 printf "\trm -f \$(DEST)$file\n" >> ${UNINSTALL_FILES} } addInstallDir () { dest=$1 printf "\tinstall -d \$(DEST)$dest\n" >> ${MAKEFILE} addUninstallDir "$dest" } addUninstallDir () { dest=$1 printf "\tif [ -d \$(DEST)$dest ]; then rmdir --ignore-fail-on-non-empty \$(DEST)$dest; fi\n" >> ${UNINSTALL_DIRS} } addComment () { printf "\t# Install $1\n" >> ${MAKEFILE} printf "\t# Uninstall files $1\n" >> ${UNINSTALL_FILES} printf "\t# Uninstall directory $1\n" >> ${UNINSTALL_DIRS} } addNewline () { printf "\n" >> ${MAKEFILE} printf "\n" >> ${UNINSTALL_FILES} printf "\n" >> ${UNINSTALL_DIRS} } onTravis () { [ "${TRAVIS}" = "true" ] } # Get commandline arguments unknown_args="" for arg in $*; do case $arg in --python=*) PYTHON=$(echo $arg | cut -f2 -d'=') ;; --python3) PYTHON="/usr/bin/python3" ;; --python) PYTHON="/usr/bin/python" ;; --help | -h) usage; exit 0;; *) unknown_args="$unknown_args $arg";; esac done if [ -n "$unknown_args" ]; then echo "Unknown Arguments: $unknown_args" fi # Check if the python binary file exists if [ ! -f "$PYTHON" ]; then echo "Warning: \"${PYTHON}\" not found on this computer" fi if [ -n "$(sed -e "s#^/usr/bin/python3\? #${PYTHON} #gw /dev/stdout" -i $USR_BIN_FILES)" ] then echo "Replacement of python path with \"${PYTHON}\" successful." else echo "WARNING: Replacement of python path with \"${PYTHON}\" FAILED. Maybe you ran configure more than once?" fi # Check languages mos="" langs="" for langfile in `ls po/*.po`; do lang=`echo $langfile | cut -d/ -f2 | cut -d. -f1` mos="po/$lang.mo $mos" langs="$lang $langs" done # Start Makefile printf ".PHONY: test test-v unittest unittest-v\n" >> ${MAKEFILE} printf "LANGS=$langs\n\n" >> ${MAKEFILE} printf "PREFIX=/usr\n" >> ${MAKEFILE} printf "DEST=\$(DESTDIR)\$(PREFIX)\n\n" >> ${MAKEFILE} printf "all:\tbuild\n\n" >> ${MAKEFILE} printf "build:\ttranslate compress\n" >> ${MAKEFILE} printf "clean:\n" >> ${MAKEFILE} printf "\trm -f po/*.mo\n" >> ${MAKEFILE} printf "\trm -f ../doc/manpages/*.gz\n" >> ${MAKEFILE} printf "\trm -f config-example-*.gz\n" >> ${MAKEFILE} printf "\trm -rf doc-dev/_build/*\n" >> ${MAKEFILE} printf "\n" >> ${MAKEFILE} # Create install and uninstall target printf "install:\tinstall_translations\n" >> ${MAKEFILE} printf "\n\t# Inject version string into source files\n" >> ${MAKEFILE} printf "\t(cd .. && ./updateversion.sh)\n\n" >> ${MAKEFILE} addComment "python" addUninstallDir "/share/backintime/common/__pycache__" addUninstallFile "*.pyc" "/share/backintime/common/__pycache__" addInstallDir "/share/backintime/common" addInstallFiles "*.py" "/share/backintime/common" addNewline addComment "plugins" addUninstallDir "/share/backintime/plugins/__pycache__" addUninstallFile "*.pyc" "/share/backintime/plugins/__pycache__" addInstallDir "/share/backintime/plugins" addInstallFiles "plugins/*.py" "/share/backintime/plugins" addUninstallDir "/share/backintime" addNewline addComment "documentation" addInstallDir "/share/doc/backintime-common" addInstallFile "../AUTHORS" "/share/doc/backintime-common" addInstallFile "../README.md" "/share/doc/backintime-common" addInstallFile "../FAQ.md" "/share/doc/backintime-common" addInstallFile "../CHANGES" "/share/doc/backintime-common" addInstallFile "../LICENSES.md" "/share/doc/backintime-common" addInstallDir "/share/doc/backintime-common/LICENSES" addInstallFiles "../LICENSES/*" "/share/doc/backintime-common/LICENSES" addNewline addComment "config and user-callback examples" addInstallDir "/share/doc/backintime-common/examples" addInstallFile "config-example-local.gz" "/share/doc/backintime-common/examples" addInstallFile "config-example-ssh.gz" "/share/doc/backintime-common/examples" addInstallDir "/share/doc/backintime-common/user-callback-examples" addInstallFiles "../doc/user-callback-examples/user-callback.*" "/share/doc/backintime-common/user-callback-examples" addUninstallDir "/share/doc/backintime-common" addUninstallDir "/share/doc" addNewline addComment "man" addInstallDir "/share/man/man1" addInstallFile "../doc/manpages/backintime.1.gz" "/share/man/man1" addInstallFile "../doc/manpages/backintime-askpass.1.gz" "/share/man/man1" addInstallFile "../doc/manpages/backintime-config.5.gz" "/share/man/man5" addUninstallDir "/share/man" addNewline addComment "application" addInstallDir "/bin" addInstallFile "backintime" "/bin" "755" addInstallFile "backintime-askpass" "/bin" "755" addNewline addComment "autostart" addInstallDir "/../etc/xdg/autostart" addInstallFile "backintime.desktop" "/../etc/xdg/autostart" addUninstallDir "/../etc/xdg" addUninstallDir "/../etc" addNewline addComment "bash-completion" addInstallDir "/share/bash-completion/completions" addInstallFiles "bash-completion/*" "/share/bash-completion/completions" addSymlink "backintime" "/share/bash-completion/completions/backintime-qt" addUninstallDir "/share/bash-completion" addNewline # compress printf "compress:\n" >> ${MAKEFILE} printf "\t# Man pages\n" >> ${MAKEFILE} printf "\t@cd ./../doc/manpages && ./build_manpages.sh backintime.1.adoc\n" >> ${MAKEFILE} printf "\t@cd ./../doc/manpages && ./build_manpages.sh backintime-askpass.1.adoc\n" >> ${MAKEFILE} printf "\t@cd ./../doc/manpages && gzip --best --stdout backintime-config.5 > backintime-config.5.gz\n" >> ${MAKEFILE} printf "\t@echo \"Compressed backintime-config.5 into backintime-config.5.gz\"\n" >> ${MAKEFILE} printf "\t# Config-examples\n" >> ${MAKEFILE} printf "\tgzip -n --best -c config-example-local > config-example-local.gz\n" >> ${MAKEFILE} printf "\tgzip -n --best -c config-example-ssh > config-example-ssh.gz\n\n" >> ${MAKEFILE} # translate printf "translate:\t$mos\n\n" >> ${MAKEFILE} for lang in $langs; do printf "po/$lang.mo: po/$lang.po\n" >> ${MAKEFILE} printf "\tmsgfmt -o po/$lang.mo po/$lang.po\n\n" >> ${MAKEFILE} done # common langs printf "install_translations:\n" >> ${MAKEFILE} addComment "translations" for lang in $langs; do addInstallDir "/share/locale/$lang/LC_MESSAGES" addInstallFileRename "po/$lang.mo" "/share/locale/$lang/LC_MESSAGES/backintime.mo" addUninstallDir "/share/locale/$lang" done addUninstallDir "/share/locale" addUninstallDir "/share" addNewline # uninstall printf "uninstall:\tuninstall_files uninstall_dirs\n\n" >> ${MAKEFILE} printf "uninstall_files:\n" >> ${MAKEFILE} cat ${UNINSTALL_FILES} >> ${MAKEFILE} printf "uninstall_dirs:\n" >> ${MAKEFILE} cat ${UNINSTALL_DIRS} >> ${MAKEFILE} for target in test test-v unittest unittest-v; do printf "\n\n%s:\n" "$target" >> ${MAKEFILE} printf "\t@echo \"Target '%s' not available anymore. " "$target">> ${MAKEFILE} printf "Use a test runner of your own choice " >> ${MAKEFILE} printf "(e.g. 'unittest' or 'pytest').\"" >> ${MAKEFILE} printf "\n\t@false" >> ${MAKEFILE} done # Copy Makefile mv ${MAKEFILE} Makefile chmod 644 Makefile # Clean up for i in "${UNINSTALL_FILES}" "${UNINSTALL_DIRS}"; do if [ -e "$i" ]; then rm "$i" fi done # check python version PYTHON_VERSION_REQUIRED="3.9" PYTHON_VERSION_CURRENT=$(${PYTHON} --version | tr --delete 'Python ') # Credits: https://unix.stackexchange.com/a/285928/136851 if [ "$(printf '%s\n' "$PYTHON_VERSION_REQUIRED" "$PYTHON_VERSION_CURRENT" | sort -V | head -n1)" != "$PYTHON_VERSION_REQUIRED" ]; then printf "Error: Wrong Python version ${PYTHON_VERSION_CURRENT}. " printf "But minimal version ${PYTHON_VERSION_REQUIRED} required.\n" exit 1 fi printf "All OK. Now run:\n" printf " make\n" printf " sudo make install\n" backintime-1.6.1/common/daemon.py000066400000000000000000000174401514264426600167520ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2007 Sander Marechal # SPDX-FileCopyrightText: © 2016 Germar Reitze # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or # go to # and . """A generic daemon class. Original from: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python Copyright © 2007 Sander Marechal License CC0 or Public Domain Notes about the license (by buhtz, 2024-08-13): The linked blog article is licensed under CC BY-SA 3.0 which is not compatible with GPLv2 used by Back In Time. But the original author clarified that the code used in the blog article is public domain. See this original email. Date: Tue, 13 Aug 2024 14:19:48 +0200 Subject: Re: Your Daemon code in Back In Time Message-ID: <06084b4b-2293-4a28-a290-96fa4d309a8b@email.android.com> In-Reply-To: <3d57067b590e271ce6f361ce4147ac08@posteo.de> From: Sander Marechal To: c.buhtz@posteo.jp Hello Christian, As far as I am concerned that daemon code is public domain. You can use it under any license you want. There are only a few ways to start a daemon so technically the code can't be copyrighted as far as I am concerned. That CC license is just for my articles in general. Kind regards, -- Sander Marechal """ import sys import os import io import signal import atexit import errno from time import sleep import logger from applicationinstance import ApplicationInstance def _duplicate_fd(old_fd: str, new_fd: io.TextIOWrapper, mode: str = 'w' ) -> None: """Duplicate a file descriptor and close it after. Used to redirect stdin, stdout and stderr from daemonized threads. Args: old_fd: Path to the old file (e.g. /dev/stdout). new_fd (_io.TextIOWrapper): File object for the new file. mode (str): Mode in which the old file should be opened. """ try: # pylint: disable-next=unspecified-encoding with open(file=old_fd, mode=mode, encoding=None) as fd: os.dup2(fd.fileno(), new_fd.fileno()) except OSError as exc: logger.error(f'Failed to redirect {old_fd}: {exc}') class Daemon: """A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, # pylint: disable=R0913,R0917 pidfile=None, stdin='/dev/null', stdout='/dev/stdout', stderr='/dev/null', umask=0o022): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile self.umask = umask if pidfile: self.app_instance = ApplicationInstance( pidfile, autoExit=False, flock=False) def daemonize(self): """Converts the current process into a daemon. It is a process running in the background, sending a SIGTERM signal to the current process. This is done via the UNIX double-fork magic, see Stevens' 'Advanced Programming in the UNIX Environment' for details (ISBN 0201563177) and this explanation: https://stackoverflow.com/a/6011298 """ try: pid = os.fork() logger.debug(f'first fork pid: {pid}', self) if pid > 0: # exit first parent sys.exit(0) except OSError as exc: logger.error(f'fork #1 failed: {exc.errno} ({exc})', self) sys.exit(1) # Decouple from parent environment # logger.debug('decouple from parent environment', self) os.chdir('/') os.setsid() os.umask(self.umask) # Do second fork try: pid = os.fork() logger.debug(f'second fork pid: {pid}', self) if pid > 0: # exit from second parent sys.exit(0) except OSError as exc: logger.error(f'fork #2 failed: {exc.errno} ({exc})', self) sys.exit(1) # redirect standard file descriptors # logger.debug('redirect standard file descriptors', self) sys.stdout.flush() sys.stderr.flush() _duplicate_fd(self.stdin, sys.stdin, 'r') _duplicate_fd(self.stdout, sys.stdout, 'w') _duplicate_fd(self.stderr, sys.stderr, 'w') signal.signal(signal.SIGTERM, self.cleanup_handler) if self.pidfile: atexit.register(self.app_instance.exitApplication) # write pidfile # logger.debug('write pidfile', self) self.app_instance.startApplication() def cleanup_handler(self, _signum, _frame): """Handle process termination.""" if self.pidfile: self.app_instance.exitApplication() sys.exit(0) def start(self): """Start the daemon.""" # Check for a pidfile to see if the daemon already runs if self.pidfile and not self.app_instance.check(): logger.error(f'pidfile {self.pidfile} already exists. ' 'Daemon already running?', self) sys.exit(1) # Start the daemon self.daemonize() self.run() def stop(self): """Stop the daemon.""" if not self.pidfile: logger.warning( 'Unattended daemon can not be stopped. No PID file.', self) return # Get the pid from the pidfile pid = self.app_instance.readPidFile()[0] if not pid: logger.error( f'pidfile {self.pidfile} does not exist. Daemon not running?', self) return # not an error in a restart # Try killing the daemon process try: while True: # <-- Why? os.kill(pid, signal.SIGTERM) sleep(0.1) except OSError as err: if err.errno == errno.ESRCH: # No such process self.app_instance.exitApplication() else: logger.error(f'Unable to stop process with pid {pid}: {err}', self) sys.exit(1) def restart(self): """Restart the daemon.""" self.stop() self.start() def reload(self): """Send SIGHUP signal to process.""" if not self.pidfile: logger.warning( "Unattended daemon can't be reloaded. No PID file", self) return # Get the pid from the pidfile pid = self.app_instance.readPidFile()[0] if not pid: logger.error(f'pidfile {self.pidfile} does not exist. ' 'Daemon not running?', self) return # Try killing the daemon process try: os.kill(pid, signal.SIGHUP) except OSError as err: if err.errno == errno.ESRCH: # no such process self.app_instance.exitApplication() else: sys.stderr.write(str(err)) sys.exit(1) def status(self): """Return status.""" if not self.pidfile: logger.warning( "Unattended daemon can't be checked. No PID file", self) return False return not self.app_instance.check() def run(self): """Override this method when subclass ``Daemon``. It will be called after the process has been daemonized by ``start()`` or ``restart()``. """ backintime-1.6.1/common/diagnostics.py000066400000000000000000000330261514264426600200140ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2022 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Provides the ability to collect diagnostic information on Back In Time. These are version numbers of the dependent tools, environment variables, paths, operating system and the like. This is used to enhance error reports and to enrich them with the necessary information as uncomplicated as possible. """ import sys import os import itertools from pathlib import Path import pwd import platform import locale import subprocess import json import re import config import tools import version def collect_minimal_diagnostics(): """Collect minimal information about backintime and the operating system. Returns: dict: A nested dictionary. """ return { 'backintime': { 'name': config.Config.APP_NAME, 'version': version.__version__, 'running-as-root': pwd.getpwuid(os.getuid()).pw_name == 'root', }, 'host-setup': { 'OS': _get_os_release() } } def collect_diagnostics(): """Collect information about environment, versions of tools and packages used by Back In Time. The information can be used e.g. for debugging and bug reports. Returns: dict: A nested dictionary. """ result = collect_minimal_diagnostics() # === BACK IN TIME === # work-around: Instantiate to get the user-callback folder # (should be singleton) cfg = config.Config() result['backintime'].update({ 'latest-config-version': config.Config.CONFIG_VERSION, 'local-config-file': cfg._LOCAL_CONFIG_PATH, 'local-config-file-found': Path(cfg._LOCAL_CONFIG_PATH).exists(), 'global-config-file': cfg._GLOBAL_CONFIG_PATH, 'global-config-file-found': Path(cfg._GLOBAL_CONFIG_PATH).exists(), # 'distribution-package': str(distro_path), 'started-from': str(Path(config.__file__).parent), 'user-callback': cfg.takeSnapshotUserCallback(), 'keyring-supported': tools.keyringSupported() }) # Git repo bit_root_path = Path(tools.as_backintime_path("")) git_info = tools.get_git_repository_info(bit_root_path) if git_info: result['backintime']['git-project-root'] = str(bit_root_path) for key in git_info: result['backintime'][f'git-{key}'] = git_info[key] # == HOST setup === result['host-setup'].update({ # Kernel & Architecture 'platform': platform.platform(), # OS Version (and maybe name) 'system': f'{platform.system()} {platform.version()}' }) # Display system (X11 or Wayland), desktop, etc # $XDG_SESSION_TYPE doesn't catch all edge cases. # See: https://unix.stackexchange.com/q/202891/136851 for var in ['XDG_SESSION_TYPE', 'XDG_CURRENT_DESKTOP', 'DESKTOP_SESSION']: result['host-setup'][var] = os.environ.get(var, '(not set)') # locale (system language etc) # # Implementation note: With env var "LC_ALL=C" getlocale() will return # (None, None). # This throws an error in "join()": # TypeError: sequence item 0: expected str instance, NoneType found my_locale = locale.getlocale() if all(x is None for x in my_locale): my_locale = ["(Unknown)"] result['host-setup']['locale'] = ', '.join(my_locale) # PATH environment variable result['host-setup']['PATH'] = os.environ.get('PATH', '($PATH unknown)') # === PYTHON setup === python = ' '.join(( platform.python_version(), ' '.join(platform.python_build()), platform.python_implementation(), platform.python_compiler() )) # Python branch and revision if available branch = platform.python_branch() if branch: python = f'{python} branch: {branch}' rev = platform.python_revision() if rev: python = f'{python} rev: {rev}' python_executable = Path(sys.executable) # Python interpreter result['python-setup'] = { 'python': python, 'python-executable': str(python_executable), 'python-executable-symlink': python_executable.is_symlink(), } # Real interpreter path if it is used via a symlink if result['python-setup']['python-executable-symlink']: result['python-setup']['python-executable-resolved'] \ = str(python_executable.resolve()) result['python-setup']['sys.path'] = sys.path result['python-setup']['qt'] = _get_qt_information() # === EXTERN TOOL === result['external-programs'] = {} # RSYNC environment variables for var in ['RSYNC_OLD_ARGS', 'RSYNC_PROTECT_ARGS']: result['external-programs'][var] = os.environ.get( var, '(not set)') result['external-programs']['rsync'] = _get_rsync_info() # ssh result['external-programs']['ssh'] = _get_extern_versions(['ssh', '-V']) # sshfs result['external-programs']['sshfs'] \ = _get_extern_versions(['sshfs', '-V'], r'SSHFS version (.*)\n') # EncFS # Using "[Vv]" in the pattern because encfs does translate its output. # e.g. In German it is "Version" in English "version". result['external-programs']['encfs'] \ = _get_extern_versions(['encfs'], r'Build: encfs [Vv]ersion (.*)\n') # Shell SHELL_ERR_MSG = '($SHELL not exists)' shell = os.environ.get('SHELL', SHELL_ERR_MSG) result['external-programs']['shell'] = shell if shell != SHELL_ERR_MSG: shell_version = _get_extern_versions([shell, '--version']) result['external-programs']['shell-version'] \ = shell_version.split('\n')[0] result = _replace_username_paths( result=result, username=pwd.getpwuid(os.getuid()).pw_name ) return result def _get_qt_information(): """Collect Version and Theme information from Qt. If environment variable ``DISPLAY`` is set a temporary QApplication instances is created. """ # pylint: disable=import-outside-toplevel try: import PyQt6.QtCore import PyQt6.QtGui import PyQt6.QtWidgets except ImportError: return '(Cannot import PyQt6)' # Themes theme_info = {} if tools.checkXServer(): # TODO use tools.is_Qt_working() when stable qapp = PyQt6.QtWidgets.QApplication.instance() if not qapp: qapp = PyQt6.QtWidgets.QApplication([]) clean_up_myself = True else: clean_up_myself = False theme_info = { 'Theme': PyQt6.QtGui.QIcon.themeName(), 'Theme Search Paths': PyQt6.QtGui.QIcon.themeSearchPaths(), 'Fallback Theme': PyQt6.QtGui.QIcon.fallbackThemeName(), 'Fallback Search Paths': PyQt6.QtGui.QIcon.fallbackSearchPaths() } if clean_up_myself: qapp.quit() del qapp return { 'Version': f'PyQt {PyQt6.QtCore.PYQT_VERSION_STR} ' f'/ Qt {PyQt6.QtCore.QT_VERSION_STR}', **theme_info } def _get_extern_versions(cmd, pattern=None, try_json=False, error_pattern=None): """Get the version of an external tools using :class:`subprocess.Popen`. Args: cmd (list[str]): Commandline arguments that will be passed to ``Popen()``. pattern (str) : A regex pattern to extract the version string from the commands output. try_json (bool): Interpret the output as json first (default: ``False``). If it could be parsed the result is a dict error_pattern (str): Regex pattern to identify a message in the output that indicates an error. Returns: Version information as :obj:`str` or :obj:`dict`. The latter is used if the ``cmd`` requested offer its information in JSON format. ``None`` if the error_pattern did match (to indicate an error). """ try: # as context manager to prevent ResourceWarning's with subprocess.Popen(cmd, env={'LC_ALL': 'C'}, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) as proc: error_output = proc.stderr.read() std_output = proc.stdout.read() except FileNotFoundError: result = f'(no {cmd[0]})' else: # Check for errors if error_pattern: match_result = re.findall(error_pattern, error_output) if match_result: return None # some tools use "stderr" for version info result = std_output if std_output else error_output # Expect JSON string if try_json: try: result = json.loads(result) except json.decoder.JSONDecodeError: # Wasn't a json. Try regex in the next block. pass else: return result # as JSON # extract version string if pattern: result = re.findall(pattern, result)[0] return result.strip() # as string def _get_rsync_info(): """Collect infos about rsync. Returns: dict: Collected info """ # rsync # rsync >= 3.2.7: -VV return a json # rsync <= 3.2.6 and > (somewhere near) 3.1.3: -VV return the same as -V # rsync <= (somewhere near) 3.1.3: -VV doesn't exists # rsync == 3.1.3 (Ubuntu 20 LTS) doesn't even know '-V' # This works when rsync understands -VV and returns json or human readable info = _get_extern_versions( ['rsync', '-VV'], r'rsync version (.*) protocol version', try_json=True, error_pattern=r'unknown option' ) # When -VV was unknown use -V and parse the human readable output if not info: # try the old way info = _get_extern_versions( ['rsync', '--version'], r'rsync version (.*) protocol version' ) elif isinstance(info, dict): # Rsync (>= 3.2.7) provide its information in JSON format. # Remove some irrelevant information. for key in ['program', 'copyright', 'url', 'license', 'caveat']: try: del info[key] except KeyError: pass # Reduce use of vertical space with transforming lists and dicts into # strings. for key in ['daemon_auth_list', 'compress_list', 'checksum_list', 'optimizations', 'capabilities']: if isinstance(info[key], list): info[key] = ', '.join(info[key]) elif isinstance(info[key], dict): info[key] = '; '.join( f'{k}: {v}' for k, v in info[key].items()) return info def _get_os_release(): """Try to get the name and version of the operating system used. First it extract infos from the file ``/etc/os-release``. Because not all GNU/Linux distributions follow the standards it will also look for alternative release files (pattern: ``/etc/*release``). See http://linuxmafia.com/faq/Admin/release-files.html for examples. Returns: A string with the name of the operating system, e.g. "Debian GNU/Linux 11 (bullseye)" or a dictionary if alternative release files where found. """ def _get_pretty_name_or_content(fp): """Return value of PRETTY_NAME from a release file or return the whole file content.""" # Read content from file try: with fp.open('r') as handle: content = handle.read() except FileNotFoundError: return f'({fp.name} file not found)' # Try to extract the pretty name try: return re.findall('PRETTY_NAME=\"(.*)\"', content)[0] except IndexError: # Return full content when no PRETTY_NAME was found return content etc_path = Path('/etc') os_files = list(filter(lambda p: p.is_file(), itertools.chain( etc_path.glob('*release*'), etc_path.glob('*version*')) )) # "os-release" is standard and should be on top of the list fp_osrelease = etc_path / 'os-release' try: os_files.remove(fp_osrelease) except ValueError: pass else: os_files = [fp_osrelease] + os_files # each release/version file found osrelease = {str(fp): _get_pretty_name_or_content(fp) for fp in os_files} # No alternative release files found if len(osrelease) == 1: return osrelease[str(fp_osrelease)] return osrelease def _replace_username_paths(result, username): """User's real ``HOME`` path and login name are replaced with surrogtes. This is because of security reasons. Args: result (dict): Dict possibly containing the username and its home path. username (str): The user's real login name to look for. Returns: A dictionary with replacements. """ # Replace home folder user names with this dummy name # for privacy reasons USER_REPLACED = 'UsernameReplaced' # JSON to string result = json.dumps(result) result = result.replace(f'/home/{username}', f'/home/{USER_REPLACED}') result = result.replace(f'~/{username}', f'~/{USER_REPLACED}') # string to JSON return json.loads(result) backintime-1.6.1/common/doc-dev/000077500000000000000000000000001514264426600164505ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/Makefile000066400000000000000000000152601514264426600201140ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BackInTime.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BackInTime.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/BackInTime" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BackInTime" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." htmlOpen: html xdg-open $(BUILDDIR)/html/index.html backintime-1.6.1/common/doc-dev/REUSE.toml000066400000000000000000000012401514264426600202250ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Back In Time Team # # SPDX-License-Identifier: CC0-1.0 # # This file is released under Creative Commons Zero 1.0 (CC0-1.0) and part of # the program "Back In Time". The program as a whole is released under GNU # General Public License v2 or any later version (GPL-2.0-or-later). # See LICENSES directory or go to # and . # See https://reuse.software/faq/#bulk-license version = 1 [[annotations]] path = [ "**/*.rst", "Makefile", "conf.py" ] SPDX-License-Identifier = "GPL-2.0-or-later" SPDX-FileCopyrightText = "© 2022 Back In Time" backintime-1.6.1/common/doc-dev/_static/000077500000000000000000000000001514264426600200765ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/_static/.dummy000066400000000000000000000000001514264426600212200ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/_templates/000077500000000000000000000000001514264426600206055ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/_templates/.dummy000066400000000000000000000000001514264426600217270ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/applicationinstance.rst000066400000000000000000000002241514264426600232300ustar00rootroot00000000000000applicationinstance module ========================== .. automodule:: applicationinstance :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/askpass.rst000066400000000000000000000001601514264426600206440ustar00rootroot00000000000000askpass module ============== .. automodule:: askpass :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/backintime.rst000066400000000000000000000001711514264426600213070ustar00rootroot00000000000000backintime module ================= .. automodule:: backintime :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/bcolors.rst000066400000000000000000000001601514264426600206420ustar00rootroot00000000000000bcolors module ============== .. automodule:: bcolors :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/cli.rst000066400000000000000000000001441514264426600177500ustar00rootroot00000000000000cli module ========== .. automodule:: cli :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/conf.py000066400000000000000000000101671514264426600177540ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath(os.path.join(os.pardir))) sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, "plugins"))) # -- General configuration ------------------------------------------------ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx_rtd_theme' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = 'BackInTime' copyright = '2016, Germar Reitze' author = 'Germar Reitze' # Don't edit this variable. It is updated automatically by "updateversion.sh". import version as version_module version = version_module.__version__ # The full version, including alpha/beta/rc tags. release = version # '1.3.3-dev' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' autodoc_default_options = { 'members': True, 'member-order': 'bysource', 'private-members': True, 'undoc-members': True, 'special-members': True, 'exclude-members': '__weakref__,__dict__,__module__,__annotations__', } # -- Intersphinx options -------------------------------------------------- intersphinx_mapping = { 'python': ('https://docs.python.org/3/', None), # PyQt is not mappable because of a known issue. See # https://riverbankcomputing.com/pipermail/pyqt/2013-March/032528.html } # -- Napoleon include private members which have docstrings --------------- napoleon_include_private_with_doc = True # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'classic' html_theme = 'sphinx_rtd_theme' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y, %H:%M (%Z)' # Output file base name for HTML help builder. htmlhelp_basename = 'BackInTimeDevDoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'BackInTime.tex', 'Back In Time Development Documentation', 'Germar Reitze', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'backintime', 'Back In Time Development Documentation', ['Germar Reitze'], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'BackInTime', 'Back In Time Development Documentation', 'Germar Reitze', 'BackInTime', 'One line description of project.', 'Miscellaneous'), ] backintime-1.6.1/common/doc-dev/config.rst000066400000000000000000000001551514264426600204500ustar00rootroot00000000000000config module ============= .. automodule:: config :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/configfile.rst000066400000000000000000000001711514264426600213060ustar00rootroot00000000000000configfile module ================= .. automodule:: configfile :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/diagnostics.rst000066400000000000000000000001741514264426600215130ustar00rootroot00000000000000diagnostics module ================== .. automodule:: diagnostics :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/encfstools.rst000066400000000000000000000001711514264426600213600ustar00rootroot00000000000000encfstools module ================= .. automodule:: encfstools :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/exceptions.rst000066400000000000000000000001711514264426600213620ustar00rootroot00000000000000exceptions module ================= .. automodule:: exceptions :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/flock.rst000066400000000000000000000001521514264426600202760ustar00rootroot00000000000000flock module ============ .. automodule:: flock :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/guiapplicationinstance.rst000066400000000000000000000002351514264426600237370ustar00rootroot00000000000000guiapplicationinstance module ============================= .. automodule:: guiapplicationinstance :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/index.rst000066400000000000000000000007351514264426600203160ustar00rootroot00000000000000.. BackInTime documentation master file, created by sphinx-quickstart on Sat Jan 9 00:04:35 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to Back In Time's documentation ======================================= Contents: .. toctree:: :maxdepth: 2 modules.rst plugins/modules.rst Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` backintime-1.6.1/common/doc-dev/logger.rst000066400000000000000000000001551514264426600204620ustar00rootroot00000000000000logger module ============= .. automodule:: logger :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/modules.rst000066400000000000000000000005551514264426600206570ustar00rootroot00000000000000common ====== .. toctree:: :maxdepth: 4 applicationinstance askpass backintime bcolors cli config configfile diagnostics encfstools exceptions flock guiapplicationinstance logger mount password password_ipc pluginmanager progress schedule snapshotlog snapshots ssh_max_arg sshtools tools backintime-1.6.1/common/doc-dev/mount.rst000066400000000000000000000001521514264426600203420ustar00rootroot00000000000000mount module ============ .. automodule:: mount :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/password.rst000066400000000000000000000001631514264426600210440ustar00rootroot00000000000000password module =============== .. automodule:: password :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/password_ipc.rst000066400000000000000000000001771514264426600217040ustar00rootroot00000000000000password_ipc module =================== .. automodule:: password_ipc :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/pluginmanager.rst000066400000000000000000000002021514264426600220250ustar00rootroot00000000000000pluginmanager module ==================== .. automodule:: pluginmanager :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/plugins/000077500000000000000000000000001514264426600201315ustar00rootroot00000000000000backintime-1.6.1/common/doc-dev/plugins/modules.rst000066400000000000000000000001051514264426600223270ustar00rootroot00000000000000plugins ======= .. toctree:: :maxdepth: 4 usercallbackplugin backintime-1.6.1/common/doc-dev/plugins/usercallbackplugin.rst000066400000000000000000000002211514264426600245300ustar00rootroot00000000000000usercallbackplugin module ========================= .. automodule:: usercallbackplugin :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/progress.rst000066400000000000000000000001631514264426600210460ustar00rootroot00000000000000progress module =============== .. automodule:: progress :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/schedule.rst000066400000000000000000000001631514264426600207760ustar00rootroot00000000000000schedule module =============== .. automodule:: schedule :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/snapshotlog.rst000066400000000000000000000001741514264426600215450ustar00rootroot00000000000000snapshotlog module ================== .. automodule:: snapshotlog :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/snapshots.rst000066400000000000000000000001661514264426600212270ustar00rootroot00000000000000snapshots module ================ .. automodule:: snapshots :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/ssh_max_arg.rst000066400000000000000000000001741514264426600214770ustar00rootroot00000000000000ssh_max_arg module ================== .. automodule:: ssh_max_arg :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/sshtools.rst000066400000000000000000000001631514264426600210600ustar00rootroot00000000000000sshtools module =============== .. automodule:: sshtools :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/doc-dev/tools.rst000066400000000000000000000001521514264426600203400ustar00rootroot00000000000000tools module ============ .. automodule:: tools :members: :undoc-members: :show-inheritance: backintime-1.6.1/common/encfstools.py000066400000000000000000000734011514264426600176650ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # SPDX-FileCopyrightText: © 2012-2022 Taylor Raack # SPDX-FileCopyrightText: © 2025 David Wales (@daviewales) # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import subprocess import re import shutil import tempfile from datetime import datetime from packaging.version import Version import config import encode import password from password_ipc import TempPasswordThread import tools import sshtools import logger from mount import MountControl from exceptions import MountException, EncodeValueError class EncFS_mount(MountControl): """Mount encrypted paths with encfs.""" def __init__(self, *args, **kwargs): # logger.debug("EncFS_mount.init() :: {args=} {kwargs=}") # DEBUG # init MountControl super(EncFS_mount, self).__init__(*args, **kwargs) # Workaround for some linters. self.path = None self.reverse = None self.config_path = None self.setattrKwargs( 'path', self.config.localEncfsPath(self.profile_id), **kwargs) # logger.debug("EncFS_mount.init() :: {self.path=}") # DEBUG self.setattrKwargs('reverse', False, **kwargs) self.setattrKwargs('config_path', None, **kwargs) self.setattrKwargs('password', None, store=False, **kwargs) self.setattrKwargs('hash_id_1', None, **kwargs) self.setattrKwargs('hash_id_2', None, **kwargs) self.setDefaultArgs() # pylint: disable=duplicate-code self.mountproc = 'encfs' self.log_command = '%s: %s' % (self.mode, self.path) self.symlink_subfolder = None def _mount(self): """ mount the service """ if self.password is None: self.password = self.config.password( self.parent, self.profile_id, self.mode) # Dev note (2026-01, buhtz): # Password flow overview: # # 1. Back In Time creates a TempPasswordThread and passes the password # to it. # 2. The thread creates a temporary FIFO and blocks while writing the # password to it, waiting for a reader. # 3. Back In Time starts encfs with "--extpass=backintime-askpass". # 4. The FIFO path is passed via the environment variable ASKPASS_TEMP. # 5. encfs invokes backintime-askpass as an external password helper. # 6. backintime-askpass reads the FIFO path from ASKPASS_TEMP, opens # the FIFO, reads the password, and writes it to stdout. # 7. encfs reads the password from backintime-askpass's stdout. # 8. After the read completes, the FIFO is removed and the thread # exits. # # Result: # The password is transferred exactly once, synchronously, via a FIFO, # without appearing on the command line, in files, or in the process # list. # # Reason: # It is about security. It minimizes password lifetime and exposure. # Password never appears in a shell context, is transffered only once. # Prepare the password-fifo-thread thread = TempPasswordThread(self.password) env = self.env() env['ASKPASS_TEMP'] = thread.temp_file # Start thread and write password to FIFO with thread.starter(): # build encfs command and provide "backintime-askpass" as # password helper encfs = [self.mountproc, '--extpass=backintime-askpass'] if self.reverse: encfs += ['--reverse'] if not self.isConfigured(): encfs += ['--standard'] encfs += [self.path, self.currentMountpoint] logger.debug('Call mount command: ' + ' '.join(encfs), self) # Encfs ask backintime-askpass for the password. # backintime-askpass will read the password from FIFO and provide # it via return on stdout to the encfs process proc = subprocess.Popen( encfs, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True ) output = proc.communicate()[0] self.backupConfig() if proc.returncode: msg = _('Unable to mount "{command}"').format( command=' '.join(encfs) ) raise MountException( f'{msg}:\n\n{output}\n\nReturn code: {proc.returncode}' ) def init_backend(self): """Empty for Encfs because initialization happens implicit. Init happens in mount() via "--standard" switch on encfs if self.isConfigured() is False. """ return def preMountCheck(self, first_run=False): """Check what ever conditions must be given for the mount. Raises: Several exceptions. """ self.checkFuse() if first_run: self.checkVersion() return True def env(self): """ return environment with encfs configfile """ env = os.environ.copy() cfg = self.configFile() if os.path.isfile(cfg): env['ENCFS6_CONFIG'] = cfg return env def configFile(self): """ return encfs config file """ f = '.encfs6.xml' # pylint: disable=duplicate-code if self.config_path is None: cfg = os.path.join(self.path, f) else: cfg = os.path.join(self.config_path, f) return cfg def isConfigured(self): """ check if encfs config file exist. If not and if we are in settingsdialog ask for password confirmation. _mount will then create a new config """ cfg = self.configFile() if os.path.isfile(cfg): logger.debug(f'Found EncFS config in {cfg}', self) return True logger.debug(f'No EncFS config in {cfg}', self) msg = _('Configuration for the encrypted directory not found.') if not self.tmp_mount: raise MountException(msg) question = '{}\n{}'.format( msg, _('Create a new encrypted directory?') ) if not self.config.askQuestion(question): # TODO # This string can appear in a "critical" message dialog. # Let us know the steps to reproduce that behavior. raise MountException(_('Cancel')) pw = password.Password(self.config) password_confirm = pw.passwordFromUser( self.parent, prompt=_('Please re-enter the EncFS password to confirm.')) if self.password == password_confirm: return False raise MountException( _('The EncFS passwords do not match.')) def checkVersion(self): """Check encfs version. 1.7.2 had a bug with --reverse that will create corrupt files Dev note (buhtz, 2025-06): EncFS itself is scheduled for removal. Dev note (buhtz, 2024-05): Looking at upstream it seems that the 1.7.2 release was widthdrawn. The release before and after are from the year 2010. In consequence this code is definitely out dated and a candidate for removal. """ logger.debug('Check version', self) if self.reverse: proc = subprocess.Popen( [ 'encfs', '--version' ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True ) output = proc.communicate()[0] m = re.search(r'(\d\.\d\.\d)', output) if m and Version(m.group(1)) <= Version('1.7.2'): logger.debug('Wrong encfs version %s' % m.group(1), self) raise MountException( 'encfs version 1.7.2 and before has a bug with ' 'option --reverse. Please update encfs.') def backupConfig(self): """Create a backup of encfs config file into local config folder. In cases of the config file get deleted or corrupt user can restore it from there. """ cfg = self.configFile() if not os.path.isfile(cfg): logger.warning( f'No encfs config in {cfg}. Skip backup of config file.', self ) return backup_folder = self.config.encfsconfigBackupFolder(self.profile_id) tools.makeDirs(backup_folder) old_backups = os.listdir(backup_folder) old_backups.sort(reverse=True) if len(old_backups): last_backup = os.path.join(backup_folder, old_backups[0]) # Don't create a new backup if config hasn't changed if tools.md5sum(cfg) == \ tools.md5sum(last_backup): logger.debug('Encfs config did not change. Skip backup', self) return new_backup_file = '.'.join(( os.path.basename(cfg), datetime.now().strftime('%Y%m%d%H%M') )) new_backup = os.path.join(backup_folder, new_backup_file) logger.debug( f'Create backup of encfs config {cfg} to {new_backup}', self ) shutil.copy2(cfg, new_backup) class EncFS_SSH(EncFS_mount): """ Mount encrypted remote path with sshfs and encfs. Mount / with encfs --reverse. rsync will then sync the encrypted view on / to the remote path """ def __init__( self, cfg=None, profile_id=None, mode=None, parent=None, *args, **kwargs ): self.config = cfg or config.Config() self.profile_id = profile_id or self.config.currentProfile() self.mode = mode if self.mode is None: self.mode = self.config.snapshotsMode(self.profile_id) self.parent = parent self.args = args self.kwargs = kwargs self.ssh = sshtools.SSH( *self.args, symlink=False, **self.splitKwargs('ssh') ) self.rev_root = EncFS_mount( *self.args, symlink=False, **self.splitKwargs('encfs_reverse') ) super(EncFS_SSH, self).__init__(*self.args, **self.splitKwargs('encfs')) def mount(self, *args, **kwargs): """ call mount for sshfs, encfs --reverse and encfs register 'encfsctl encode' in config.ENCODE """ logger.debug('Mount sshfs', self) self.ssh.mount(*args, **kwargs) # mount fsroot with encfs --reverse first. # If the config does not exist already this will make sure # the new created config works with --reverse if not os.path.isfile(self.configFile()): # encfs >= 1.8.0 changed behavior when ENCFS6_CONFIG environ # variable file does not exist. It will not create a new one # anymore but just fail. As encfs would create the config in # /.encfs6.xml (which will most likely fail) we need to mount a # temp folder with reverse first and copy the config when done. # logger.debug( # 'Mount temp directory with encfs --reverse to create a new ' # 'encfs config', # self # ) with tempfile.TemporaryDirectory() as src: tmp_kwargs = self.splitKwargs('encfs_reverse') tmp_kwargs['path'] = src tmp_kwargs['config_path'] = src tmp_mount = EncFS_mount( *self.args, symlink=False, **tmp_kwargs) tmp_mount.mount(*args, **kwargs) tmp_mount.umount() cfg = tmp_mount.configFile() if os.path.isfile(cfg): logger.debug( f'Copy new encfs config {cfg} to its original place ' f'{self.ssh.currentMountpoint}', self ) shutil.copy2(cfg, self.ssh.currentMountpoint) else: logger.error(f'New encfs config {cfg} not found', self) # logger.debug('Mount local filesystem root with encfs --reverse', self) self.rev_root.mount(*args, **kwargs) # logger.debug('Mount encfs', self) kwargs['check'] = False ret = super(EncFS_SSH, self).mount(*args, **kwargs) self.config.ENCODE = Encode(self) return ret def umount(self, *args, **kwargs): """Close 'encfsctl encode' process and set config.ENCODE back to the dummy class. Call umount for encfs, encfs --reverse and sshfs """ self.config.ENCODE.close() self.config.ENCODE = encode.Bounce() # logger.debug('Unmount encfs', self) super(EncFS_SSH, self).umount(*args, **kwargs) # logger.debug('Unmount local filesystem root mount encfs --reverse', self) self.rev_root.umount(*args, **kwargs) # logger.debug('Unmount sshfs', self) self.ssh.umount(*args, **kwargs) def preMountCheck(self, *args, **kwargs): """Call preMountCheck for sshfs, encfs --reverse and encfs. """ if (self.ssh.preMountCheck(*args, **kwargs) and self.rev_root.preMountCheck(*args, **kwargs) and super(EncFS_SSH, self).preMountCheck(*args, **kwargs)): # Dev note (buhtz, 2024-09): Seems unnecessary. No one checks this # return value. return True def splitKwargs(self, mode): """ split all given arguments for the desired mount class """ d = self.kwargs.copy() d['cfg'] = self.config d['profile_id'] = self.profile_id d['mode'] = self.mode d['parent'] = self.parent if mode == 'ssh': if 'path' in d: d.pop('path') if 'ssh_path' in d: d['path'] = d.pop('ssh_path') if 'ssh_password' in d: d['password'] = d.pop('ssh_password') else: d['password'] = self.config.password( parent=self.parent, profile_id=self.profile_id, mode=self.mode ) if 'hash_id' in d: d.pop('hash_id') if 'hash_id_2' in d: d['hash_id'] = d['hash_id_2'] return d elif mode == 'encfs': d['path'] = self.ssh.currentMountpoint d['hash_id_1'] = self.rev_root.hash_id d['hash_id_2'] = self.ssh.hash_id if 'encfs_password' in d: d['password'] = d.pop('encfs_password') else: d['password'] = self.config.password( parent=self.parent, profile_id=self.profile_id, mode=self.mode, pw_id=2 ) return d elif mode == 'encfs_reverse': d['reverse'] = True d['path'] = '/' d['config_path'] = self.ssh.currentMountpoint if 'encfs_password' in d: d['password'] = d.pop('encfs_password') else: d['password'] = self.config.password( parent=self.parent, profile_id=self.profile_id, mode=self.mode, pw_id=2 ) if 'hash_id' in d: d.pop('hash_id') if 'hash_id_1' in d: d['hash_id'] = d['hash_id_1'] return d class Encode: """ encode path with encfsctl. ENCFS_SSH will replace config.ENCODE with this """ def __init__(self, encfs): self.encfs = encfs self.password = self.encfs.password self.chroot = self.encfs.rev_root.currentMountpoint if not self.chroot[-1] == os.sep: self.chroot += os.sep self.remote_path = self.encfs.ssh.path if not self.remote_path[-1] == os.sep: self.remote_path += os.sep # Precompile some regular expressions self.re_asterisk = re.compile(r'\*') self.re_separate_asterisk = re.compile(r'(.*?)(\*+)(.*)') def __del__(self): self.close() def startProcess(self): """ start 'encfsctl encode' process in pipe mode. """ thread = TempPasswordThread(self.password) env = self.encfs.env() env['ASKPASS_TEMP'] = thread.temp_file with thread.starter(): encfsctl = ['encfsctl', 'encode', '--extpass=backintime-askpass', '/'] logger.debug(f'Call command: {encfsctl}', self) self.p = subprocess.Popen( encfsctl, env=env, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True ) def path(self, path): """ write plain path to encfsctl stdin and read encrypted path from stdout """ if not 'p' in vars(self): self.startProcess() if not self.p.returncode is None: logger.warning( "'encfsctl encode' process terminated. Restarting.", self ) del self.p self.startProcess() self.p.stdin.write(path + '\n') ret = self.p.stdout.readline().strip('\n') if not len(ret) and len(path): logger.debug(f'Failed to encode {path}. Got empty string', self) raise EncodeValueError() return ret def exclude(self, path): """ encrypt paths for snapshots.takeSnapshot exclude list. After encoding the path a wildcard would not match anymore so all paths with wildcards are ignored. Only single and double asterisk that will match a full file or folder name will work. """ if tools.patternHasNotEncryptableWildcard(path): return None enc = '' m = self.re_asterisk.search(path) if not m is None: path_ = path[:] while True: # Search for foo/*, foo/*/bar, */bar or **/bar # but not foo* or foo/*bar m = self.re_separate_asterisk.search(path_) if m is None: return None if m.group(1): if not m.group(1).endswith(os.sep): return None enc = os.path.join(enc, self.path(m.group(1))) enc = os.path.join(enc, m.group(2)) if m.group(3): if not m.group(3).startswith(os.sep): return None m1 = self.re_asterisk.search(m.group(3)) if m1 is None: enc = os.path.join(enc, self.path(m.group(3))) break else: path_ = m.group(3) continue else: break else: enc = self.path(path) if os.path.isabs(path): return os.path.join(os.sep, enc) return enc def include(self, path): """ encrypt paths for snapshots.takeSnapshot include list. """ return os.path.join(os.sep, self.path(path)) def remote(self, path): """ encode the path on remote host starting from backintime/host/user/... """ enc_path = self.path(path[len(self.remote_path):]) return os.path.join(self.remote_path, enc_path) def close(self): """ stop encfsctl process """ if 'p' in vars(self) and self.p.returncode is None: logger.debug("stop 'encfsctl encode' process", self) self.p.communicate() class Decode: """ decode path with encfsctl. """ def __init__(self, cfg, string=True): self.config = cfg self.mode = cfg.snapshotsMode() if self.mode == 'local_encfs': self.password = cfg.password(pw_id=1) elif self.mode == 'ssh_encfs': self.password = cfg.password(pw_id=2) self.encfs = cfg.SNAPSHOT_MODES[self.mode][0](cfg) self.remote_path = cfg.sshSnapshotsPath() if not self.remote_path: self.remote_path = './' if not self.remote_path[-1] == os.sep: self.remote_path += os.sep # German translation changed from Snapshot to Schnappschuss. # Catch both variants otherwise old logs wouldn't get decoded. # Warning (2023-11): Do not modify the source string. # See #1559 for details. takeSnapshot = _('Take snapshot') \ .replace('Schnappschuss', '(?:Schnappschuss|Snapshot)') host, _post, user, path, _cipher = cfg.sshHostUserPortPathCipher() # replace: --exclude"" or --include"" self.re_include_exclude = re.compile( r'(--(?:ex|in)clude=")(.*?)(")') # codespell-ignore # replace: 'USER@HOST:"PATH"' self.re_remote_path = re.compile( r'(\'%s@%s:"%s)(.*?)("\')' % (user, host, path) ) # replace: --link-dest="../../" self.re_link_dest = re.compile(r'(--link-dest="\.\./\.\./)(.*?)(")') # search for: [C] self.re_change = re.compile(r'(^\[C\] .{11} )(.*)') #search for: [I] Take snapshot (rsync: BACKINTIME: ) # [I] Take snapshot (rsync: deleting ) # [I] Take snapshot (rsync: rsync: readlink_stat("...mountpoint/") # [I] Take snapshot (rsync: rsync: send_files failed to open "...mountpoint/": Permission denied (13)) # [I] Take snapshot (rsync: file has vanished: "...mountpoint/") # [I] Take snapshot (rsync: ) pattern = [] pattern.append(r' BACKINTIME: .{11} ') pattern.append(r' deleting ') pattern.append(r' rsync: readlink_stat\(".*?mountpoint/') pattern.append(r' rsync: send_files failed to open ".*?mountpoint/') pattern.append(r' file has vanished: ".*?mountpoint/') pattern.append(r' ') self.re_info = re.compile(r'(^(?:\[I\] )?%s \(rsync:(?:%s))(.*?)(\).*|".*)' % (takeSnapshot, '|'.join(pattern))) #search for: [E] Error: rsync readlink_stat("...mountpoint/") # [E] Error: rsync: send_files failed to open "...mountpoint/": Permission denied (13) # [E] Error: rsync: recv_generator: failed to stat "/": File name too long (36) # [E] Error: rsync: recv_generator: mkdir "/": File name too long (36) pattern = [] pattern.append(r' rsync: readlink_stat\(".*?mountpoint/') pattern.append(r' rsync: send_files failed to open ".*?mountpoint/') if self.remote_path == './': pattern.append(r' rsync: recv_generator: failed to stat "/home/[^/]*/') pattern.append(r' rsync: recv_generator: mkdir "/home/[^/]*/') else: pattern.append(r' rsync: recv_generator: failed to stat ".*?{}'.format(self.remote_path)) pattern.append(r' rsync: recv_generator: mkdir ".*?{}'.format(self.remote_path)) pattern.append(r' rsync: .*?".*?mountpoint/') self.re_error = re.compile(r'(^(?:\[E\] )?Error:(?:%s))(.*?)(".*)' % '|'.join(pattern)) # search for: [I] ssh USER@HOST cp -aRl "PATH"* "PATH" self.re_info_cp= re.compile(r'(^\[I\] .*? cp -aRl "%s/)(.*?)("\* "%s/)(.*?)(")' % (path, path)) # search for all chars except * self.re_all_except_asterisk = re.compile(r'[^\*]+') # search for: -> self.re_all_except_arrow = re.compile(r'(.*?)((?: [-=]> )+)(.*)') #skip: [I] Take snapshot (rsync: sending incremental file list) # [I] Take snapshot (rsync: building file list ... done) # [I] Take snapshot (rsync: sent 26569703 bytes received 239616 bytes 85244.26 bytes/sec) # [I] Take snapshot (rsync: total size is 9130263449 speedup is 340.56) # [I] Take snapshot (rsync: rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1070) [sender=3.0.9]) # [I] Take snapshot (rsync: rsync warning: some files vanished before they could be transferred (code 24) at main.c(1070) [sender=3.0.9]) pattern = [] pattern.append(r'sending incremental file list') pattern.append(r'building file list ... done') pattern.append(r'sent .*? received') pattern.append(r'total size is .*? speedup is') pattern.append(r'rsync error: some files/attrs were not transferred') pattern.append(r'rsync warning: some files vanished before they could be transferred') self.re_skip = re.compile(r'^(?:\[I\] )?%s \(rsync: (%s)' % (takeSnapshot, '|'.join(pattern))) self.string = string self.newline = '\n' if string else b'\n' def __del__(self): self.close() def startProcess(self): """ start 'encfsctl decode' process in pipe mode. """ thread = TempPasswordThread(self.password) env = os.environ.copy() env['ASKPASS_TEMP'] = thread.temp_file with thread.starter(): encfsctl = [ 'encfsctl', 'decode', '--extpass=backintime-askpass', self.encfs.path ] logger.debug(f'Call command: {encfsctl}', self) self.p = subprocess.Popen( encfsctl, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, # return string (if True) or bytes universal_newlines=self.string, bufsize=0 ) def path(self, path): """ write encrypted path to encfsctl stdin and read plain path from stdout if stdout is empty (most likely because there was an error) return crypt path """ if self.string: assert isinstance(path, str), 'path is not str type: %s' % path else: assert isinstance(path, bytes), 'path is not bytes type: %s' % path if not 'p' in vars(self): self.startProcess() if not self.p.returncode is None: logger.warning( "'encfsctl decode' process terminated. Restarting.", self ) del self.p self.startProcess() self.p.stdin.write(path + self.newline) ret = self.p.stdout.readline() ret = ret.strip(self.newline) if ret: return ret return path def list(self, list_): """ decode a list of paths """ output = [] for path in list_: output.append(self.path(path)) return output def log(self, line): """ decode paths in takesnapshot.log """ # rsync cmd if line.startswith('[I] rsync') or line.startswith('[I] nocache rsync'): line = self.re_include_exclude.sub(self.replace, line) line = self.re_remote_path.sub(self.replace, line) line = self.re_link_dest.sub(self.replace, line) return line # [C] Change lines m = self.re_change.match(line) if not m is None: return m.group(1) + self.pathWithArrow(m.group(2)) # [I] Information lines m = self.re_skip.match(line) if not m is None: return line m = self.re_info.match(line) if not m is None: return m.group(1) + self.pathWithArrow(m.group(2)) + m.group(3) # [E] Error lines m = self.re_error.match(line) if not m is None: return m.group(1) + self.path(m.group(2)) + m.group(3) # cp cmd m = self.re_info_cp.match(line) if not m is None: return m.group(1) + self.path(m.group(2)) + m.group(3) + self.path(m.group(4)) + m.group(5) return line def replace(self, m): """ return decoded string for re.sub """ decrypt = self.re_all_except_asterisk.sub(self.pathMatch, m.group(2)) if os.path.isabs(m.group(2)): decrypt = os.path.join(os.sep, decrypt) return m.group(1) + decrypt + m.group(3) def pathMatch(self, m): """ return decoded path of a match object """ return self.path(m.group(0)) def pathWithArrow(self, path): """rsync print symlinks like 'dest -> src'. This will decode both and also normal paths """ m = self.re_all_except_arrow.match(path) if not m is None: return self.path(m.group(1)) + m.group(2) + self.path(m.group(3)) else: return self.path(path) def remote(self, path): """ decode the path on remote host starting from backintime/host/user/... """ assert isinstance(path, bytes), 'path is not bytes type: %s' % path remote_path = self.remote_path.encode() dec_path = self.path(path[len(remote_path):]) return os.path.join(remote_path, dec_path) def close(self): """ stop encfsctl process """ if 'p' in vars(self) and self.p.returncode is None: logger.debug('stop \'encfsctl decode\' process', self) self.p.communicate() backintime-1.6.1/common/encode.py000066400000000000000000000020141514264426600167330ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # SPDX-FileCopyrightText: © 2012-2022 Taylor Raack # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Split from common/encfstools.py. """Module related to encrypted backup profiles. """ import os class Bounce: """Dummy class that will simply return all input. This is the standard for config.ENCODE. """ def __init__(self): self.chroot = os.sep def path(self, path: str) -> str: """The path.""" return path def exclude(self, path: str) -> str: """Exclude entry.""" return path def include(self, path: str) -> str: """Include entry.""" return path def remote(self, path: str) -> str: """Remote path.""" return path def close(self) -> None: """Nothing.""" backintime-1.6.1/common/event.py000066400000000000000000000050161514264426600166240ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Code originally from the "Feedybus" project. Author of that project is also # the author of this file. """Module offering an event class do realize observer pattern. It is not a classic textbook-accurate implementation of the observer pattern, but rather a simple, pragmatic and pythonic solution. The solution is inspired by discussion and code in https://stackoverflow.com/a/48339861/4865723 . The subject owns an instance of the `Event` class and the observer registers to that instance. That's it. Example : .. python:: class SomeData: def __init__(self): self.event_data_modified = Event() def do_modify_data(self): # ... modify data ... # Notify observers self.event_data_modified.notify() class ListWidget: def _init__(self, data): data.register(self._handle_data_modified) def _handle_data_modified(self): print('data was modified') """ from contextlib import contextmanager class Event: """Pragmatic and pythonic implementation of Obserer pattern. Inspired by discussion and code in https://stackoverflow.com/a/48339861/4865723 """ def __init__(self): self._callbacks = [] def notify(self, *args, **kwargs): """Notify registered observers. The args, and kwargs are given to the observers. """ for callback in self._callbacks: callback(*args, **kwargs) def register(self, callback): """Register an observer (callback function).""" if callback not in self._callbacks: self._callbacks.append(callback) return callback def deregister(self, callback): """Deregister / remove an observer (callback function).""" self._callbacks.remove(callback) @contextmanager def keep_silent(self): """A context manager function to suppress notification of the observers.""" silent_callbacks = [] try: silent_callbacks = self._callbacks self._callbacks = [] yield finally: if silent_callbacks: self._callbacks = silent_callbacks backintime-1.6.1/common/exceptions.py000066400000000000000000000024061514264426600176640ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2015-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . class BackInTimeException(Exception): pass class MountException(BackInTimeException): pass class NoPubKeyLogin(MountException): pass class KnownHost(MountException): pass class HashCollision(BackInTimeException): pass class EncodeValueError(BackInTimeException): pass class StopException(BackInTimeException): pass class Timeout(BackInTimeException): pass class InvalidChar(BackInTimeException): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg class InvalidCmd(BackInTimeException): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg class LimitExceeded(BackInTimeException): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg class PermissionDeniedByPolicy(BackInTimeException): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg backintime-1.6.1/common/flock.py000066400000000000000000000137661514264426600166140ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Manage file lock. Offer context managers to manage file lock (flock) files. """ import os import fcntl from pathlib import Path import logger class _FlockContext: """Context manager to manage file locks (flock). It will be tried to establish a multi-user file lock; if not feasible a single-user file lock will be used. It depends on the GNU/Linux distribution used and the write permissions to the file lock locations in the file system. Usage example :: class MyFlock(_FlockContext): def __init__(self): super().__init__('my.lock') with MyFlock(): do_fancy_things() The following directories will be checked in sequence to determine if they exist, if a file lock file exists within them, or if there are sufficient permissions to create such a file within them. :: /run/lock /var/lock /run/user// ~/.cache The first and second directory in that list is for multi-user file lock. To the experience of the developers on Debian-based distributions there is no problem having a multi-user file lock. But on Arch-based distributions only a user with root privileges is able to do it. Because of that on Arch a single-user file lock is used by default until Back In Time is started once as root. """ def __init__(self, filename: str, disable: bool = False): """Check if an flock file can be used or created. See the classes documentation about details. Args: filename: The filename (without path) used for the flock file. disabled: Disable the whole context managers behavior. This is a workaround. See #1751 and :func:``Snapshots.backup()`` for details. Raises: RuntimeError: If it wasn't possible to use """ self._file_path = None """Full path used for the flock file""" self._flock_handle = None """File handle (descriptor) to the flock file.""" # Workaround for #1751. Remove after refactoring Snapshots.backup() if disable: return None folder = Path(Path.cwd().root) / 'run' / 'lock' if not folder.exists(): # On older systems folder = Path(Path.cwd().root) / 'var' / 'lock' self._file_path = folder / filename if self._can_use_file(self._file_path): return None # Try user specific file lock # e.g. /run/user/ self._file_path = Path( os.environ.get('XDG_RUNTIME_DIR', f'/run/user/{os.getuid()}') ) / filename if self._can_use_file(self._file_path): return None # At last, try users cache dir. self._file_path = Path( os.environ.get('XDG_CACHE_HOME', Path.home() / '.cache') ) / filename if self._can_use_file(self._file_path): return None raise RuntimeError( f'Can not establish global flock file {self._file_path}') def _can_use_file(self, file_path: Path) -> bool: """Check if ``file_path`` is usable as an flock file. The answer is ``True`` if the file exists without checking its permissions. If not the file will be created and if successful ``True`` will be returned. Returns: bool: The answer. Raises: PermissionError: Not enough permissions to create the file. Exception: Any other error. """ if file_path.exists(): return True # Try to create it try: file_path.touch(mode=0o666) except PermissionError: logger.debug(f'Cannot use file lock on {file_path}.') except Exception as err: logger.error( f'Unknown error while testing file lock on {file_path}. ' f'Please open a bug report. Error was {err}.') else: logger.debug(f'Use {file_path} for file lock.') return True return False def __enter__(self): """Request an exclucive file lock on :data:``self._file_path``. """ # Workaround for #1751. Remove after refactoring Snapshots.backup() # See __init__() for details if self._file_path is None: return None self._log('Set') # Open file for reading self._flock_handle = self._file_path.open(mode='r') # blocks (waits) until an existing flock is released fcntl.flock(self._flock_handle, fcntl.LOCK_EX) return self def __exit__(self, exc_type, exc_value, exc_tb): # Workaround for #1751. Remove after refactoring Snapshots.backup() # See __init__() for details if self._flock_handle is None: return None self._log('Release') fcntl.fcntl(self._flock_handle, fcntl.LOCK_UN) self._flock_handle.close() def _log(self, prefix: str): """Generate a log message including the current lock files path and the process ID. Args: prefix: Used in front of the log message. """ logger.debug(f'{prefix} flock {self._file_path} by PID {os.getpid()}') class GlobalFlock(_FlockContext): """Context manager used for global file lock in Back In Time. If it is a multi-user or single-user flock depends on the several aspects. See :class:`_FlockContext` for details. """ def __init__(self, disable: bool = False): """See :func:`_FlockContext.__init__()` for details. """ super().__init__('backintime.lock', disable=disable) backintime-1.6.1/common/gocryptfstools.py000066400000000000000000000116211514264426600206030ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2017 Germar Reitze # SPDX-FileCopyrightText: © 2025 David Wales (@daviewales) # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import subprocess import logger from pathlib import Path from password_ipc import TempPasswordThread from mount import MountControl from exceptions import MountException class GocryptfsMount(MountControl): """ """ def __init__(self, *args, **kwargs): super(GocryptfsMount, self).__init__(*args, **kwargs) # Workaround for some linters. self.path = None self.reverse = None self.config_path = None self.setattrKwargs( 'path', self.config.localGocryptfsPath(self.profile_id), **kwargs ) self.setattrKwargs('reverse', False, **kwargs) self.setattrKwargs('password', None, store=False, **kwargs) self.setattrKwargs('config_path', None, **kwargs) self.setDefaultArgs() self.mountproc = 'gocryptfs' self.log_command = f'{self.mode}: {self.path}' self.symlink_subfolder = None def _mount(self): """ mount the service """ if self.password is None: self.password = self.config.password( self.parent, self.profile_id, self.mode ) thread = TempPasswordThread(self.password) env = os.environ.copy() env['ASKPASS_TEMP'] = thread.temp_file with thread.starter(): gocryptfs = [ self.mountproc, '-extpass', 'backintime-askpass', '-quiet' ] if self.reverse: gocryptfs += ['-reverse'] gocryptfs += [ self.path, self.currentMountpoint ] logger.debug(f'Call mount command: {gocryptfs}', self) proc = subprocess.Popen( gocryptfs, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True ) output = proc.communicate()[0] if proc.returncode: msg = _('Unable to mount "{command}"').format( command=' '.join(gocryptfs) ) raise MountException( f'{msg}:\n\n{output}\n\nReturn code: {proc.returncode}' ) def init_backend(self): """ init the cipher path """ self.checkFuse() # gocryptfs binary available? if self.password is None: self.password = self.config.password( self.parent, self.profile_id, self.mode) # Dev note: See docstring in EncFS_mount._mount() for detailed # description about the password thing. thread = TempPasswordThread(self.password) env = os.environ.copy() env['ASKPASS_TEMP'] = thread.temp_file with thread.starter(): gocryptfs = [ self.mountproc, '-extpass', 'backintime-askpass'] gocryptfs.append('-init') gocryptfs.append(self.path) logger.debug( f'Call command to create gocryptfs config file: {gocryptfs}', self ) proc = subprocess.Popen( gocryptfs, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) output = proc.communicate()[0] if proc.returncode: msg = _('Unable to init encrypted path "{command}"').format( command=' '.join(gocryptfs) ) raise MountException( f'{msg}:\n\n{output}\n\nReturn code: {proc.returncode}' ) def preMountCheck(self, first_run=False): """ check what ever conditions must be given for the mount """ self.checkFuse() if first_run: pass return True def configFile(self) -> str: """Full path of gocryptfs config file""" fn = 'gocryptfs.conf' if self.config_path is None: return os.path.join(self.path, fn) return os.path.join(self.config_path, fn) def isConfigured(self) -> bool: """Check if `gocryptfs.conf` exists.""" fp_conf = Path(self.configFile()) if fp_conf.exists(): logger.debug(f'Found gocryptfs config file in {fp_conf}', self) return True logger.debug(f'No gocryptfs config found. Missing {fp_conf}', self) return False backintime-1.6.1/common/guiapplicationinstance.py000066400000000000000000000043311514264426600222370ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import logger from applicationinstance import ApplicationInstance class GUIApplicationInstance(ApplicationInstance): """Handle one application instance mechanism. """ def __init__(self, baseControlFile, raiseCmd=''): """Specify the base for control files.""" self.raiseFile = baseControlFile + '.raise' self.raiseCmd = raiseCmd super(GUIApplicationInstance, self).__init__( baseControlFile + '.pid', False, False) # Remove raiseFile is already exists if os.path.exists(self.raiseFile): os.remove(self.raiseFile) self.check() self.startApplication() def check(self): """Check if the current application is already running.""" ret = super(GUIApplicationInstance, self).check(False) if not ret: print(f'The application is already running. (pid: {self.pid})') # Notify raise try: with open(self.raiseFile, 'wt') as f: f.write(self.raiseCmd) except OSError as e: logger.error(f'Failed to write raise file {e.filename}: ' f'[{e.errno}] {e.strerror}') # Exit raise an exception so don't put it in a try/except block exit(0) else: return ret def raiseCommand(self): """ check if the application must to be raised return None if no raise needed, or a string command to raise """ ret_val = None try: if os.path.isfile(self.raiseFile): with open(self.raiseFile, 'rt') as f: ret_val = f.read() os.remove(self.raiseFile) except: pass return ret_val backintime-1.6.1/common/inhibitsuspend.py000066400000000000000000000157501514264426600205410ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2014 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Split from common/tools.py """Manage inhibition of suspend mode via DBus. """ import os import sys import dbus import logger import bitbase class InhibitSuspend: """Context manager to prevent machine to go to suspend or hibernate.""" def __init__(self, reason: str = None, app_id: str = None): self.app_id = app_id if app_id else sys.argv[0] self.reason = reason if reason else 'take snapshot' self.cookie = None self.bus = None self.interface = None self.file_descs = [] # Order is important. Don't change it for no good reason. self.providers = { 'freedesktop.login1': self._inhibit_via_freedesktop_login_one, 'freedesktop.PowerManagment': self._inhibit_via_freedesktop_power_management, 'gnome': self._inhibit_via_gnome, 'mate': self._inhibit_via_mate, } def _open_system_bus(self): try: self.bus = dbus.SystemBus() except dbus.exceptions.DBusException as exc: logger.error(f'Unable to open DBus system bus. {exc}') def _open_session_bus(self): # Fixes #1592 (BiT hangs as root when trying to establish a dbus user # session connection) # Side effect: In BiT <= 1.4.1 root still tried to connect to the dbus # user session and it may have worked sometimes (without logging we # don't know) so as root suspend can no longer inhibited. if bitbase.IS_IN_ROOT_MODE: # Dev note (buhtz, 2025-04): But does this need to be a "Fail"? logger.debug( 'Inhibit Suspend aborted because BIT was started as root.') return # Connect directly to the socket instead of dbus.SessionBus because # the dbus.SessionBus was initiated before we loaded the environ # variables and might not work. try: self.bus = dbus.bus.BusConnection( os.environ['DBUS_SESSION_BUS_ADDRESS']) except KeyError: pass except dbus.exceptions.DBusException as exc: logger.error(f'Unable to open DBus session bus. {exc}') if self.bus: return try: # This code may hang forever (if BIT is run as root via cron # job and no user is logged in). See #1592 self.bus = dbus.SessionBus() except dbus.exceptions.DBusException as exc: logger.error(f'Unable to open DBus session bus. {exc}') def _inhibit_via_freedesktop_login_one(self): """Inhibit using system bus and login1 method. Method should be available on modern systems with and without systemd. Uninhibition is done via closing a file descriptor. """ self._open_system_bus() if not self.bus: return False try: obj = self.bus.get_object( bus_name='org.freedesktop.login1', object_path='/org/freedesktop/login1') iface = dbus.Interface( object=obj, dbus_interface='org.freedesktop.login1.Manager') # Inhibition is active until this file descriptor is closed file_desc = iface.Inhibit( 'sleep', self.app_id, self.reason, "block").take() except dbus.DBusException as exc: logger.debug(f'Inhibition (via "login1") failed: {exc}') return False self.file_descs.append(file_desc) return True def _inhibit_generic_in_session(self, bus_name: str, object_path: str, dbus_interface: str, args: tuple) -> bool: if not self.bus: return False try: obj = self.bus.get_object( bus_name=bus_name, object_path=object_path) self.interface = dbus.Interface( object=obj, dbus_interface=dbus_interface) self.cookie = self.interface.Inhibit(*args) except dbus.DBusException as exc: logger.debug(f'Inhibition (via "{bus_name}") failed: {exc}') return False return True def _inhibit_via_freedesktop_power_management(self): return self._inhibit_generic_in_session( bus_name='org.freedesktop.PowerManagement', object_path='/org/freedesktop/Inhibit', dbus_interface='org.freedesktop.PowerManager.Inhibit', args=( self.app_id, self.reason ) ) def _inhibit_via_gnome(self): return self._inhibit_generic_in_session( bus_name='org.gnome.SessionManager', object_path='/org/gnome/SessionManager', dbus_interface='org.gnome.SessionManager.Inhibit', args=( self.app_id, 0, # xwindow-id not relevant today self.reason, dbus.UInt32(4), # 4 = SUSPEND ) ) def _inhibit_via_mate(self): return self._inhibit_generic_in_session( bus_name='org.mate.SessionManager', object_path='/org/mate/SessionManager', dbus_interface='org.mate.SessionManager.Inhibit', args=( self.app_id, 0, # xwindow-id not relevant today self.reason, dbus.UInt32(4), # 4 = SUSPEND ) ) def __enter__(self): failed = [] for name, inhibit in self.providers.items(): # logger.debug(f'Try inhibiting suspend mode via "{name}"') result = inhibit() if result: logger.info(f'Suspend mode inhibited via "{name}"') break failed.append(name) result = True if failed: if result: logger.debug('Inhibiting suspend mode failed ' f'beforehand with {failed}') else: logger.error('Inhibiting suspend mode failed. ' f'Tried with {failed}') return self def __exit__(self, exc_type, exc_value, exc_tb): try: if self.cookie: self.interface.UnInhibit(self.cookie) for fd in self.file_descs: os.close(fd) except dbus.exceptions.DBusException as exc: logger.error(f'Release suspend mode inhibition failed: {exc}') else: if self.cookie or self.file_descs: logger.info('Released suspend mode inhibition') backintime-1.6.1/common/languages.py000066400000000000000000002013211514264426600174460ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2023 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Generated at Tue Feb 10 15:49:56 2026 with help # of package "babel" and "polib". # https://babel.pocoo.org # https://github.com/python-babel/babel # pylint: disable=too-many-lines,missing-module-docstring names = { 'ar': { '_native': 'العربية', 'zh_CN': '阿拉伯语', 'is': 'arabíska', 'et': 'araabia', 'sr': 'арапски', 'nl': 'Arabisch', 'sl': 'arabščina', 'fa': 'عربی', 'zh_TW': '阿拉伯文', 'bg': 'арабски', 'gl': 'árabe', 'lt': 'arabų', 'eu': 'arabiera', 'he': 'ערבית', 'pl': 'arabski', 'sk': 'arabčina', 'cs': 'arabština', 'ka': 'არაბული', 'de': 'Arabisch', 'hu': 'arab', 'ca': 'àrab', 'ar': 'العربية', 'ro': 'arabă', 'fo': 'arabiskt', 'tr': 'Arapça', 'nb': 'arabisk', 'pt': 'árabe', 'it': 'arabo', 'uk': 'арабська', 'fi': 'arabia', 'ko': '아랍어', 'hr': 'arapski', 'vi': 'Tiếng Ả Rập', 'pt_BR': 'árabe', 'el': 'Αραβικά', 'ru': 'арабский', 'eo': 'araba', 'ja': 'アラビア語', 'sr_Latn': 'arapski', 'sv': 'arabiska', 'da': 'arabisk', 'id': 'Arab', 'fr': 'arabe', 'es': 'árabe', 'nn': 'arabisk', 'en': 'Arabic', }, 'bg': { '_native': 'български', 'zh_CN': '保加利亚语', 'is': 'búlgarska', 'et': 'bulgaaria', 'sr': 'бугарски', 'nl': 'Bulgaars', 'sl': 'bolgarščina', 'fa': 'بلغاری', 'zh_TW': '保加利亞文', 'bg': 'български', 'gl': 'búlgaro', 'lt': 'bulgarų', 'eu': 'bulgariera', 'he': 'בולגרית', 'pl': 'bułgarski', 'sk': 'bulharčina', 'cs': 'bulharština', 'ka': 'ბულგარული', 'de': 'Bulgarisch', 'hu': 'bolgár', 'ca': 'búlgar', 'ar': 'البلغارية', 'ro': 'bulgară', 'fo': 'bulgarskt', 'tr': 'Bulgarca', 'nb': 'bulgarsk', 'pt': 'búlgaro', 'it': 'bulgaro', 'uk': 'болгарська', 'fi': 'bulgaria', 'ko': '불가리아어', 'hr': 'bugarski', 'vi': 'Tiếng Bulgaria', 'pt_BR': 'búlgaro', 'el': 'Βουλγαρικά', 'ru': 'болгарский', 'eo': 'bulgara', 'ja': 'ブルガリア語', 'sr_Latn': 'bugarski', 'sv': 'bulgariska', 'da': 'bulgarsk', 'id': 'Bulgaria', 'fr': 'bulgare', 'es': 'búlgaro', 'nn': 'bulgarsk', 'en': 'Bulgarian', }, 'ca': { '_native': 'català', 'zh_CN': '加泰罗尼亚语', 'is': 'katalónska', 'et': 'katalaani', 'sr': 'каталонски', 'nl': 'Catalaans', 'sl': 'katalonščina', 'fa': 'کاتالان', 'zh_TW': '加泰蘭文', 'bg': 'каталонски', 'gl': 'catalán', 'lt': 'katalonų', 'eu': 'katalana', 'he': 'קטלאנית', 'pl': 'kataloński', 'sk': 'katalánčina', 'cs': 'katalánština', 'ka': 'კატალანური', 'de': 'Katalanisch', 'hu': 'katalán', 'ca': 'català', 'ar': 'الكتالانية', 'ro': 'catalană', 'fo': 'katalani', 'tr': 'Katalanca', 'nb': 'katalansk', 'pt': 'catalão', 'it': 'catalano', 'uk': 'каталонська', 'fi': 'katalaani', 'ko': '카탈로니아어', 'hr': 'katalonski', 'vi': 'Tiếng Catalan', 'pt_BR': 'catalão', 'el': 'Καταλανικά', 'ru': 'каталанский', 'eo': 'kataluna', 'ja': 'カタロニア語', 'sr_Latn': 'katalonski', 'sv': 'katalanska', 'da': 'catalansk', 'id': 'Katalan', 'fr': 'catalan', 'es': 'catalán', 'nn': 'katalansk', 'en': 'Catalan', }, 'cs': { '_native': 'čeština', 'zh_CN': '捷克语', 'is': 'tékkneska', 'et': 'tšehhi', 'sr': 'чешки', 'nl': 'Tsjechisch', 'sl': 'češčina', 'fa': 'چکی', 'zh_TW': '捷克文', 'bg': 'чешки', 'gl': 'checo', 'lt': 'čekų', 'eu': 'txekiera', 'he': 'צ׳כית', 'pl': 'czeski', 'sk': 'čeština', 'cs': 'čeština', 'ka': 'ჩეხური', 'de': 'Tschechisch', 'hu': 'cseh', 'ca': 'txec', 'ar': 'التشيكية', 'ro': 'cehă', 'fo': 'kekkiskt', 'tr': 'Çekçe', 'nb': 'tsjekkisk', 'pt': 'tcheco', 'it': 'ceco', 'uk': 'чеська', 'fi': 'tšekki', 'ko': '체코어', 'hr': 'češki', 'vi': 'Tiếng Séc', 'pt_BR': 'tcheco', 'el': 'Τσεχικά', 'ru': 'чешский', 'eo': 'ĉeĥa', 'ja': 'チェコ語', 'sr_Latn': 'češki', 'sv': 'tjeckiska', 'da': 'tjekkisk', 'id': 'Ceko', 'fr': 'tchèque', 'es': 'checo', 'nn': 'tsjekkisk', 'en': 'Czech', }, 'da': { '_native': 'dansk', 'zh_CN': '丹麦语', 'is': 'danska', 'et': 'taani', 'sr': 'дански', 'nl': 'Deens', 'sl': 'danščina', 'fa': 'دانمارکی', 'zh_TW': '丹麥文', 'bg': 'датски', 'gl': 'dinamarqués', 'lt': 'danų', 'eu': 'daniera', 'he': 'דנית', 'pl': 'duński', 'sk': 'dánčina', 'cs': 'dánština', 'ka': 'დანიური', 'de': 'Dänisch', 'hu': 'dán', 'ca': 'danès', 'ar': 'الدانمركية', 'ro': 'daneză', 'fo': 'danskt', 'tr': 'Danca', 'nb': 'dansk', 'pt': 'dinamarquês', 'it': 'danese', 'uk': 'данська', 'fi': 'tanska', 'ko': '덴마크어', 'hr': 'danski', 'vi': 'Tiếng Đan Mạch', 'pt_BR': 'dinamarquês', 'el': 'Δανικά', 'ru': 'датский', 'eo': 'dana', 'ja': 'デンマーク語', 'sr_Latn': 'danski', 'sv': 'danska', 'da': 'dansk', 'id': 'Dansk', 'fr': 'danois', 'es': 'danés', 'nn': 'dansk', 'en': 'Danish', }, 'de': { '_native': 'Deutsch', 'zh_CN': '德语', 'is': 'þýska', 'et': 'saksa', 'sr': 'немачки', 'nl': 'Duits', 'sl': 'nemščina', 'fa': 'آلمانی', 'zh_TW': '德文', 'bg': 'немски', 'gl': 'alemán', 'lt': 'vokiečių', 'eu': 'alemana', 'he': 'גרמנית', 'pl': 'niemiecki', 'sk': 'nemčina', 'cs': 'němčina', 'ka': 'გერმანული', 'de': 'Deutsch', 'hu': 'német', 'ca': 'alemany', 'ar': 'الألمانية', 'ro': 'germană', 'fo': 'týskt', 'tr': 'Almanca', 'nb': 'tysk', 'pt': 'alemão', 'it': 'tedesco', 'uk': 'німецька', 'fi': 'saksa', 'ko': '독일어', 'hr': 'njemački', 'vi': 'Tiếng Đức', 'pt_BR': 'alemão', 'el': 'Γερμανικά', 'ru': 'немецкий', 'eo': 'germana', 'ja': 'ドイツ語', 'sr_Latn': 'nemački', 'sv': 'tyska', 'da': 'tysk', 'id': 'Jerman', 'fr': 'allemand', 'es': 'alemán', 'nn': 'tysk', 'en': 'German', }, 'el': { '_native': 'Ελληνικά', 'zh_CN': '希腊语', 'is': 'gríska', 'et': 'kreeka', 'sr': 'грчки', 'nl': 'Grieks', 'sl': 'grščina', 'fa': 'یونانی', 'zh_TW': '希臘文', 'bg': 'гръцки', 'gl': 'grego', 'lt': 'graikų', 'eu': 'greziera', 'he': 'יוונית', 'pl': 'grecki', 'sk': 'gréčtina', 'cs': 'řečtina', 'ka': 'ბერძნული', 'de': 'Griechisch', 'hu': 'görög', 'ca': 'grec', 'ar': 'اليونانية', 'ro': 'greacă', 'fo': 'grikskt', 'tr': 'Yunanca', 'nb': 'gresk', 'pt': 'grego', 'it': 'greco', 'uk': 'грецька', 'fi': 'kreikka', 'ko': '그리스어', 'hr': 'grčki', 'vi': 'Tiếng Hy Lạp', 'pt_BR': 'grego', 'el': 'Ελληνικά', 'ru': 'греческий', 'eo': 'greka', 'ja': 'ギリシャ語', 'sr_Latn': 'grčki', 'sv': 'grekiska', 'da': 'græsk', 'id': 'Yunani', 'fr': 'grec', 'es': 'griego', 'nn': 'gresk', 'en': 'Greek', }, 'en': { '_native': 'English', 'zh_CN': '英语', 'is': 'enska', 'et': 'inglise', 'sr': 'енглески', 'nl': 'Engels', 'sl': 'angleščina', 'fa': 'انگلیسی', 'zh_TW': '英文', 'bg': 'английски', 'gl': 'inglés', 'lt': 'anglų', 'eu': 'ingelesa', 'he': 'אנגלית', 'pl': 'angielski', 'sk': 'angličtina', 'cs': 'angličtina', 'ka': 'ინგლისური', 'de': 'Englisch', 'hu': 'angol', 'ca': 'anglès', 'ar': 'الإنجليزية', 'ro': 'engleză', 'fo': 'enskt', 'tr': 'İngilizce', 'nb': 'engelsk', 'pt': 'inglês', 'it': 'inglese', 'uk': 'англійська', 'fi': 'englanti', 'ko': '영어', 'hr': 'engleski', 'vi': 'Tiếng Anh', 'pt_BR': 'inglês', 'el': 'Αγγλικά', 'ru': 'английский', 'eo': 'angla', 'ja': '英語', 'sr_Latn': 'engleski', 'sv': 'engelska', 'da': 'engelsk', 'id': 'Inggris', 'fr': 'anglais', 'es': 'inglés', 'nn': 'engelsk', 'en': 'English', }, 'eo': { '_native': 'Esperanto', 'zh_CN': '世界语', 'is': 'esperantó', 'et': 'esperanto', 'sr': 'есперанто', 'nl': 'Esperanto', 'sl': 'esperanto', 'fa': 'اسپرانتو', 'zh_TW': '世界文', 'bg': 'есперанто', 'gl': 'esperanto', 'lt': 'esperanto', 'eu': 'esperantoa', 'he': 'אספרנטו', 'pl': 'esperanto', 'sk': 'esperanto', 'cs': 'esperanto', 'ka': 'ესპერანტო', 'de': 'Esperanto', 'hu': 'eszperantó', 'ca': 'esperanto', 'ar': 'الإسبرانتو', 'ro': 'esperanto', 'fo': 'esperanto', 'tr': 'Esperanto', 'nb': 'esperanto', 'pt': 'esperanto', 'it': 'esperanto', 'uk': 'есперанто', 'fi': 'esperanto', 'ko': '에스페란토어', 'hr': 'esperanto', 'vi': 'Tiếng Quốc Tế Ngữ', 'pt_BR': 'esperanto', 'el': 'Εσπεράντο', 'ru': 'эсперанто', 'eo': 'Esperanto', 'ja': 'エスペラント語', 'sr_Latn': 'esperanto', 'sv': 'esperanto', 'da': 'esperanto', 'id': 'Esperanto', 'fr': 'espéranto', 'es': 'esperanto', 'nn': 'esperanto', 'en': 'Esperanto', }, 'es': { '_native': 'español', 'zh_CN': '西班牙语', 'is': 'spænska', 'et': 'hispaania', 'sr': 'шпански', 'nl': 'Spaans', 'sl': 'španščina', 'fa': 'اسپانیایی', 'zh_TW': '西班牙文', 'bg': 'испански', 'gl': 'español', 'lt': 'ispanų', 'eu': 'gaztelania', 'he': 'ספרדית', 'pl': 'hiszpański', 'sk': 'španielčina', 'cs': 'španělština', 'ka': 'ესპანური', 'de': 'Spanisch', 'hu': 'spanyol', 'ca': 'espanyol', 'ar': 'الإسبانية', 'ro': 'spaniolă', 'fo': 'spanskt', 'tr': 'İspanyolca', 'nb': 'spansk', 'pt': 'espanhol', 'it': 'spagnolo', 'uk': 'іспанська', 'fi': 'espanja', 'ko': '스페인어', 'hr': 'španjolski', 'vi': 'Tiếng Tây Ban Nha', 'pt_BR': 'espanhol', 'el': 'Ισπανικά', 'ru': 'испанский', 'eo': 'hispana', 'ja': 'スペイン語', 'sr_Latn': 'španski', 'sv': 'spanska', 'da': 'spansk', 'id': 'Spanyol', 'fr': 'espagnol', 'es': 'español', 'nn': 'spansk', 'en': 'Spanish', }, 'et': { '_native': 'eesti', 'zh_CN': '爱沙尼亚语', 'is': 'eistneska', 'et': 'eesti', 'sr': 'естонски', 'nl': 'Estisch', 'sl': 'estonščina', 'fa': 'استونیایی', 'zh_TW': '愛沙尼亞文', 'bg': 'естонски', 'gl': 'estoniano', 'lt': 'estų', 'eu': 'estoniera', 'he': 'אסטונית', 'pl': 'estoński', 'sk': 'estónčina', 'cs': 'estonština', 'ka': 'ესტონური', 'de': 'Estnisch', 'hu': 'észt', 'ca': 'estonià', 'ar': 'الإستونية', 'ro': 'estonă', 'fo': 'estiskt', 'tr': 'Estonca', 'nb': 'estisk', 'pt': 'estoniano', 'it': 'estone', 'uk': 'естонська', 'fi': 'viro', 'ko': '에스토니아어', 'hr': 'estonski', 'vi': 'Tiếng Estonia', 'pt_BR': 'estoniano', 'el': 'Εσθονικά', 'ru': 'эстонский', 'eo': 'estona', 'ja': 'エストニア語', 'sr_Latn': 'estonski', 'sv': 'estniska', 'da': 'estisk', 'id': 'Estonia', 'fr': 'estonien', 'es': 'estonio', 'nn': 'estisk', 'en': 'Estonian', }, 'eu': { '_native': 'euskara', 'zh_CN': '巴斯克语', 'is': 'baskneska', 'et': 'baski', 'sr': 'баскијски', 'nl': 'Baskisch', 'sl': 'baskovščina', 'fa': 'باسکی', 'zh_TW': '巴斯克文', 'bg': 'баски', 'gl': 'éuscaro', 'lt': 'baskų', 'eu': 'euskara', 'he': 'בסקית', 'pl': 'baskijski', 'sk': 'baskičtina', 'cs': 'baskičtina', 'ka': 'ბასკური', 'de': 'Baskisch', 'hu': 'baszk', 'ca': 'basc', 'ar': 'الباسكية', 'ro': 'bască', 'fo': 'baskiskt', 'tr': 'Baskça', 'nb': 'baskisk', 'pt': 'basco', 'it': 'basco', 'uk': 'баскська', 'fi': 'baski', 'ko': '바스크어', 'hr': 'baskijski', 'vi': 'Tiếng Basque', 'pt_BR': 'basco', 'el': 'Βασκικά', 'ru': 'баскский', 'eo': 'eŭska', 'ja': 'バスク語', 'sr_Latn': 'baskijski', 'sv': 'baskiska', 'da': 'baskisk', 'id': 'Basque', 'fr': 'basque', 'es': 'euskera', 'nn': 'baskisk', 'en': 'Basque', }, 'fa': { '_native': 'فارسی', 'zh_CN': '波斯语', 'is': 'persneska', 'et': 'pärsia', 'sr': 'персијски', 'nl': 'Perzisch', 'sl': 'perzijščina', 'fa': 'فارسی', 'zh_TW': '波斯文', 'bg': 'персийски', 'gl': 'persa', 'lt': 'persų', 'eu': 'persiera', 'he': 'פרסית', 'pl': 'perski', 'sk': 'perzština', 'cs': 'perština', 'ka': 'სპარსული', 'de': 'Persisch', 'hu': 'perzsa', 'ca': 'persa', 'ar': 'الفارسية', 'ro': 'persană', 'fo': 'persiskt', 'tr': 'Farsça', 'nb': 'persisk', 'pt': 'persa', 'it': 'persiano', 'uk': 'перська', 'fi': 'persia', 'ko': '페르시아어', 'hr': 'perzijski', 'vi': 'Tiếng Ba Tư', 'pt_BR': 'persa', 'el': 'Περσικά', 'ru': 'персидский', 'eo': 'persa', 'ja': 'ペルシア語', 'sr_Latn': 'persijski', 'sv': 'persiska', 'da': 'persisk', 'id': 'Persia', 'fr': 'persan', 'es': 'persa', 'nn': 'persisk', 'en': 'Persian', }, 'fi': { '_native': 'suomi', 'zh_CN': '芬兰语', 'is': 'finnska', 'et': 'soome', 'sr': 'фински', 'nl': 'Fins', 'sl': 'finščina', 'fa': 'فنلاندی', 'zh_TW': '芬蘭文', 'bg': 'фински', 'gl': 'finés', 'lt': 'suomių', 'eu': 'finlandiera', 'he': 'פינית', 'pl': 'fiński', 'sk': 'fínčina', 'cs': 'finština', 'ka': 'ფინური', 'de': 'Finnisch', 'hu': 'finn', 'ca': 'finès', 'ar': 'الفنلندية', 'ro': 'finlandeză', 'fo': 'finskt', 'tr': 'Fince', 'nb': 'finsk', 'pt': 'finlandês', 'it': 'finlandese', 'uk': 'фінська', 'fi': 'suomi', 'ko': '핀란드어', 'hr': 'finski', 'vi': 'Tiếng Phần Lan', 'pt_BR': 'finlandês', 'el': 'Φινλανδικά', 'ru': 'финский', 'eo': 'finna', 'ja': 'フィンランド語', 'sr_Latn': 'finski', 'sv': 'finska', 'da': 'finsk', 'id': 'Suomi', 'fr': 'finnois', 'es': 'finés', 'nn': 'finsk', 'en': 'Finnish', }, 'fo': { '_native': 'føroyskt', 'zh_CN': '法罗语', 'is': 'færeyska', 'et': 'fääri', 'sr': 'фарски', 'nl': 'Faeröers', 'sl': 'ferščina', 'fa': 'فارویی', 'zh_TW': '法羅文', 'bg': 'фарьорски', 'gl': 'feroés', 'lt': 'farerų', 'eu': 'faroera', 'he': 'פארואזית', 'pl': 'farerski', 'sk': 'faerčina', 'cs': 'faerština', 'ka': 'ფარერული', 'de': 'Färöisch', 'hu': 'feröeri', 'ca': 'feroès', 'ar': 'الفاروية', 'ro': 'feroeză', 'fo': 'føroyskt', 'tr': 'Faroe dili', 'nb': 'færøysk', 'pt': 'feroês', 'it': 'faroese', 'uk': 'фарерська', 'fi': 'fääri', 'ko': '페로어', 'hr': 'ferojski', 'vi': 'Tiếng Faroe', 'pt_BR': 'feroês', 'el': 'Φεροϊκά', 'ru': 'фарерский', 'eo': 'feroa', 'ja': 'フェロー語', 'sr_Latn': 'farski', 'sv': 'färöiska', 'da': 'færøsk', 'id': 'Faroe', 'fr': 'féroïen', 'es': 'feroés', 'nn': 'færøysk', 'en': 'Faroese', }, 'fr': { '_native': 'français', 'zh_CN': '法语', 'is': 'franska', 'et': 'prantsuse', 'sr': 'француски', 'nl': 'Frans', 'sl': 'francoščina', 'fa': 'فرانسوی', 'zh_TW': '法文', 'bg': 'френски', 'gl': 'francés', 'lt': 'prancūzų', 'eu': 'frantsesa', 'he': 'צרפתית', 'pl': 'francuski', 'sk': 'francúzština', 'cs': 'francouzština', 'ka': 'ფრანგული', 'de': 'Französisch', 'hu': 'francia', 'ca': 'francès', 'ar': 'الفرنسية', 'ro': 'franceză', 'fo': 'franskt', 'tr': 'Fransızca', 'nb': 'fransk', 'pt': 'francês', 'it': 'francese', 'uk': 'французька', 'fi': 'ranska', 'ko': '프랑스어', 'hr': 'francuski', 'vi': 'Tiếng Pháp', 'pt_BR': 'francês', 'el': 'Γαλλικά', 'ru': 'французский', 'eo': 'franca', 'ja': 'フランス語', 'sr_Latn': 'francuski', 'sv': 'franska', 'da': 'fransk', 'id': 'Prancis', 'fr': 'français', 'es': 'francés', 'nn': 'fransk', 'en': 'French', }, 'gl': { '_native': 'galego', 'zh_CN': '加利西亚语', 'is': 'galisíska', 'et': 'galeegi', 'sr': 'галицијски', 'nl': 'Galicisch', 'sl': 'galicijščina', 'fa': 'گالیسیایی', 'zh_TW': '加利西亞文', 'bg': 'галисийски', 'gl': 'galego', 'lt': 'galisų', 'eu': 'galiziera', 'he': 'גליציאנית', 'pl': 'galicyjski', 'sk': 'galícijčina', 'cs': 'galicijština', 'ka': 'გალისიური', 'de': 'Galicisch', 'hu': 'gallego', 'ca': 'gallec', 'ar': 'الجاليكية', 'ro': 'galiciană', 'fo': 'galisiskt', 'tr': 'Galiçyaca', 'nb': 'galisisk', 'pt': 'galego', 'it': 'galiziano', 'uk': 'галісійська', 'fi': 'galicia', 'ko': '갈리시아어', 'hr': 'galicijski', 'vi': 'Tiếng Galician', 'pt_BR': 'galego', 'el': 'Γαλικιανά', 'ru': 'галисийский', 'eo': 'galega', 'ja': 'ガリシア語', 'sr_Latn': 'galicijski', 'sv': 'galiciska', 'da': 'galicisk', 'id': 'Galisia', 'fr': 'galicien', 'es': 'gallego', 'nn': 'galisisk', 'en': 'Galician', }, 'he': { '_native': 'עברית', 'zh_CN': '希伯来语', 'is': 'hebreska', 'et': 'heebrea', 'sr': 'хебрејски', 'nl': 'Hebreeuws', 'sl': 'hebrejščina', 'fa': 'عبری', 'zh_TW': '希伯來文', 'bg': 'иврит', 'gl': 'hebreo', 'lt': 'hebrajų', 'eu': 'hebreera', 'he': 'עברית', 'pl': 'hebrajski', 'sk': 'hebrejčina', 'cs': 'hebrejština', 'ka': 'ებრაული', 'de': 'Hebräisch', 'hu': 'héber', 'ca': 'hebreu', 'ar': 'العبرية', 'ro': 'ebraică', 'fo': 'hebraiskt', 'tr': 'İbranice', 'nb': 'hebraisk', 'pt': 'hebraico', 'it': 'ebraico', 'uk': 'іврит', 'fi': 'heprea', 'ko': '히브리어', 'hr': 'hebrejski', 'vi': 'Tiếng Do Thái', 'pt_BR': 'hebraico', 'el': 'Εβραϊκά', 'ru': 'иврит', 'eo': 'hebrea', 'ja': 'ヘブライ語', 'sr_Latn': 'hebrejski', 'sv': 'hebreiska', 'da': 'hebraisk', 'id': 'Ibrani', 'fr': 'hébreu', 'es': 'hebreo', 'nn': 'hebraisk', 'en': 'Hebrew', }, 'hr': { '_native': 'hrvatski', 'zh_CN': '克罗地亚语', 'is': 'króatíska', 'et': 'horvaadi', 'sr': 'хрватски', 'nl': 'Kroatisch', 'sl': 'hrvaščina', 'fa': 'کروات', 'zh_TW': '克羅埃西亞文', 'bg': 'хърватски', 'gl': 'croata', 'lt': 'kroatų', 'eu': 'kroaziera', 'he': 'קרואטית', 'pl': 'chorwacki', 'sk': 'chorvátčina', 'cs': 'chorvatština', 'ka': 'ხორვატული', 'de': 'Kroatisch', 'hu': 'horvát', 'ca': 'croat', 'ar': 'الكرواتية', 'ro': 'croată', 'fo': 'kroatiskt', 'tr': 'Hırvatça', 'nb': 'kroatisk', 'pt': 'croata', 'it': 'croato', 'uk': 'хорватська', 'fi': 'kroatia', 'ko': '크로아티아어', 'hr': 'hrvatski', 'vi': 'Tiếng Croatia', 'pt_BR': 'croata', 'el': 'Κροατικά', 'ru': 'хорватский', 'eo': 'kroata', 'ja': 'クロアチア語', 'sr_Latn': 'hrvatski', 'sv': 'kroatiska', 'da': 'kroatisk', 'id': 'Kroasia', 'fr': 'croate', 'es': 'croata', 'nn': 'kroatisk', 'en': 'Croatian', }, 'hu': { '_native': 'magyar', 'zh_CN': '匈牙利语', 'is': 'ungverska', 'et': 'ungari', 'sr': 'мађарски', 'nl': 'Hongaars', 'sl': 'madžarščina', 'fa': 'مجاری', 'zh_TW': '匈牙利文', 'bg': 'унгарски', 'gl': 'húngaro', 'lt': 'vengrų', 'eu': 'hungariera', 'he': 'הונגרית', 'pl': 'węgierski', 'sk': 'maďarčina', 'cs': 'maďarština', 'ka': 'უნგრული', 'de': 'Ungarisch', 'hu': 'magyar', 'ca': 'hongarès', 'ar': 'الهنغارية', 'ro': 'maghiară', 'fo': 'ungarskt', 'tr': 'Macarca', 'nb': 'ungarsk', 'pt': 'húngaro', 'it': 'ungherese', 'uk': 'угорська', 'fi': 'unkari', 'ko': '헝가리어', 'hr': 'mađarski', 'vi': 'Tiếng Hungary', 'pt_BR': 'húngaro', 'el': 'Ουγγρικά', 'ru': 'венгерский', 'eo': 'hungara', 'ja': 'ハンガリー語', 'sr_Latn': 'mađarski', 'sv': 'ungerska', 'da': 'ungarsk', 'id': 'Hungaria', 'fr': 'hongrois', 'es': 'húngaro', 'nn': 'ungarsk', 'en': 'Hungarian', }, 'id': { '_native': 'Indonesia', 'zh_CN': '印度尼西亚语', 'is': 'indónesíska', 'et': 'indoneesia', 'sr': 'индонежански', 'nl': 'Indonesisch', 'sl': 'indonezijščina', 'fa': 'اندونزیایی', 'zh_TW': '印尼文', 'bg': 'индонезийски', 'gl': 'indonesio', 'lt': 'indoneziečių', 'eu': 'indonesiera', 'he': 'אינדונזית', 'pl': 'indonezyjski', 'sk': 'indonézština', 'cs': 'indonéština', 'ka': 'ინდონეზიური', 'de': 'Indonesisch', 'hu': 'indonéz', 'ca': 'indonesi', 'ar': 'الإندونيسية', 'ro': 'indoneziană', 'fo': 'indonesiskt', 'tr': 'Endonezce', 'nb': 'indonesisk', 'pt': 'indonésio', 'it': 'indonesiano', 'uk': 'індонезійська', 'fi': 'indonesia', 'ko': '인도네시아어', 'hr': 'indonezijski', 'vi': 'Tiếng Indonesia', 'pt_BR': 'indonésio', 'el': 'Ινδονησιακά', 'ru': 'индонезийский', 'eo': 'indonezia', 'ja': 'インドネシア語', 'sr_Latn': 'indonežanski', 'sv': 'indonesiska', 'da': 'indonesisk', 'id': 'Indonesia', 'fr': 'indonésien', 'es': 'indonesio', 'nn': 'indonesisk', 'en': 'Indonesian', }, 'is': { '_native': 'íslenska', 'zh_CN': '冰岛语', 'is': 'íslenska', 'et': 'islandi', 'sr': 'исландски', 'nl': 'IJslands', 'sl': 'islandščina', 'fa': 'ایسلندی', 'zh_TW': '冰島文', 'bg': 'исландски', 'gl': 'islandés', 'lt': 'islandų', 'eu': 'islandiera', 'he': 'איסלנדית', 'pl': 'islandzki', 'sk': 'islandčina', 'cs': 'islandština', 'ka': 'ისლანდიური', 'de': 'Isländisch', 'hu': 'izlandi', 'ca': 'islandès', 'ar': 'الأيسلندية', 'ro': 'islandeză', 'fo': 'íslendskt', 'tr': 'İzlandaca', 'nb': 'islandsk', 'pt': 'islandês', 'it': 'islandese', 'uk': 'ісландська', 'fi': 'islanti', 'ko': '아이슬란드어', 'hr': 'islandski', 'vi': 'Tiếng Iceland', 'pt_BR': 'islandês', 'el': 'Ισλανδικά', 'ru': 'исландский', 'eo': 'islanda', 'ja': 'アイスランド語', 'sr_Latn': 'islandski', 'sv': 'isländska', 'da': 'islandsk', 'id': 'Islandia', 'fr': 'islandais', 'es': 'islandés', 'nn': 'islandsk', 'en': 'Icelandic', }, 'it': { '_native': 'italiano', 'zh_CN': '意大利语', 'is': 'ítalska', 'et': 'itaalia', 'sr': 'италијански', 'nl': 'Italiaans', 'sl': 'italijanščina', 'fa': 'ایتالیایی', 'zh_TW': '義大利文', 'bg': 'италиански', 'gl': 'italiano', 'lt': 'italų', 'eu': 'italiera', 'he': 'איטלקית', 'pl': 'włoski', 'sk': 'taliančina', 'cs': 'italština', 'ka': 'იტალიური', 'de': 'Italienisch', 'hu': 'olasz', 'ca': 'italià', 'ar': 'الإيطالية', 'ro': 'italiană', 'fo': 'italskt', 'tr': 'İtalyanca', 'nb': 'italiensk', 'pt': 'italiano', 'it': 'italiano', 'uk': 'італійська', 'fi': 'italia', 'ko': '이탈리아어', 'hr': 'talijanski', 'vi': 'Tiếng Italy', 'pt_BR': 'italiano', 'el': 'Ιταλικά', 'ru': 'итальянский', 'eo': 'itala', 'ja': 'イタリア語', 'sr_Latn': 'italijanski', 'sv': 'italienska', 'da': 'italiensk', 'id': 'Italia', 'fr': 'italien', 'es': 'italiano', 'nn': 'italiensk', 'en': 'Italian', }, 'ja': { '_native': '日本語', 'zh_CN': '日语', 'is': 'japanska', 'et': 'jaapani', 'sr': 'јапански', 'nl': 'Japans', 'sl': 'japonščina', 'fa': 'ژاپنی', 'zh_TW': '日文', 'bg': 'японски', 'gl': 'xaponés', 'lt': 'japonų', 'eu': 'japoniera', 'he': 'יפנית', 'pl': 'japoński', 'sk': 'japončina', 'cs': 'japonština', 'ka': 'იაპონური', 'de': 'Japanisch', 'hu': 'japán', 'ca': 'japonès', 'ar': 'اليابانية', 'ro': 'japoneză', 'fo': 'japanskt', 'tr': 'Japonca', 'nb': 'japansk', 'pt': 'japonês', 'it': 'giapponese', 'uk': 'японська', 'fi': 'japani', 'ko': '일본어', 'hr': 'japanski', 'vi': 'Tiếng Nhật', 'pt_BR': 'japonês', 'el': 'Ιαπωνικά', 'ru': 'японский', 'eo': 'japana', 'ja': '日本語', 'sr_Latn': 'japanski', 'sv': 'japanska', 'da': 'japansk', 'id': 'Jepang', 'fr': 'japonais', 'es': 'japonés', 'nn': 'japansk', 'en': 'Japanese', }, 'ka': { '_native': 'ქართული', 'zh_CN': '格鲁吉亚语', 'is': 'georgíska', 'et': 'gruusia', 'sr': 'грузијски', 'nl': 'Georgisch', 'sl': 'gruzijščina', 'fa': 'گرجی', 'zh_TW': '喬治亞文', 'bg': 'грузински', 'gl': 'xeorxiano', 'lt': 'gruzinų', 'eu': 'georgiera', 'he': 'גאורגית', 'pl': 'gruziński', 'sk': 'gruzínčina', 'cs': 'gruzínština', 'ka': 'ქართული', 'de': 'Georgisch', 'hu': 'grúz', 'ca': 'georgià', 'ar': 'الجورجية', 'ro': 'georgiană', 'fo': 'georgiskt', 'tr': 'Gürcüce', 'nb': 'georgisk', 'pt': 'georgiano', 'it': 'georgiano', 'uk': 'грузинська', 'fi': 'georgia', 'ko': '조지아어', 'hr': 'gruzijski', 'vi': 'Tiếng Georgia', 'pt_BR': 'georgiano', 'el': 'Γεωργιανά', 'ru': 'грузинский', 'eo': 'kartvela', 'ja': 'ジョージア語', 'sr_Latn': 'gruzijski', 'sv': 'georgiska', 'da': 'georgisk', 'id': 'Georgia', 'fr': 'géorgien', 'es': 'georgiano', 'nn': 'georgisk', 'en': 'Georgian', }, 'ko': { '_native': '한국어', 'zh_CN': '韩语', 'is': 'kóreska', 'et': 'korea', 'sr': 'корејски', 'nl': 'Koreaans', 'sl': 'korejščina', 'fa': 'کره‌ای', 'zh_TW': '韓文', 'bg': 'корейски', 'gl': 'coreano', 'lt': 'korėjiečių', 'eu': 'koreera', 'he': 'קוריאנית', 'pl': 'koreański', 'sk': 'kórejčina', 'cs': 'korejština', 'ka': 'კორეული', 'de': 'Koreanisch', 'hu': 'koreai', 'ca': 'coreà', 'ar': 'الكورية', 'ro': 'coreeană', 'fo': 'koreanskt', 'tr': 'Korece', 'nb': 'koreansk', 'pt': 'coreano', 'it': 'coreano', 'uk': 'корейська', 'fi': 'korea', 'ko': '한국어', 'hr': 'korejski', 'vi': 'Tiếng Hàn', 'pt_BR': 'coreano', 'el': 'Κορεατικά', 'ru': 'корейский', 'eo': 'korea', 'ja': '韓国語', 'sr_Latn': 'korejski', 'sv': 'koreanska', 'da': 'koreansk', 'id': 'Korea', 'fr': 'coréen', 'es': 'coreano', 'nn': 'koreansk', 'en': 'Korean', }, 'lt': { '_native': 'lietuvių', 'zh_CN': '立陶宛语', 'is': 'litháíska', 'et': 'leedu', 'sr': 'литвански', 'nl': 'Litouws', 'sl': 'litovščina', 'fa': 'لیتوانیایی', 'zh_TW': '立陶宛文', 'bg': 'литовски', 'gl': 'lituano', 'lt': 'lietuvių', 'eu': 'lituaniera', 'he': 'ליטאית', 'pl': 'litewski', 'sk': 'litovčina', 'cs': 'litevština', 'ka': 'ლიეტუვური', 'de': 'Litauisch', 'hu': 'litván', 'ca': 'lituà', 'ar': 'الليتوانية', 'ro': 'lituaniană', 'fo': 'litaviskt', 'tr': 'Litvanca', 'nb': 'litauisk', 'pt': 'lituano', 'it': 'lituano', 'uk': 'литовська', 'fi': 'liettua', 'ko': '리투아니아어', 'hr': 'litavski', 'vi': 'Tiếng Litva', 'pt_BR': 'lituano', 'el': 'Λιθουανικά', 'ru': 'литовский', 'eo': 'litova', 'ja': 'リトアニア語', 'sr_Latn': 'litvanski', 'sv': 'litauiska', 'da': 'litauisk', 'id': 'Lituania', 'fr': 'lituanien', 'es': 'lituano', 'nn': 'litauisk', 'en': 'Lithuanian', }, 'nb': { '_native': 'norsk bokmål', 'zh_CN': '书面挪威语', 'is': 'norskt bókmál', 'et': 'norra bokmål', 'sr': 'норвешки букмол', 'nl': 'Noors - Bokmål', 'sl': 'knjižna norveščina', 'fa': 'نروژی بوک‌مُل', 'zh_TW': '書面挪威文', 'bg': 'норвежки (букмол)', 'gl': 'noruegués bokmål', 'lt': 'norvegų bukmolas', 'eu': 'bokmål (norvegiera)', 'he': 'נורווגית ספרותית', 'pl': 'norweski (bokmål)', 'sk': 'nórčina (bokmal)', 'cs': 'norština (bokmål)', 'ka': 'ნორვეგიული ბუკმოლი', 'de': 'Norwegisch (Bokmål)', 'hu': 'norvég (bokmål)', 'ca': 'noruec bokmål', 'ar': 'النرويجية بوكمال', 'ro': 'norvegiană bokmål', 'fo': 'norskt bókmál', 'tr': 'Norveççe Bokmål', 'nb': 'norsk bokmål', 'pt': 'bokmål norueguês', 'it': 'norvegese bokmål', 'uk': 'норвезька (букмол)', 'fi': 'norjan bokmål', 'ko': '노르웨이어(보크말)', 'hr': 'norveški bokmål', 'vi': 'Tiếng Na Uy (Bokmål)', 'pt_BR': 'bokmål norueguês', 'el': 'Νορβηγικά Μποκμάλ', 'ru': 'норвежский букмол', 'eo': 'dannorvega', 'ja': 'ノルウェー語(ブークモール)', 'sr_Latn': 'norveški bukmol', 'sv': 'norskt bokmål', 'da': 'bokmål', 'id': 'Bokmål Norwegia', 'fr': 'norvégien bokmål', 'es': 'noruego bokmal', 'nn': 'norsk bokmål', 'en': 'Norwegian Bokmål', }, 'nl': { '_native': 'Nederlands', 'zh_CN': '荷兰语', 'is': 'hollenska', 'et': 'hollandi', 'sr': 'холандски', 'nl': 'Nederlands', 'sl': 'nizozemščina', 'fa': 'هلندی', 'zh_TW': '荷蘭文', 'bg': 'нидерландски', 'gl': 'neerlandés', 'lt': 'olandų', 'eu': 'nederlandera', 'he': 'הולנדית', 'pl': 'niderlandzki', 'sk': 'holandčina', 'cs': 'nizozemština', 'ka': 'ნიდერლანდური', 'de': 'Niederländisch', 'hu': 'holland', 'ca': 'neerlandès', 'ar': 'الهولندية', 'ro': 'neerlandeză', 'fo': 'hálendskt', 'tr': 'Felemenkçe', 'nb': 'nederlandsk', 'pt': 'holandês', 'it': 'olandese', 'uk': 'нідерландська', 'fi': 'hollanti', 'ko': '네덜란드어', 'hr': 'nizozemski', 'vi': 'Tiếng Hà Lan', 'pt_BR': 'holandês', 'el': 'Ολλανδικά', 'ru': 'нидерландский', 'eo': 'nederlanda', 'ja': 'オランダ語', 'sr_Latn': 'holandski', 'sv': 'nederländska', 'da': 'nederlandsk', 'id': 'Belanda', 'fr': 'néerlandais', 'es': 'neerlandés', 'nn': 'nederlandsk', 'en': 'Dutch', }, 'nn': { '_native': 'norsk nynorsk', 'zh_CN': '挪威尼诺斯克语', 'is': 'nýnorska', 'et': 'uusnorra', 'sr': 'норвешки нинорск', 'nl': 'Noors - Nynorsk', 'sl': 'novonorveščina', 'fa': 'نروژی نی‌نُشک', 'zh_TW': '新挪威文', 'bg': 'норвежки (нюношк)', 'gl': 'noruegués nynorsk', 'lt': 'naujoji norvegų', 'eu': 'nynorsk (norvegiera)', 'he': 'נורווגית חדשה', 'pl': 'norweski (nynorsk)', 'sk': 'nórčina (nynorsk)', 'cs': 'norština (nynorsk)', 'ka': 'ნორვეგიული ნიუნორსკი', 'de': 'Norwegisch (Nynorsk)', 'hu': 'norvég (nynorsk)', 'ca': 'noruec nynorsk', 'ar': 'النرويجية نينورسك', 'ro': 'norvegiană nynorsk', 'fo': 'nýnorskt', 'tr': 'Norveççe Nynorsk', 'nb': 'norsk nynorsk', 'pt': 'nynorsk norueguês', 'it': 'norvegese nynorsk', 'uk': 'норвезька (нюношк)', 'fi': 'norjan nynorsk', 'ko': '노르웨이어(니노르스크)', 'hr': 'norveški nynorsk', 'vi': 'Tiếng Na Uy (Nynorsk)', 'pt_BR': 'nynorsk norueguês', 'el': 'Νορβηγικά Νινόρσκ', 'ru': 'нюнорск', 'eo': 'novnorvega', 'ja': 'ノルウェー語(ニーノシュク)', 'sr_Latn': 'norveški ninorsk', 'sv': 'nynorska', 'da': 'nynorsk', 'id': 'Nynorsk Norwegia', 'fr': 'norvégien nynorsk', 'es': 'noruego nynorsk', 'nn': 'norsk nynorsk', 'en': 'Norwegian Nynorsk', }, 'pl': { '_native': 'polski', 'zh_CN': '波兰语', 'is': 'pólska', 'et': 'poola', 'sr': 'пољски', 'nl': 'Pools', 'sl': 'poljščina', 'fa': 'لهستانی', 'zh_TW': '波蘭文', 'bg': 'полски', 'gl': 'polaco', 'lt': 'lenkų', 'eu': 'poloniera', 'he': 'פולנית', 'pl': 'polski', 'sk': 'poľština', 'cs': 'polština', 'ka': 'პოლონური', 'de': 'Polnisch', 'hu': 'lengyel', 'ca': 'polonès', 'ar': 'البولندية', 'ro': 'poloneză', 'fo': 'pólskt', 'tr': 'Lehçe', 'nb': 'polsk', 'pt': 'polonês', 'it': 'polacco', 'uk': 'польська', 'fi': 'puola', 'ko': '폴란드어', 'hr': 'poljski', 'vi': 'Tiếng Ba Lan', 'pt_BR': 'polonês', 'el': 'Πολωνικά', 'ru': 'польский', 'eo': 'pola', 'ja': 'ポーランド語', 'sr_Latn': 'poljski', 'sv': 'polska', 'da': 'polsk', 'id': 'Polski', 'fr': 'polonais', 'es': 'polaco', 'nn': 'polsk', 'en': 'Polish', }, 'pt': { '_native': 'português', 'zh_CN': '葡萄牙语', 'is': 'portúgalska', 'et': 'portugali', 'sr': 'португалски', 'nl': 'Portugees', 'sl': 'portugalščina', 'fa': 'پرتغالی', 'zh_TW': '葡萄牙文', 'bg': 'португалски', 'gl': 'portugués', 'lt': 'portugalų', 'eu': 'portugesa', 'he': 'פורטוגזית', 'pl': 'portugalski', 'sk': 'portugalčina', 'cs': 'portugalština', 'ka': 'პორტუგალიური', 'de': 'Portugiesisch', 'hu': 'portugál', 'ca': 'portuguès', 'ar': 'البرتغالية', 'ro': 'portugheză', 'fo': 'portugiskiskt', 'tr': 'Portekizce', 'nb': 'portugisisk', 'pt': 'português', 'it': 'portoghese', 'uk': 'португальська', 'fi': 'portugali', 'ko': '포르투갈어', 'hr': 'portugalski', 'vi': 'Tiếng Bồ Đào Nha', 'pt_BR': 'português', 'el': 'Πορτογαλικά', 'ru': 'португальский', 'eo': 'portugala', 'ja': 'ポルトガル語', 'sr_Latn': 'portugalski', 'sv': 'portugisiska', 'da': 'portugisisk', 'id': 'Portugis', 'fr': 'portugais', 'es': 'portugués', 'nn': 'portugisisk', 'en': 'Portuguese', }, 'pt_BR': { '_native': 'português (Brasil)', 'zh_CN': '葡萄牙语 (巴西)', 'is': 'portúgalska (Brasilía)', 'et': 'portugali (Brasiilia)', 'sr': 'португалски (Бразил)', 'nl': 'Portugees (Brazilië)', 'sl': 'portugalščina (Brazilija)', 'fa': 'پرتغالی (برزیل)', 'zh_TW': '葡萄牙文 (巴西)', 'bg': 'португалски (Бразилия)', 'gl': 'portugués (Brasil)', 'lt': 'portugalų (Brazilija)', 'eu': 'portugesa (Brasil)', 'he': 'פורטוגזית (ברזיל)', 'pl': 'portugalski (Brazylia)', 'sk': 'portugalčina (Brazília)', 'cs': 'portugalština (Brazílie)', 'ka': 'პორტუგალიური (ბრაზილია)', 'de': 'Portugiesisch (Brasilien)', 'hu': 'portugál (Brazília)', 'ca': 'portuguès (Brasil)', 'ar': 'البرتغالية (البرازيل)', 'ro': 'portugheză (Brazilia)', 'fo': 'portugiskiskt (Brasil)', 'tr': 'Portekizce (Brezilya)', 'nb': 'portugisisk (Brasil)', 'pt': 'português (Brasil)', 'it': 'portoghese (Brasile)', 'uk': 'португальська (Бразилія)', 'fi': 'portugali (Brasilia)', 'ko': '포르투갈어 (브라질)', 'hr': 'portugalski (Brazil)', 'vi': 'Tiếng Bồ Đào Nha (Brazil)', 'pt_BR': 'português (Brasil)', 'el': 'Πορτογαλικά (Βραζιλία)', 'ru': 'португальский (Бразилия)', 'eo': 'portugala (Brazilo)', 'ja': 'ポルトガル語 (ブラジル)', 'sr_Latn': 'portugalski (Brazil)', 'sv': 'portugisiska (Brasilien)', 'da': 'portugisisk (Brasilien)', 'id': 'Portugis (Brasil)', 'fr': 'portugais (Brésil)', 'es': 'portugués (Brasil)', 'nn': 'portugisisk (Brasil)', 'en': 'Portuguese (Brazil)', }, 'ro': { '_native': 'română', 'zh_CN': '罗马尼亚语', 'is': 'rúmenska', 'et': 'rumeenia', 'sr': 'румунски', 'nl': 'Roemeens', 'sl': 'romunščina', 'fa': 'رومانیایی', 'zh_TW': '羅馬尼亞文', 'bg': 'румънски', 'gl': 'romanés', 'lt': 'rumunų', 'eu': 'errumaniera', 'he': 'רומנית', 'pl': 'rumuński', 'sk': 'rumunčina', 'cs': 'rumunština', 'ka': 'რუმინული', 'de': 'Rumänisch', 'hu': 'román', 'ca': 'romanès', 'ar': 'الرومانية', 'ro': 'română', 'fo': 'rumenskt', 'tr': 'Rumence', 'nb': 'rumensk', 'pt': 'romeno', 'it': 'rumeno', 'uk': 'румунська', 'fi': 'romania', 'ko': '루마니아어', 'hr': 'rumunjski', 'vi': 'Tiếng Romania', 'pt_BR': 'romeno', 'el': 'Ρουμανικά', 'ru': 'румынский', 'eo': 'rumana', 'ja': 'ルーマニア語', 'sr_Latn': 'rumunski', 'sv': 'rumänska', 'da': 'rumænsk', 'id': 'Rumania', 'fr': 'roumain', 'es': 'rumano', 'nn': 'rumensk', 'en': 'Romanian', }, 'ru': { '_native': 'русский', 'zh_CN': '俄语', 'is': 'rússneska', 'et': 'vene', 'sr': 'руски', 'nl': 'Russisch', 'sl': 'ruščina', 'fa': 'روسی', 'zh_TW': '俄文', 'bg': 'руски', 'gl': 'ruso', 'lt': 'rusų', 'eu': 'errusiera', 'he': 'רוסית', 'pl': 'rosyjski', 'sk': 'ruština', 'cs': 'ruština', 'ka': 'რუსული', 'de': 'Russisch', 'hu': 'orosz', 'ca': 'rus', 'ar': 'الروسية', 'ro': 'rusă', 'fo': 'russiskt', 'tr': 'Rusça', 'nb': 'russisk', 'pt': 'russo', 'it': 'russo', 'uk': 'російська', 'fi': 'venäjä', 'ko': '러시아어', 'hr': 'ruski', 'vi': 'Tiếng Nga', 'pt_BR': 'russo', 'el': 'Ρωσικά', 'ru': 'русский', 'eo': 'rusa', 'ja': 'ロシア語', 'sr_Latn': 'ruski', 'sv': 'ryska', 'da': 'russisk', 'id': 'Rusia', 'fr': 'russe', 'es': 'ruso', 'nn': 'russisk', 'en': 'Russian', }, 'sk': { '_native': 'slovenčina', 'zh_CN': '斯洛伐克语', 'is': 'slóvakíska', 'et': 'slovaki', 'sr': 'словачки', 'nl': 'Slowaaks', 'sl': 'slovaščina', 'fa': 'اسلواکی', 'zh_TW': '斯洛伐克文', 'bg': 'словашки', 'gl': 'eslovaco', 'lt': 'slovakų', 'eu': 'eslovakiera', 'he': 'סלובקית', 'pl': 'słowacki', 'sk': 'slovenčina', 'cs': 'slovenština', 'ka': 'სლოვაკური', 'de': 'Slowakisch', 'hu': 'szlovák', 'ca': 'eslovac', 'ar': 'السلوفاكية', 'ro': 'slovacă', 'fo': 'slovakiskt', 'tr': 'Slovakça', 'nb': 'slovakisk', 'pt': 'eslovaco', 'it': 'slovacco', 'uk': 'словацька', 'fi': 'slovakki', 'ko': '슬로바키아어', 'hr': 'slovački', 'vi': 'Tiếng Slovak', 'pt_BR': 'eslovaco', 'el': 'Σλοβακικά', 'ru': 'словацкий', 'eo': 'slovaka', 'ja': 'スロバキア語', 'sr_Latn': 'slovački', 'sv': 'slovakiska', 'da': 'slovakisk', 'id': 'Slovak', 'fr': 'slovaque', 'es': 'eslovaco', 'nn': 'slovakisk', 'en': 'Slovak', }, 'sl': { '_native': 'slovenščina', 'zh_CN': '斯洛文尼亚语', 'is': 'slóvenska', 'et': 'sloveeni', 'sr': 'словеначки', 'nl': 'Sloveens', 'sl': 'slovenščina', 'fa': 'اسلوونیایی', 'zh_TW': '斯洛維尼亞文', 'bg': 'словенски', 'gl': 'esloveno', 'lt': 'slovėnų', 'eu': 'esloveniera', 'he': 'סלובנית', 'pl': 'słoweński', 'sk': 'slovinčina', 'cs': 'slovinština', 'ka': 'სლოვენური', 'de': 'Slowenisch', 'hu': 'szlovén', 'ca': 'eslovè', 'ar': 'السلوفانية', 'ro': 'slovenă', 'fo': 'slovenskt', 'tr': 'Slovence', 'nb': 'slovensk', 'pt': 'esloveno', 'it': 'sloveno', 'uk': 'словенська', 'fi': 'sloveeni', 'ko': '슬로베니아어', 'hr': 'slovenski', 'vi': 'Tiếng Slovenia', 'pt_BR': 'esloveno', 'el': 'Σλοβενικά', 'ru': 'словенский', 'eo': 'slovena', 'ja': 'スロベニア語', 'sr_Latn': 'slovenački', 'sv': 'slovenska', 'da': 'slovensk', 'id': 'Slovenia', 'fr': 'slovène', 'es': 'esloveno', 'nn': 'slovensk', 'en': 'Slovenian', }, 'sr': { '_native': 'српски', 'zh_CN': '塞尔维亚语', 'is': 'serbneska', 'et': 'serbia', 'sr': 'српски', 'nl': 'Servisch', 'sl': 'srbščina', 'fa': 'صربی', 'zh_TW': '塞爾維亞文', 'bg': 'сръбски', 'gl': 'serbio', 'lt': 'serbų', 'eu': 'serbiera', 'he': 'סרבית', 'pl': 'serbski', 'sk': 'srbčina', 'cs': 'srbština', 'ka': 'სერბული', 'de': 'Serbisch', 'hu': 'szerb', 'ca': 'serbi', 'ar': 'الصربية', 'ro': 'sârbă', 'fo': 'serbiskt', 'tr': 'Sırpça', 'nb': 'serbisk', 'pt': 'sérvio', 'it': 'serbo', 'uk': 'сербська', 'fi': 'serbia', 'ko': '세르비아어', 'hr': 'srpski', 'vi': 'Tiếng Serbia', 'pt_BR': 'sérvio', 'el': 'Σερβικά', 'ru': 'сербский', 'eo': 'serba', 'ja': 'セルビア語', 'sr_Latn': 'srpski', 'sv': 'serbiska', 'da': 'serbisk', 'id': 'Serbia', 'fr': 'serbe', 'es': 'serbio', 'nn': 'serbisk', 'en': 'Serbian', }, 'sr_Latn': { '_native': 'srpski (latinica)', 'zh_CN': '塞尔维亚语 (拉丁文)', 'is': 'serbneska (latneskt)', 'et': 'serbia (ladina)', 'sr': 'српски (латиница)', 'nl': 'Servisch (Latijns)', 'sl': 'srbščina (latinica)', 'fa': 'صربی (لاتین)', 'zh_TW': '塞爾維亞文 (拉丁字母)', 'bg': 'сръбски (латиница)', 'gl': 'serbio (latino)', 'lt': 'serbų (lotynų)', 'eu': 'serbiera (latinoa)', 'he': 'סרבית (לטיני)', 'pl': 'serbski (łacińskie)', 'sk': 'srbčina (latinka)', 'cs': 'srbština (latinka)', 'ka': 'სერბული (ლათინური)', 'de': 'Serbisch (Lateinisch)', 'hu': 'szerb (Latin)', 'ca': 'serbi (llatí)', 'ar': 'الصربية (اللاتينية)', 'ro': 'sârbă (latină)', 'fo': 'serbiskt (latínskt)', 'tr': 'Sırpça (Latin)', 'nb': 'serbisk (latinsk)', 'pt': 'sérvio (latim)', 'it': 'serbo (latino)', 'uk': 'сербська (латиниця)', 'fi': 'serbia (latinalainen)', 'ko': '세르비아어 (로마자)', 'hr': 'srpski (latinica)', 'vi': 'Tiếng Serbia (Chữ La tinh)', 'pt_BR': 'sérvio (latim)', 'el': 'Σερβικά (Λατινικό)', 'ru': 'сербский (латиница)', 'eo': 'serba (latina)', 'ja': 'セルビア語 (ラテン文字)', 'sr_Latn': 'srpski (latinica)', 'sv': 'serbiska (latinska)', 'da': 'serbisk (latinsk)', 'id': 'Serbia (Latin)', 'fr': 'serbe (latin)', 'es': 'serbio (latino)', 'nn': 'serbisk (latinsk)', 'en': 'Serbian (Latin)', }, 'sv': { '_native': 'svenska', 'zh_CN': '瑞典语', 'is': 'sænska', 'et': 'rootsi', 'sr': 'шведски', 'nl': 'Zweeds', 'sl': 'švedščina', 'fa': 'سوئدی', 'zh_TW': '瑞典文', 'bg': 'шведски', 'gl': 'sueco', 'lt': 'švedų', 'eu': 'suediera', 'he': 'שוודית', 'pl': 'szwedzki', 'sk': 'švédčina', 'cs': 'švédština', 'ka': 'შვედური', 'de': 'Schwedisch', 'hu': 'svéd', 'ca': 'suec', 'ar': 'السويدية', 'ro': 'suedeză', 'fo': 'svenskt', 'tr': 'İsveççe', 'nb': 'svensk', 'pt': 'sueco', 'it': 'svedese', 'uk': 'шведська', 'fi': 'ruotsi', 'ko': '스웨덴어', 'hr': 'švedski', 'vi': 'Tiếng Thụy Điển', 'pt_BR': 'sueco', 'el': 'Σουηδικά', 'ru': 'шведский', 'eo': 'sveda', 'ja': 'スウェーデン語', 'sr_Latn': 'švedski', 'sv': 'svenska', 'da': 'svensk', 'id': 'Swedia', 'fr': 'suédois', 'es': 'sueco', 'nn': 'svensk', 'en': 'Swedish', }, 'tr': { '_native': 'Türkçe', 'zh_CN': '土耳其语', 'is': 'tyrkneska', 'et': 'türgi', 'sr': 'турски', 'nl': 'Turks', 'sl': 'turščina', 'fa': 'ترکی استانبولی', 'zh_TW': '土耳其文', 'bg': 'турски', 'gl': 'turco', 'lt': 'turkų', 'eu': 'turkiera', 'he': 'טורקית', 'pl': 'turecki', 'sk': 'turečtina', 'cs': 'turečtina', 'ka': 'თურქული', 'de': 'Türkisch', 'hu': 'török', 'ca': 'turc', 'ar': 'التركية', 'ro': 'turcă', 'fo': 'turkiskt', 'tr': 'Türkçe', 'nb': 'tyrkisk', 'pt': 'turco', 'it': 'turco', 'uk': 'турецька', 'fi': 'turkki', 'ko': '튀르키예어', 'hr': 'turski', 'vi': 'Tiếng Thổ Nhĩ Kỳ', 'pt_BR': 'turco', 'el': 'Τουρκικά', 'ru': 'турецкий', 'eo': 'turka', 'ja': 'トルコ語', 'sr_Latn': 'turski', 'sv': 'turkiska', 'da': 'tyrkisk', 'id': 'Turki', 'fr': 'turc', 'es': 'turco', 'nn': 'tyrkisk', 'en': 'Turkish', }, 'uk': { '_native': 'українська', 'zh_CN': '乌克兰语', 'is': 'úkraínska', 'et': 'ukraina', 'sr': 'украјински', 'nl': 'Oekraïens', 'sl': 'ukrajinščina', 'fa': 'اوکراینی', 'zh_TW': '烏克蘭文', 'bg': 'украински', 'gl': 'ucraíno', 'lt': 'ukrainiečių', 'eu': 'ukrainera', 'he': 'אוקראינית', 'pl': 'ukraiński', 'sk': 'ukrajinčina', 'cs': 'ukrajinština', 'ka': 'უკრაინული', 'de': 'Ukrainisch', 'hu': 'ukrán', 'ca': 'ucraïnès', 'ar': 'الأوكرانية', 'ro': 'ucraineană', 'fo': 'ukrainskt', 'tr': 'Ukraynaca', 'nb': 'ukrainsk', 'pt': 'ucraniano', 'it': 'ucraino', 'uk': 'українська', 'fi': 'ukraina', 'ko': '우크라이나어', 'hr': 'ukrajinski', 'vi': 'Tiếng Ukraina', 'pt_BR': 'ucraniano', 'el': 'Ουκρανικά', 'ru': 'украинский', 'eo': 'ukraina', 'ja': 'ウクライナ語', 'sr_Latn': 'ukrajinski', 'sv': 'ukrainska', 'da': 'ukrainsk', 'id': 'Ukraina', 'fr': 'ukrainien', 'es': 'ucraniano', 'nn': 'ukrainsk', 'en': 'Ukrainian', }, 'vi': { '_native': 'Tiếng Việt', 'zh_CN': '越南语', 'is': 'víetnamska', 'et': 'vietnami', 'sr': 'вијетнамски', 'nl': 'Vietnamees', 'sl': 'vietnamščina', 'fa': 'ویتنامی', 'zh_TW': '越南文', 'bg': 'виетнамски', 'gl': 'vietnamita', 'lt': 'vietnamiečių', 'eu': 'vietnamera', 'he': 'וייטנאמית', 'pl': 'wietnamski', 'sk': 'vietnamčina', 'cs': 'vietnamština', 'ka': 'ვიეტნამური', 'de': 'Vietnamesisch', 'hu': 'vietnámi', 'ca': 'vietnamita', 'ar': 'الفيتنامية', 'ro': 'vietnameză', 'fo': 'vjetnamesiskt', 'tr': 'Vietnamca', 'nb': 'vietnamesisk', 'pt': 'vietnamita', 'it': 'vietnamita', 'uk': 'вʼєтнамська', 'fi': 'vietnam', 'ko': '베트남어', 'hr': 'vijetnamski', 'vi': 'Tiếng Việt', 'pt_BR': 'vietnamita', 'el': 'Βιετναμικά', 'ru': 'вьетнамский', 'eo': 'vjetnama', 'ja': 'ベトナム語', 'sr_Latn': 'vijetnamski', 'sv': 'vietnamesiska', 'da': 'vietnamesisk', 'id': 'Vietnam', 'fr': 'vietnamien', 'es': 'vietnamita', 'nn': 'vietnamesisk', 'en': 'Vietnamese', }, 'zh_CN': { '_native': '中文 (简体, 中国)', 'zh_CN': '中文 (简体, 中国)', 'is': 'kínverska (einfaldað, Kína)', 'et': 'hiina (lihtsustatud, Hiina)', 'sr': 'кинески (поједностављено кинеско писмо, Кина)', 'nl': 'Chinees (vereenvoudigd, China)', 'sl': 'kitajščina (poenostavljena pisava, Kitajska)', 'fa': 'چینی (ساده‌شده, چین)', 'zh_TW': '中文 (簡體, 中國)', 'bg': 'китайски (опростена, Китай)', 'gl': 'chinés (simplificado, China)', 'lt': 'kinų (supaprastinti, Kinija)', 'eu': 'txinera (sinplifikatua, Txina)', 'he': 'סינית (פשוט, סין)', 'pl': 'chiński (uproszczone, Chiny)', 'sk': 'čínština (zjednodušené, Čína)', 'cs': 'čínština (zjednodušené, Čína)', 'ka': 'ჩინური (გამარტივებული, ჩინეთი)', 'de': 'Chinesisch (Vereinfacht, China)', 'hu': 'kínai (Egyszerűsített, Kína)', 'ca': 'xinès (simplificat, Xina)', 'ar': 'الصينية (المبسطة, الصين)', 'ro': 'chineză (simplificată, China)', 'fo': 'kinesiskt (einkult, Kina)', 'tr': 'Çince (Basitleştirilmiş, Çin)', 'nb': 'kinesisk (forenklet, Kina)', 'pt': 'chinês (simplificado, China)', 'it': 'cinese (semplificato, Cina)', 'uk': 'китайська (спрощена, Китай)', 'fi': 'kiina (yksinkertaistettu, Kiina)', 'ko': '중국어 (간체, 중국)', 'hr': 'kineski (pojednostavljeno pismo, Kina)', 'vi': 'Tiếng Trung (Giản thể, Trung Quốc)', 'pt_BR': 'chinês (simplificado, China)', 'el': 'Κινεζικά (Απλοποιημένο, Κίνα)', 'ru': 'китайский (упрощенная, Китай)', 'eo': 'ĉina (simpligita, Ĉinujo)', 'ja': '中国語 (簡体字, 中国)', 'sr_Latn': 'kineski (pojednostavljeno kinesko pismo, Kina)', 'sv': 'kinesiska (förenklad, Kina)', 'da': 'kinesisk (forenklet, Kina)', 'id': 'Tionghoa (Sederhana, Tiongkok)', 'fr': 'chinois (simplifié, Chine)', 'es': 'chino (simplificado, China)', 'nn': 'kinesisk (forenkla, Kina)', 'en': 'Chinese (Simplified, China)', }, 'zh_TW': { '_native': '中文 (繁體, 台灣)', 'zh_CN': '中文 (繁体, 台湾)', 'is': 'kínverska (hefðbundið, Taívan)', 'et': 'hiina (traditsiooniline, Taiwan)', 'sr': 'кинески (традиционално кинеско писмо, Тајван)', 'nl': 'Chinees (traditioneel, Taiwan)', 'sl': 'kitajščina (tradicionalna pisava, Tajvan)', 'fa': 'چینی (سنتی, تایوان)', 'zh_TW': '中文 (繁體, 台灣)', 'bg': 'китайски (традиционна, Тайван)', 'gl': 'chinés (tradicional, Taiwán)', 'lt': 'kinų (tradiciniai, Taivanas)', 'eu': 'txinera (tradizionala, Taiwan)', 'he': 'סינית (מסורתי, טייוואן)', 'pl': 'chiński (tradycyjne, Tajwan)', 'sk': 'čínština (tradičné, Taiwan)', 'cs': 'čínština (tradiční, Tchaj-wan)', 'ka': 'ჩინური (ტრადიციული, ტაივანი)', 'de': 'Chinesisch (Traditionell, Taiwan)', 'hu': 'kínai (Hagyományos, Tajvan)', 'ca': 'xinès (tradicional, Taiwan)', 'ar': 'الصينية (التقليدية, تايوان)', 'ro': 'chineză (tradițională, Taiwan)', 'fo': 'kinesiskt (vanligt, Taivan)', 'tr': 'Çince (Geleneksel, Tayvan)', 'nb': 'kinesisk (tradisjonell, Taiwan)', 'pt': 'chinês (tradicional, Taiwan)', 'it': 'cinese (tradizionale, Taiwan)', 'uk': 'китайська (традиційна, Тайвань)', 'fi': 'kiina (perinteinen, Taiwan)', 'ko': '중국어 (번체, 대만)', 'hr': 'kineski (tradicionalno pismo, Tajvan)', 'vi': 'Tiếng Trung (Phồn thể, Đài Loan)', 'pt_BR': 'chinês (tradicional, Taiwan)', 'el': 'Κινεζικά (Παραδοσιακό, Ταϊβάν)', 'ru': 'китайский (традиционная, Тайвань)', 'eo': 'ĉina (tradicia, Tajvano)', 'ja': '中国語 (繁体字, 台湾)', 'sr_Latn': 'kineski (tradicionalno kinesko pismo, Tajvan)', 'sv': 'kinesiska (traditionell, Taiwan)', 'da': 'kinesisk (traditionelt, Taiwan)', 'id': 'Tionghoa (Tradisional, Taiwan)', 'fr': 'chinois (traditionnel, Taïwan)', 'es': 'chino (tradicional, Taiwán)', 'nn': 'kinesisk (tradisjonell, Taiwan)', 'en': 'Chinese (Traditional, Taiwan)', }, } completeness = { 'eo': 100, 'cs': 100, 'de': 100, 'hr': 24, 'he': 82, 'it': 100, 'pt': 100, 'zh_CN': 100, 'ja': 100, 'ru': 100, 'hu': 100, 'da': 100, 'sr_Latn': 55, 'vi': 35, 'ca': 82, 'et': 100, 'lt': 61, 'gl': 100, 'eu': 86, 'ko': 55, 'zh_TW': 82, 'is': 44, 'id': 97, 'nb': 62, 'fo': 18, 'fi': 88, 'tr': 100, 'el': 90, 'sv': 100, 'ar': 45, 'bg': 54, 'sl': 66, 'fr': 100, 'es': 100, 'nn': 46, 'sr': 57, 'nl': 99, 'fa': 72, 'uk': 100, 'sk': 55, 'ro': 100, 'ka': 23, 'pt_BR': 62, 'pl': 100, 'en': 100, } backintime-1.6.1/common/logger.py000066400000000000000000000061561514264426600167700ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import syslog import os import pwd import sys import atexit import bcolors DEBUG = False # Set to "True" when passing "--debug" as cmd arg SYSLOG_IDENTIFIER = 'backintime' SYSLOG_MESSAGE_PREFIX = '' USER = pwd.getpwuid(os.getuid()).pw_name # Labels for the syslog levels _level_names = { syslog.LOG_INFO: 'INFO', syslog.LOG_WARNING: 'WARNING', syslog.LOG_ERR: 'ERROR', syslog.LOG_CRIT: 'CRITICAL', syslog.LOG_DEBUG: 'DEBUG', } syslog_id_suffix = '' def openlog(suffix: str): """Initialize the BIT logger system using syslog. Attention: Call it in each sub process that uses logging. """ global syslog_id_suffix syslog_id_suffix = suffix syslog.openlog(SYSLOG_IDENTIFIER) atexit.register(closelog) def changeProfile(profile_id, profile_name): global SYSLOG_MESSAGE_PREFIX SYSLOG_MESSAGE_PREFIX = f'{profile_name}({profile_id}) :: ' def closelog(): syslog.closelog() def _do_syslog(message: str, level: int) -> str: syslog.syslog(level, '{}: {}{}{}'.format( _level_names[level], f'{USER} ' if DEBUG else '', SYSLOG_MESSAGE_PREFIX, message )) def critical(msg, parent=None, traceDepth=0): if DEBUG: msg = _debugHeader(parent, traceDepth) + ' ' + msg print(f'{bcolors.CRITICAL}CRITICAL{bcolors.ENDC}: {msg}', file=sys.stderr) _do_syslog(msg, syslog.LOG_CRIT) def error(msg, parent=None, traceDepth=0): if DEBUG: msg = _debugHeader(parent, traceDepth) + ' ' + msg print(f'{bcolors.FAIL}ERROR{bcolors.ENDC}: {msg}', file=sys.stderr) _do_syslog(msg, syslog.LOG_ERR) def warning(msg, parent=None, traceDepth=0): if DEBUG: msg = _debugHeader(parent, traceDepth) + ' ' + msg print(f'{bcolors.WARNING}WARNING{bcolors.ENDC}: {msg}', file=sys.stderr) _do_syslog(msg, syslog.LOG_WARNING) def info(msg, parent=None, traceDepth=0): if DEBUG: msg = _debugHeader(parent, traceDepth) + ' ' + msg print(f'{bcolors.OKGREEN}INFO{bcolors.ENDC}: {msg}', file=sys.stderr) _do_syslog(msg, syslog.LOG_INFO) def debug(msg, parent=None, traceDepth=0): if not DEBUG: return msg = _debugHeader(parent, traceDepth) + ' ' + msg print(f'{bcolors.OKBLUE}DEBUG{bcolors.ENDC}: {msg}', file=sys.stderr) _do_syslog(msg, syslog.LOG_DEBUG) def _debugHeader(parent, traceDepth): frame = sys._getframe(2 + traceDepth) line = frame.f_lineno func = frame.f_code.co_name fdir, fname = os.path.split(frame.f_code.co_filename) fmodule = os.path.basename(fdir) fclass = f'{parent.__class__.__name__}.' if parent else '' return f'[{syslog_id_suffix}::{fmodule}/{fname}:{line} {fclass}{func}]' backintime-1.6.1/common/mount.py000066400000000000000000001205451514264426600166520ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # SPDX-FileCopyrightText: © 2012-2022 Taylor Raack # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """The mount API. The high-level mount API is :py:class:`Mount` and handles mount, umount, remount and checks for *Back In Time*. The low-level mount API is :py:class:`MountControl`. The latter can be used to create own mounting services via subclassing it. See the following example. Example: See this template to create your own mounting service by inheriting from :py:class:`MountControl`. All you need to do is: - Add your settings in ``qt/settingsdialog.py``. - Add settings in ``common/config.py``. - Use the following template class ``MountDummy``, rename and modify it to your needs. - Please use ``self.currentMountpoint`` as your local mountpoint. - Your class should inherit from :py:class:`mount.MountControl`. As real usage example see the two classes :py:class:`sshtools.SSH` and :py:class:`encfstools.EncFS_mount`. This is the template: :: class MountDummy(mount.MountControl): def __init__(self, *args, **kwargs): super(MountDummy, self).__init__(*args, **kwargs) self.all_kwargs = {} # First we need to map the settings. # If is in kwargs (e.g. if this class is called with # dummytools.Dummy( = ) this will map self. to # kwargs[]; else self. = from config # e.g. self.setattrKwargs(, , **kwargs) self.setattrKwargs( 'user', self.config.get_dummy_user(self.profile_id), **kwargs) self.setattrKwargs( 'host', self.config.get_dummy_host(self.profile_id), **kwargs) self.setattrKwargs( 'port', self.config.get_dummy_port(self.profile_id), **kwargs) self.setattrKwargs( 'password', self.config.password(self.parent, self.profile_id), store = False, **kwargs) self.setDefaultArgs() # If self.currentMountpoint is not the remote snapshot path # you can specify a subfolder of self.currentMountpoint for # the symlink self.symlink_subfolder = None self.mountproc = 'dummy' self.log_command = '%s: %s@%s' % (self.mode, self.user, self.host) def _mount(self): # Mount the service # Implement your mountprocess here. pass def _umount(self): # Umount the service # Implement your unmountprocess here. pass def preMountCheck(self, first_run = False): # Check what ever conditions must be given for the mount to be # done successful. # Raise MountException('Error description') if service can not mount # return True if everything is okay # all pre|post_[u]mount_check can also be used to prepare # things or clean up return True def postMountCheck(self): # Check if mount was successful # Raise MountException('Error description') if not return True def preUmountCheck(self): # Check if service is safe to umount # Raise MountException('Error description') if not return True def postUmountCheck(self): # Check if umount successful # Raise MountException('Error description') if not return True """ import getpass import json import os import subprocess from time import sleep from zlib import crc32 from pathlib import Path import config import logger import password import tools from exceptions import HashCollision, MountException class Mount: """ This is the high-level mount API. This will handle mount, umount, remount and checks on the low-level :py:class:`MountControl` subclass backends for BackInTime. If ``cfg`` is ``None`` this will load the default config. If ``profile_id`` is ``None`` it will use :py:func:`configfile.ConfigFileWithProfiles.currentProfile`. If the current profile uses Password-Cache and the Password-Cache is not running this will try to start it. Args: cfg (config.Config): Current config. profile_id (str): Profile ID to be used. tmp_mount (bool): If ``True`` mount to a temporary destination. parent (QWidget): Parent widget for QDialogs or ``None`` if there is no parent. Dev note (buhtz, 2026-01): Rename that class into something like MountOrchestrator or MountManager. """ def __init__(self, cfg=None, profile_id=None, tmp_mount=False, parent=None): self.config = cfg or config.Config() self.profile_id = profile_id or self.config.currentProfile() self.tmp_mount = tmp_mount self.parent = parent if self.config.passwordUseCache(self.profile_id): cache = password.Password_Cache(self.config) action = None running = cache.status() if not running: logger.debug('pw-cache is not running', self) action = 'start' if running and not cache.checkVersion(): logger.debug('pw-cache is running but is an old version', self) action = 'restart' bit = tools.which('backintime') if not action is None and not bit is None and len(bit): cmd = [bit, 'pw-cache', action] logger.debug(f'Call command: {cmd}', self) proc = subprocess.Popen( cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) if proc.returncode: logger.error( f'Failed to {action} pw-cache: {proc.returncode}', self) def get_backend(self, mode, **kwargs): mounttools = self.config.SNAPSHOT_MODES[mode][0] return mounttools( cfg=self.config, profile_id=self.profile_id, tmp_mount=self.tmp_mount, mode=mode, parent=self.parent, **kwargs) def mount(self, mode=None, check=True, **kwargs): """High-level `mount`. Check if the selected ``mode`` need to be mounted, select the low-level backend and mount it. Args: mode (str): Mode to use. One of 'local', 'ssh', 'local_encfs' or 'ssh_encfs'. check (bool): If ``True`` run :py:func:`MountControl.preMountCheck` before mounting. **kwargs: Keyword arguments paste to low-level :py:class:`MountControl` subclass backend. Returns: str: Hash ID used as mountpoint. Raises: exceptions.MountException: If a check failed. exceptions.HashCollision: If hash ID was used before but umount info wasn't identical. """ self.config.PLUGIN_MANAGER.load(cfg=self.config) self.config.PLUGIN_MANAGER.mount(self.profile_id) if mode is None: mode = self.config.snapshotsMode(self.profile_id) if self.config.SNAPSHOT_MODES[mode][0] is None: # mode doesn't need to mount return 'local' else: while True: # ??? try: backend = self.get_backend(mode, **kwargs) return backend.mount(check=check) except HashCollision as ex: logger.warning(str(ex), self) del backend check = False continue break def umount(self, hash_id=None): """High-level `unmount`. Unmount the low-level backend. This will read unmount infos written next to the mountpoint identified by ``hash_id`` and unmount it. Args: hash_id (bool): Hash ID used as mountpoint before that should get unmounted. Raises: exceptions.MountException: If a check failed. """ self.config.PLUGIN_MANAGER.load(cfg=self.config) self.config.PLUGIN_MANAGER.unmount(self.profile_id) if hash_id is None: hash_id = self.config.current_hash_id if hash_id == 'local': # mode doesn't need to umount return umount_info = os.path.join( self.config._LOCAL_MOUNT_ROOT, hash_id, 'umount') with open(umount_info, 'r') as f: data_string = f.read() f.close() kwargs = json.loads(data_string) mode = kwargs.pop('mode') mounttools = self.config.SNAPSHOT_MODES[mode][0] backend = mounttools(cfg=self.config, profile_id=self.profile_id, tmp_mount=self.tmp_mount, mode=mode, hash_id=hash_id, parent=self.parent, **kwargs) backend.umount() def preMountCheck(self, mode=None, first_run=False, **kwargs): """ High-level check. Run :py:func:`MountControl.preMountCheck` to check if all conditions for :py:func:`Mount.mount` are set. Should be called with ``first_run = True`` to check if new settings are correct before saving them. Args: mode (str): Mode to use. One of 'local', 'ssh', 'local_encfs' or 'ssh_encfs'. first_run (bool): Run intense checks that only need to run after changing settings but not every time before mounting. **kwargs: Keyword arguments paste to low-level :py:class:`MountControl` subclass backend. Returns: bool: ``True`` if all checks where okay. Raises: exceptions.MountException: If a check failed. """ if mode is None: mode = self.config.snapshotsMode(self.profile_id) # sshtools.SSH, encfstools.EncFS_mount, encfstools.EncFS_SSH Mounttools = self.config.SNAPSHOT_MODES[mode][0] # "local" mode if Mounttools is None: # mode doesn't need to mount return True backend = Mounttools(cfg=self.config, profile_id=self.profile_id, tmp_mount=self.tmp_mount, mode=mode, parent=self.parent, **kwargs) return backend.preMountCheck(first_run) def remount(self, new_profile_id, mode=None, hash_id=None, **kwargs): """ High-level `remount`. Unmount the old profile presented by ``hash_id`` and mount new profile ``new_profile_id`` with mode ``mode``. If old and new mounts are the same just add new symlinks and keep the mount. Args map to profiles:: new_profile_id <= new profile mode <= new profile kwargs <= new profile hash_id <= old profile self.profile_id <= old profile Args: new_profile_id (str): Profile ID that should get mounted mode (str): mode to use for new mount. One of 'local', 'ssh', 'local_encfs' or 'ssh_encfs' hash_id (str): Hash ID used as mountpoint on the old mount, that should get unmounted **kwargs: keyword arguments paste to low-level :py:class:`MountControl` subclass backend for the new mount Returns: str: Hash ID used as mountpoint Raises: exceptions.MountException: if a check failed exceptions.HashCollision: if Hash ID was used before but umount info wasn't identical """ if mode is None: mode = self.config.snapshotsMode(new_profile_id) if hash_id is None: hash_id = self.config.current_hash_id if self.config.SNAPSHOT_MODES[mode][0] is None: # new profile don't need to mount. self.umount(hash_id=hash_id) return 'local' if hash_id == 'local': # old profile don't need to umount. self.profile_id = new_profile_id return self.mount(mode=mode, **kwargs) mounttools = self.config.SNAPSHOT_MODES[mode][0] backend = mounttools( cfg=self.config, profile_id=new_profile_id, tmp_mount=self.tmp_mount, mode=mode, parent=self.parent, **kwargs ) if backend.compareRemount(hash_id): # profiles uses the same settings. just swap the symlinks backend.removeSymlink(profile_id=self.profile_id) backend.setSymlink(profile_id=new_profile_id, hash_id=hash_id) return hash_id else: # profiles are different. we need to umount and mount again self.umount(hash_id=hash_id) self.profile_id = new_profile_id return self.mount(mode=mode, **kwargs) def init_backend(self, mode=None, **kwargs): """ High-level init. Run :py:func:`MountControl.init_backend` to initiate the backend if not configured yet. Args: mode (str): mode to use. One of 'local', 'ssh', 'local_encfs' or 'ssh_encfs' **kwargs: keyword arguments paste to low-level :py:class:`MountControl` subclass backend Raises: exceptions.MountException: if init_backend failed """ if mode is None: mode = self.config.snapshotsMode(self.profile_id) if self.config.SNAPSHOT_MODES[mode][0] is None: # mode doesn't need to mount return True backend = self.get_backend(mode, **kwargs) return backend.init_backend() class MountControl: """This is the low-level mount API. This should be subclassed by backends. Subclasses should have its own ``__init__`` but **must** also call the inherited ``__init__``. See module description (:py:mod:`mount`) for a detailed example. You **must** overwrite methods: - :py:func:`MountControl._mount` You **can** overwrite methods: - :py:func:`MountControl._umount` - :py:func:`MountControl.preMountCheck` - :py:func:`MountControl.postMountCheck` - :py:func:`MountControl.preUmountCheck` - :py:func:`MountControl.postUmountCheck` These arguments (all of type :py:obj:`str`) **must** be defined in ``self`` namespace by subclassing ``__init__`` method: - ``mountproc``: process used to mount - ``log_command``: shortened form of mount command used in logs - ``symlink_subfolder``: mountpoint-subfolder which should be linked Args: cfg (config.Config): current config profile_id (str): profile ID that should be used hash_id (str): crc32 hash used to identify identical mountpoints tmp_mount (bool): if ``True`` mount to a temporary destination parent (QWidget): parent widget for QDialogs or ``None`` if there is no parent symlink (bool): if ``True`` set symlink to mountpoint mode (str): one of ``local``, ``local_encfs``, ``ssh`` or ``ssh_encfs`` hash_collision (int): global value used to prevent hash collisions on mountpoints Dev note (buhtz, 2026-01): Rename that class into something like MountController or MountBase """ def __init__(self, cfg=None, profile_id=None, hash_id=None, tmp_mount=False, parent=None, symlink=True, *args, **kwargs): # The following members should get valid values from the inheriting # class. self.mode = None self.log_command = None self.mountproc = None self.symlink_subfolder = None self.config = cfg or config.Config() self.profile_id = profile_id or self.config.currentProfile() self.tmp_mount = tmp_mount self.hash_id = hash_id self.parent = parent self.symlink = symlink self.local_host = self.config.host() self.local_user = getpass.getuser() self.pid = str(os.getpid()) self.all_kwargs = {} self.setattrKwargs( 'mode', self.config.snapshotsMode(self.profile_id), **kwargs) self.setattrKwargs( 'hash_collision', self.config.hashCollision(), **kwargs) def setDefaultArgs(self): """ Set some arguments which are necessary for all backends. ``self.all_kwargs`` need to be filled through :py:func:`setattrKwargs` before calling this. """ # self.destination should contain all arguments that are necessary for # mount. args = list(self.all_kwargs.keys()) self.destination = '%s:' % self.all_kwargs['mode'] logger.debug(f"{self.destination=}") args.remove('mode') args.sort() for arg in args: self.destination += ' %s' % self.all_kwargs[arg] # Unique id for every different mount settings. Similar settings even # in different profiles will generate the same hash_id and so share # the same mountpoint. if self.hash_id is None: self.hash_id = self.hash(self.destination) logger.debug(f"{self.hash_id=}") # e.g. ~/.local/share/backintime/mnt self.mount_root = self.config._LOCAL_MOUNT_ROOT self.snapshots_path = self.config.snapshotsPath( profile_id=self.profile_id, mode=self.mode, tmp_mount=self.tmp_mount) self.hash_id_path = self.hashIdPath() self.currentMountpoint = self.mountpoint() self.lock_path = self.lockPath() self.umount_info = self.umountInfoPath() def mount(self, check=True): """ Low-level `mount`. Set mountprocess lock and prepare mount, run checks and than call :py:func:`_mount` for the subclassed backend. Finally set mount lock and symlink and release mountprocess lock. Args: check (bool): If ``True`` run :py:func:`preMountCheck` before mounting. Returns: str: Hash ID used as mountpoint. Raises: exceptions.MountException: If a check failed. exceptions.HashCollision: If Hash ID was used before but umount info wasn't identical. """ self.createMountStructure() self.mountProcessLockAcquire() try: if self.mounted(): if not self.compareUmountInfo(): # We probably have a hash collision self.config.incrementHashCollision() raise HashCollision( f'Hash collision occurred in hash_id {self.hash_id}. ' 'Incrementing global value hash_collision and ' 'trying again.') logger.info('Mountpoint {} is already mounted' .format(self.currentMountpoint), self) else: if check: self.preMountCheck() self._mount() self.postMountCheck() logger.info( f'mount {self.log_command} on {self.currentMountpoint}', self) self.writeUmountInfo() except Exception: # ??? raise else: self.mountLockAquire() self.setSymlink() finally: self.mountProcessLockRelease() return self.hash_id def umount(self): """ Low-level `umount`. Set mountprocess lock, run umount checks and call :py:func:`_umount` for the subclassed backend. Finally release mount lock, remove symlink and release mountprocess lock. Raises: exceptions.MountException: if a check failed """ self.mountProcessLockAcquire() msg_begin = f'Mountpoint {self.currentMountpoint} ' try: if not os.path.isdir(self.hash_id_path): logger.info(msg_begin + 'does not exist.', self) else: if not self.mounted(): logger.info(msg_begin + 'is not mounted.', self) else: if self.mountLockCheck(): logger.info(msg_begin + 'still in use. Keep mounted.', self) else: self.preUmountCheck() self._umount() self.postUmountCheck() if os.listdir(self.currentMountpoint): logger.warning( msg_begin + 'not empty after unmount', self) else: logger.info( f'unmount {self.log_command} ' f'from {self.currentMountpoint}', self) except Exception: raise else: self.mountLockRelease() self.removeSymlink() finally: self.mountProcessLockRelease() def _mount(self): """ Backend mount method. This **must** be overwritten in the backend which subclasses :py:class:`MountControl`. """ raise NotImplementedError('_mount need to be overwritten in backend') def _umount(self): """ Unmount with ``fusermount -u`` for fuse based backends. This **can** be overwritten by backends which subclasses :py:class:`MountControl`. Raises: exceptions.MountException: If unmount failed. """ try: subprocess.check_call(['fusermount', '-u', self.currentMountpoint]) except subprocess.CalledProcessError as exc: raise MountException( _('Unable to unmount {mountprocess} from {mountpoint}.') .format(mountprocess=self.mountproc, mountpoint=self.currentMountpoint)) from exc def preMountCheck(self, first_run=False): """ Check what ever conditions must be given for the mount to be done successful. This **can** be overwritten in backends which subclasses :py:class:`MountControl`. Returns: bool: ``True`` if all checks where okay Raises: exceptions.MountException: if backend can not mount Note: This can also be used to prepare things before running :py:func:`_mount` """ return True def postMountCheck(self): """ Check if the mount was successful. This **can** be overwritten in backends which subclasses :py:class:`MountControl`. Returns: bool: ``True`` if all checks where okay Raises: exceptions.MountException: if backend wasn't mount successful Note: This can also be used to clean up after running :py:func:`_mount` """ return True def preUmountCheck(self): """ Check if backend is safe to umount. This **can** be overwritten in backends which subclasses :py:class:`MountControl`. Returns: bool: ``True`` if all checks where okay Raises: exceptions.MountException: if backend can not umount Note: This can also be used to prepare things before running :py:func:`_umount` """ return True def postUmountCheck(self): """ Check if unmount was successful. This **can** be overwritten in backends which subclasses :py:class:`MountControl`. Returns: bool: ``True`` if all checks where okay Raises: exceptions.MountException: if backend wasn't unmounted successful Note: This can also be used to clean up after running :py:func:`_umount` """ return True def checkFuse(self): """ Check if command in ``self.mountproc`` is installed. Raises: exceptions.MountException: If either command is not available. """ if not tools.checkCommand(self.mountproc): logger.debug(f'{self.mountproc} is missing', self) raise MountException( _('{command} not found. Please install it ' '(e.g. via "{installcommand}")').format( command=self.mountproc, installcommand=f"'apt-get install {self.mountproc}'") ) def mounted(self): """ Check if the mountpoint is already mounted. Returns: bool: ``True`` if mountpoint is mounted Raises: exceptions.MountException: if mountpoint is not mounted but also not empty """ if os.path.ismount(self.currentMountpoint): return True else: try: if os.listdir(self.currentMountpoint): raise MountException( _('Mountpoint {mntpoint} not empty.').format( mntpoint=self.currentMountpoint)) except FileNotFoundError: pass return False def createMountStructure(self): """ Create folders that are necessary for mounting. Folder structure in ``~/.local/share/backintime/mnt/`` (``self.mount_root``):: . ├── .lock <= mountprocess lock that will prevent │ different processes modifying │ mountpoints at one time │ ├── / <= ``self.hash_id_path`` will be │ │ shared by all profiles with the │ │ same mount settings │ │ │ ├── mountpoint/ <= ``self.currentMountpoint`` real │ │ mountpoint │ │ │ ├── umount <= ``self.umount_info`` json file with │ │ all necessary args for unmount │ │ │ └── locks/ <= ``self.lock_path`` for each process │ you have a ``.lock`` file │ ├── _/ <= sym-link to the right path. return │ by config.snapshotsPath (can be │ ../mnt//mount_point for ssh │ or ../mnt/// │ for fusesmb ...) │ └── tmp__/ <= sym-link for testing mountpoints in settingsdialog """ tools.mkdir(self.mount_root, 0o700) tools.mkdir(self.hash_id_path, 0o700) tools.mkdir(self.currentMountpoint, 0o700, False) tools.mkdir(self.lock_path, 0o700) def mountProcessLockAcquire(self, timeout=60): """ Create a short term lock only for blocking other processes changing mounts at the same time. Args: timeout (int): Wait ``timeout`` seconds before fail acquiring the lock. Raises: exceptions.MountException: If timed out. """ lock_path = self.mount_root lockSuffix = '.lock' # e.g. ~/.local/share/backintime/mnt/123456.lock lock = os.path.join(lock_path, self.pid + lockSuffix) # Every second count = 0 while self.checkLocks(lock_path, lockSuffix): count += 1 if count == timeout: raise MountException('Mountprocess lock timeout') sleep(1) logger.debug(f'Acquire mountprocess lock {lock}', self) with open(lock, 'w') as f: f.write(self.pid) def mountProcessLockRelease(self): """Remove mountprocess lock.""" lock_path = self.mount_root lockSuffix = '.lock' lock = os.path.join(lock_path, self.pid + lockSuffix) logger.debug(f'Release mountprocess lock {lock}', self) if os.path.exists(lock): os.remove(lock) def mountLockAquire(self): """ Create a lock file for a mountpoint to prevent unmounting as long as this process is running. """ lockSuffix = '.tmp.lock' if self.tmp_mount else '.lock' lock = os.path.join(self.lock_path, self.pid + lockSuffix) logger.debug(f'Set mount lock {lock}', self) with open(lock, 'w') as f: f.write(self.pid) def mountLockCheck(self): """ Check for locks on the current mountpoint. Returns: bool: ``True`` if there are any locks """ lockSuffix = '.lock' return self.checkLocks(self.lock_path, lockSuffix) def mountLockRelease(self): """ Remove mountpoint lock for this process. """ lockSuffix = '.tmp.lock' if self.tmp_mount else '.lock' lock = os.path.join(self.lock_path, self.pid + lockSuffix) if os.path.exists(lock): logger.debug(f'Remove mount lock {lock}', self) os.remove(lock) def checkLocks(self, path, lock_suffix): """Check existence of active and foreign locks. The lock owning process is specified by the PID contained in the filename of the lock file used. Lock files of the current process are ignored and ``False`` is returned if they share the same tmp-mount state. If a lock exist but its process not the lock is removed and ``False`` returned. In that latter case mount symlinks related to that lock also removed. Args: path (str): Full path to lock directory. lock_suffix (str): Last part of locks name. Returns: bool: ``True`` if there are active locks in ``path``. Raises: FileNotFoundError: If the path does not exists. """ if isinstance(path, str): path = Path(path) for lock_fp in path.iterdir(): # Not a lock file? if lock_fp.suffix != lock_suffix: # next file continue # Secondary suffix is "tmp"? (e.g. "12345.tmp.lock") is_tmp = lock_fp.with_suffix('').suffix == '.tmp' # Extract PID from lock file name lock_pid = lock_fp.stem if is_tmp: lock_pid = lock_pid[:-4] # cut ".tmp" from the end # Ignore process's own lock files. if lock_pid == self.pid: # ...with the same tmp-state. if is_tmp == self.tmp_mount: # Dev note (buhtz, 2024-11-22): I have no idea what makes # a mount temporary. continue if tools.processAlive(int(lock_pid)): return True logger.debug(f'Remove old and invalid lock {lock_fp}', self) # Clean up the lock file lock_fp.unlink() # Clean up related symlinks for symlink in Path(self.mount_root).iterdir(): if symlink.name.endswith(f'_{lock_pid}'): symlink.unlink() return False def setattrKwargs(self, arg, default, store=True, **kwargs): """ Set attribute ``arg`` in local namespace (self.arg). Also collect all args in ``self.all_kwargs`` which will be hashed later and used as mountpoint name and also be written as unmount_info. Args: arg (str): argument name default: default value used if ``arg`` is not in ``kwargs`` store (bool): if ``True`` add ``arg`` to ``self.all_kwargs`` **kwargs: arguments given on backend constructor """ if arg in kwargs: value = kwargs[arg] else: value = default setattr(self, arg, value) if store: #make dictionary with all used args for umount self.all_kwargs[arg] = value def writeUmountInfo(self): """ Write content of ``self.all_kwargs`` to file ``~/.local/share/backintime/mnt//umount``. This will be used to unmount the filesystem later. """ data_string = json.dumps(self.all_kwargs) with open(self.umount_info, 'w') as f: f.write(data_string) f.close def readUmountInfo(self, umount_info = None): """ Read keyword arguments from file ``umount_info``. Args: umount_info (str): full path to /umount file. If ``None`` current ``/umount`` file will be used Returns: dict: previously written ``self.all_kwargs`` """ if umount_info is None: umount_info = self.umount_info with open(umount_info, 'r') as f: data_string = f.read() f.close() return json.loads(data_string) def compareUmountInfo(self, umount_info = None): """ Compare current ``self.all_kwargs`` with those from file ``umount_info``. This should prevent hash collisions of two different mounts. Args: umount_info (str): full path to /umount file Returns: bool: ``True`` if ``self.all_kwargs`` and ``kwargs`` read from ``umount_info`` file are identiacal """ #run self.all_kwargs through json first current_kwargs = json.loads(json.dumps(self.all_kwargs)) saved_kwargs = self.readUmountInfo(umount_info) if not len(current_kwargs) == len(saved_kwargs): return False for arg in list(current_kwargs.keys()): if not arg in list(saved_kwargs.keys()): return False if not current_kwargs[arg] == saved_kwargs[arg]: return False return True def compareRemount(self, old_hash_id): """ Compare mount arguments between current and ``old_hash_id``. If they are identical we could reuse the mount and don't need to remount. Args: old_hash_id (str): Hash ID of the old mountpoint Returns: bool: True if the old mountpoint and current are identiacal """ if old_hash_id == self.hash_id: return self.compareUmountInfo(self.umountInfoPath(old_hash_id)) return False def setSymlink(self, profile_id = None, hash_id = None, tmp_mount = None): """ If ``self.symlink`` is ``True`` set symlink ``~/.local/share/backintime/mnt/_``. Target will be either the mountpoint or a subfolder of the mountpoint if ``self.symlink_subfolder`` is set. Args: profile_id (str): Profile ID that should be linked. If ``None`` use ``self.profile_id`` hash_id (str): Hash ID of mountpoint where this sysmlink should point to. If ``None`` use ``self.hash_id`` tmp_mount (bool): Set a temporary symlink just for testing new settings """ if not self.symlink: return if profile_id is None: profile_id = self.profile_id if hash_id is None: hash_id = self.hash_id if tmp_mount is None: tmp_mount = self.tmp_mount dst = self.config.snapshotsPath(profile_id=profile_id, mode=self.mode, tmp_mount=tmp_mount) mountpoint = self.mountpoint(hash_id) if self.symlink_subfolder is None: src = mountpoint else: src = os.path.join(mountpoint, self.symlink_subfolder) if os.path.exists(dst): os.remove(dst) os.symlink(src, dst) def removeSymlink(self, profile_id=None, tmp_mount=None): """ Remove symlink ``~/.local/share/backintime/mnt/_``. Args: profile_id (str): Profile ID for the symlink. tmp_mount (bool): Symlink is a temporary link for testing new settings. """ if not self.symlink: return if profile_id is None: profile_id = self.profile_id if tmp_mount is None: tmp_mount = self.tmp_mount symlink_filename = self.config.snapshotsPath( profile_id=profile_id, mode=self.mode, tmp_mount=tmp_mount) try: os.remove(symlink_filename) except FileNotFoundError as exc: logger.error( f'Can not remove unexisting symlink "{symlink_filename}". ' 'See issue #2296 for details.') logger.debug(str(exc)) else: logger.debug(f'Symlink removed: "{symlink_filename}"') def hash(self, s): """ Create a CRC32 hash of string ``s``. Args: s (str): string that should be hashed Returns: str: hash of string ``s`` """ return '%X' % (crc32(s.encode()) & 0xFFFFFFFF) def hashIdPath(self, hash_id = None): """ Get path ``~/.local/share/backintime/mnt/``. Args: hash_id (str): Unique identifier for a mountpoint. If ``None`` use ``self.hash_id`` Returns: str: full path to ```` """ if hash_id is None: hash_id = self.hash_id return os.path.join(self.mount_root, self.hash_id) def mountpoint(self, hash_id = None): """ Get path ``~/.local/share/backintime/mnt//mountpoint``. Args: hash_id (str): Unique identifier for a mountpoint Returns: str: full path to ``/mountpoint`` """ return os.path.join(self.hashIdPath(hash_id), 'mountpoint') def lockPath(self, hash_id = None): """ Get path ``~/.local/share/backintime/mnt//locks``. Args: hash_id (str): Unique identifier for a mountpoint Returns: str: full path to ``/locks``` """ return os.path.join(self.hashIdPath(hash_id), 'locks') def umountInfoPath(self, hash_id = None): """ Get path ``~/.local/share/backintime/mnt//umount``. Args: hash_id (str): Unique identifier for a mountpoint Returns: str: full path to ``/umount``` """ return os.path.join(self.hashIdPath(hash_id), 'umount') backintime-1.6.1/common/password.py000066400000000000000000000270111514264426600173440ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import sys import os import time import atexit import signal import config import configfile import tools import daemon import password_ipc import logger from exceptions import Timeout class Password_Cache(daemon.Daemon): """ Password_Cache get started on User login. It provides passwords for BIT cronjobs because keyring is not available when the User is not logged in. Does not start if there is no password to cache (e.g. no profile allows to cache). """ PW_CACHE_VERSION = 3 def __init__(self, cfg = None, *args, **kwargs): self.config = cfg if self.config is None: self.config = config.Config() cachePath = self.config.passwordCacheFolder() if not tools.mkdir(cachePath, 0o700): msg = 'Failed to create secure Password_Cache folder' logger.error(msg, self) raise PermissionError(msg) pid = self.config.passwordCachePid() super(Password_Cache, self).__init__( pid, umask = 0o077, *args, **kwargs) self.dbKeyring = {} self.dbUsr = {} self.fifo = password_ipc.FIFO(self.config.passwordCacheFifo()) self.keyringSupported = tools.keyringSupported() def run(self): """ wait for password request on FIFO and answer with password from self.db through FIFO. """ info = configfile.ConfigFile() info.setIntValue('version', self.PW_CACHE_VERSION) info.save(self.config.passwordCacheInfo()) os.chmod(self.config.passwordCacheInfo(), 0o600) logger.debug('Keyring supported: %s' %self.keyringSupported, self) tools.envSave(self.config.cronEnvFile()) if not self.collectPasswords(): logger.debug('Nothing to cache. Quit.', self) sys.exit(0) self.fifo.create() atexit.register(self.fifo.delfifo) signal.signal(signal.SIGHUP, self.reloadHandler) logger.debug('Start loop', self) while True: try: request = self.fifo.read() request = request.split('\n')[0] task, value = request.split(':', 1) if task == 'get_pw': key = value if key in self.dbKeyring: answer = 'pw:' + self.dbKeyring[key] elif key in self.dbUsr: answer = 'pw:' + self.dbUsr[key] else: answer = 'none:' self.fifo.write(answer, 5) elif task == 'set_pw': key, value = value.split(':', 1) self.dbUsr[key] = value except IOError as exc: logger.error(f'Error in writing answer to FIFO: {exc}', self) except KeyboardInterrupt: logger.debug('Quit.', self) break except Timeout: # That exception is thrown by tools.Alarm.handle() if the # timeout ends. That Alarm was set by FIFO.read(). logger.error('FIFO timeout', self) except Exception as e: logger.error('ERROR: %s' % str(e), self) def reloadHandler(self, _signum, _frame): """ reload passwords during runtime. """ time.sleep(2) cfgPath = self.config._LOCAL_CONFIG_PATH del self.config self.config = config.Config(cfgPath) del self.dbKeyring self.dbKeyring = {} self.collectPasswords() def collectPasswords(self): """ search all profiles in config and collect passwords from keyring. """ run_daemon = False profiles = self.config.profiles() for profile_id in profiles: mode = self.config.snapshotsMode(profile_id) for pw_id in (1, 2): if self.config.modeNeedPassword(mode, pw_id): if self.config.passwordUseCache(profile_id): run_daemon = True if (self.config.passwordSave(profile_id) and self.keyringSupported): service_name = self.config.keyringServiceName( profile_id, mode, pw_id) user_name = self.config.keyringUserName(profile_id) password = tools.password(service_name, user_name) if password is None: continue self.dbKeyring[f'{service_name}/{user_name}'] \ = password return run_daemon def checkVersion(self): info = configfile.ConfigFile() info.load(self.config.passwordCacheInfo()) if info.intValue('version') < self.PW_CACHE_VERSION: return False return True def cleanup_handler(self, signum, frame): self.fifo.delfifo() super(Password_Cache, self).cleanup_handler(signum, frame) class Password: """Provide passwords for BIT either from keyring, Password_Cache or by asking user. """ def __init__(self, cfg=None): self.config = cfg if self.config is None: self.config = config.Config() self.cache = Password_Cache(self.config) self.fifo = password_ipc.FIFO(self.config.passwordCacheFifo()) self.db = {} self.keyringSupported = tools.keyringSupported() def password(self, parent, profile_id, mode, pw_id=1, only_from_keyring=False, refresh=False): """ Based on profile settings return password from keyring, Password_Cache or by asking User. """ if not self.config.modeNeedPassword(mode, pw_id): return '' service_name = self.config.keyringServiceName(profile_id, mode, pw_id) user_name = self.config.keyringUserName(profile_id) try: return self.db['%s/%s' % (service_name, user_name)] except KeyError: pass password = '' if (self.config.passwordUseCache(profile_id) and not only_from_keyring and not refresh): # From cache password = self.passwordFromCache(service_name, user_name) if password is not None: self.setPasswordDb(service_name, user_name, password) return password if self.config.passwordSave(profile_id) and not refresh: # From keyring password = self.passwordFromKeyring(service_name, user_name) if password is not None: self.setPasswordDb(service_name, user_name, password) return password if refresh or not only_from_keyring: # Ask user and write to cache password = self.passwordFromUser(parent, profile_id, mode, pw_id) if self.config.passwordUseCache(profile_id): self.setPasswordCache(service_name, user_name, password) self.setPasswordDb(service_name, user_name, password) return password return password def passwordFromKeyring(self, service_name, user_name): """ get password from system keyring (seahorse). The keyring is only available if User is logged in. """ if self.keyringSupported: try: return tools.password(service_name, user_name) except Exception: logger.error('get password from Keyring failed', self) return None def passwordFromCache(self, service_name, user_name): """ get password from Password_Cache """ if not self.cache.status(): return None self.cache.checkVersion() self.fifo.write(f'get_pw:{service_name}/{user_name}', timeout=5) answer = self.fifo.read(timeout = 5) mode, pw = answer.split(':', 1) return None if mode == 'none' else pw def passwordFromUser(self, parent, profile_id=None, mode=None, pw_id=1, prompt=None): """Ask user for password. Use terminal input or a dialog box if X is available. This does even work when run as cronjob and user is logged in. Args: parent: Parent of the ``QMessageDialog``. profile_id(str): Profile identifier. mode(str): Mode identifier (e.g. SSH (encrypted)). pwd_id(int): See :data:`config.SNAPSHOT_MODES` for details. prompt(str): Alternative string used as prompt. Return: str: The password. """ # Default prompt if prompt is None: prompt = _('Enter password for {mode} profile "{profile}":') \ .format( profile=self.config.profileName(profile_id), mode=self.config.SNAPSHOT_MODES[mode][pw_id+1]) tools.register_backintime_path('qt') x_server = tools.checkXServer() import_successful = False if x_server: try: import messagebox import_successful = True except ImportError: pass if not import_successful or not x_server: import getpass alarm = tools.Alarm() alarm.start(300) try: password = getpass.getpass(prompt + ' ') alarm.stop() except Timeout: password = '' return password # Use QDialog as graphical prompt password = messagebox.ask_password_dialog( parent=parent, title=self.config.APP_NAME, prompt=prompt, language_code=self.config.language(), timeout=300) return password def setPasswordDb(self, service_name, user_name, password): """ internal Password cache. Prevent to ask password several times during runtime. """ self.db['%s/%s' %(service_name, user_name)] = password def setPassword(self, password, profile_id, mode, pw_id): """ store password to keyring and Password_Cache """ if self.config.modeNeedPassword(mode, pw_id): service_name = self.config.keyringServiceName( profile_id, mode, pw_id) user_name = self.config.keyringUserName(profile_id) if self.config.passwordSave(profile_id): self.setPasswordKeyring(service_name, user_name, password) if self.config.passwordUseCache(profile_id): self.setPasswordCache(service_name, user_name, password) self.setPasswordDb(service_name, user_name, password) def setPasswordKeyring(self, service_name, user_name, password): return tools.setPassword(service_name, user_name, password) def setPasswordCache(self, service_name, user_name, password): if self.cache.status(): self.cache.checkVersion() self.fifo.write( f'set_pw:{service_name}/{user_name}:{password}', timeout=5) backintime-1.6.1/common/password_ipc.py000066400000000000000000000107071514264426600202030ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import sys import stat import tools import threading import tempfile from contextlib import contextmanager import logger class FIFO: """Inter-process communication (IPC) with named pipes using the first-in, first-out principle (FIFO). Params: fifo (str): Name of the named pipe file. alarm (tools.Alarm): To handle read/write timeouts. """ def __init__(self, fname): self.fifo = fname self.alarm = tools.Alarm() def delfifo(self): """Remove named pipe file.""" try: os.remove(self.fifo) # TODO: Catch FileNotFoundError only except: pass def create(self): """Create the named pipe file in a way that only the current user has access to it. """ if os.path.exists(self.fifo): self.delfifo() try: # Permissions are "rw- --- ---" os.mkfifo(self.fifo, 0o600) except OSError as e: logger.error(f'Failed to create named pipe file. Error: {e}', self) sys.exit(1) def read(self, timeout=0): """Read from named pipe until timeout. If timeout is 0 it will wait forever for input. """ # sys.stdout.write('read fifo\n') if not self.isFifo(): # TODO raise an Exception or write to stderr sys.exit(1) self.alarm.start(timeout) with open(self.fifo, 'r') as handle: # Will wait until data is available, # or an exception (e.g. exception.Timeout) is raised. # The latter will happen when the timeout is finished. ret = handle.read() # If the alarm timeout ends but read() received not data, a # exception.Timeout will be raised at this point. # The exception will be caught far away in # password.py::Password_Cache.run(). self.alarm.stop() return ret def write(self, string, timeout=0): """Write to named pipe file until timeout. If timeout is 0 it will wait forever for an other process that will read this. """ if not self.isFifo(): # TODO raise an Exception or write to stderr sys.exit(1) self.alarm.start(timeout) with open(self.fifo, 'w') as fifo: fifo.write(string) # See FIFO.read() to learn about "hidden" handling of Timeout # exception. self.alarm.stop() def isFifo(self): """Make sure file is still a FIFO and has correct permissions.""" try: s = os.stat(self.fifo) except OSError: return False if not s.st_uid == os.getuid(): logger.error(f'{self.fifo} is not owned by user', self) return False mode = s.st_mode if not stat.S_ISFIFO(mode): logger.error(f'{self.fifo} is not a named pipe file (FIFO)', self) return False forbidden_perm = stat.S_IXUSR + stat.S_IRWXG + stat.S_IRWXO if mode & forbidden_perm > 0: logger.error(f'{self.fifo} has wrong permissions', self) return False return True class TempPasswordThread(threading.Thread): """Provide password through temp FIFO. In case BIT is not configured yet this provides a password through temp FIFO to backintime-askpass. """ def __init__(self, string): super(TempPasswordThread, self).__init__() self.pw = string self.temp_file = os.path.join(tempfile.mkdtemp(), 'FIFO') self.fifo = FIFO(self.temp_file) @contextmanager def starter(self): self.start() yield self.stop() def run(self): self.fifo.create() self.fifo.write(self.pw) self.fifo.delfifo() def read(self): """ read fifo to end the blocking fifo.write use only if thread timeout. """ self.fifo.read() def stop(self): self.join(5) if self.is_alive(): #threading does not support signal.alarm self.read() try: os.rmdir(os.path.dirname(self.temp_file)) except OSError: pass backintime-1.6.1/common/pluginmanager.py000066400000000000000000000262371514264426600203440ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import sys import tools tools.register_backintime_path('common') tools.register_backintime_path('plugins') tools.register_backintime_path('common', 'plugins') tools.register_backintime_path('qt', 'plugins') import logger from exceptions import StopException class Plugin: """ Interface methods to customize behavior for different backup steps Back In Time allows to inform plugins (implemented in Python files) about different steps ("events") in the backup process. Plugins may implement special behavior to predefined "events" that are declared in this interface class as methods. To implement a new plugin create a new class that inherits from this one and implement all methods. Plugins are loaded by calling :py:func:`PluginManager.load`. """ def init(self, snapshots): return True def isGui(self): """Indicates a GUI-related plugin The return value shall indicate if the plugin is related to the Back In Time GUI. Loaded GUI-related plugins are called before non-GUI-related plugins by the PluginManager. Returns: True if plugin is GUI-related, otherwise False """ return False def processBegin(self): """Called before a backup process is started. A new snapshot is only taken if required (as configured). Returns: ``None`` (return value will be ignored anyhow) """ return def processEnd(self): """Called after a backup process has ended Returns: ``None`` (return value will be ignored anyhow) """ return def error(self, code, message): """Indicates errors during the backup process Called to send errors in the backup process (while taking a snapshot) to plugins. Args: code: A Back In Time error code Known error codes: 1: No or no valid configuration (check the configuration file) 2: A backup process is already running. Make sure that automatic and manual backups do not run at once. 3: Snapshots directory not found (eg. when a removable drive is not mounted) 4: The requested snapshot for "now" already exists. ``message`` contains the SID (snapshot ID) then. 5: Error while taking a snapshot. ``message`` contains more information (as string). 6: New snapshot taken but with errors. ``message`` contains the SID (snapshot ID) then. message: The error message for the code (mostly an empty string by default) Returns: ``None`` (return value will be ignored anyhow) """ return def newSnapshot(self, snapshot_id, snapshot_path): """ Called when the backup process has taken a new snapshot. A new snapshot is only taken by the backup process if required (as configured). Args: snapshot_id: The id of the new snapshot snapshot_path: The path to the new snapshot Returns: ``None`` (return value will be ignored anyhow) """ return def message(self, profile_id, profile_name, level, message, timeout): """Send snapshot-related messages to plugins. Args: profile_id: Profile ID from configuration. profile_name: Profile name from the configuration. level: 0 = INFO, 1 = ERROR message: Message text. timeout: Requested timeout in seconds to process the message. Not used at the moment. (default -1 means "no timeout") """ def appStart(self): """ Called when the GUI of Back In Time was started. Not called when only the CLI command was started without the GUI. Returns: ``None`` (return value will be ignored anyhow) """ return def appExit(self): """ Called when the GUI of Back In Time is closed Returns: ``None`` (return value will be ignored anyhow) """ return def mount(self, profileID = None): """ Called when mounting a filesystem for the profile may be necessary. Args: profileID: Profile ID from the configuration Returns: ``None`` (return value will be ignored anyhow) """ return def unmount(self, profileID = None): """ Called when unmounting a filesystem for a profile may be necessary Args: profileID: Profile ID from the configuration Returns ``None`` (return value will be ignored anyhow) """ return class PluginManager: """ Central interface for loading plugins and calling their API Back In Time allows to inform plugins (implemented in Python files) about different steps ("events") in the backup process. Use this class to load installed plugin classes and call their methods (see the interface declared by :py:class:`Plugin`). Plugins are loaded by calling :py:func:`PluginManager.load`. When you call a plugin function of the PluginManager it will call this plugin function for all loaded plugins. """ # TODO 09/28/2022: Should inherit from + implement class "Plugin" def __init__(self): self.plugins = [] self.hasGuiPlugins = False self.loaded = False def load(self, snapshots=None, cfg=None, force=False): """Loads plugins Loads all plugins from python source code files that are stored in one of these plugin sub folders in the installation root folder: 'plugins', 'common/plugins', 'qt/plugins' Plugins must inherit from :py:class:`Plugin` otherwise they are silently ignored. Args: snapshots (snapshots.Snapshots): Snapshot info cfg (config.Config): Current configuration force (bool): ``True`` to enforce reloading all plugins (``False`` does only load if not already done) """ if self.loaded and not force: return if snapshots is None: import snapshots as snapshots_ snapshots = snapshots_.Snapshots(cfg) self.loaded = True self.plugins = [] self.hasGuiPlugins = False self.loadedPlugins = [] # TODO 09/28/2022: Move hard coded plugin folders to configuration for path in ('plugins', 'common/plugins', 'qt/plugins'): fullPath = tools.as_backintime_path(path) if not os.path.isdir(fullPath): continue logger.debug(f'Register plugin path {fullPath}', self) tools.register_backintime_path(path) for f in os.listdir(fullPath): if f.startswith('__') or not f.lower().endswith('.py'): logger.debug(f'Not a plugin file: {f}', self) continue self._load_plugin_from_file(f, snapshots) def _load_plugin_from_file(self, file_name: str, snapshots: list): if file_name in self.loadedPlugins: logger.debug(f'Plugin file still loaded: {file_name}', self) return try: module = __import__(file_name[: -3]) module_dict = module.__dict__ for key, value in list(module_dict.items()): if key.startswith('__'): continue if type(value) is type: # A plugin must implement this class via inheritance if issubclass(value, Plugin): plugin = value() if plugin.init(snapshots): logger.debug(f'Add plugin {file_name}', self) if plugin.isGui(): self.hasGuiPlugins = True self.plugins.insert(0, plugin) else: self.plugins.append(plugin) self.loadedPlugins.append(file_name) except BaseException as exc: logger.error(f'Failed to load plugin {file_name}: {exc=}', self) raise def processBegin(self): ret_val = True for plugin in self.plugins: try: plugin.processBegin() except StopException: ret_val = False except BaseException as e: self.logError(plugin, e) return ret_val def processEnd(self): for plugin in reversed(self.plugins): try: plugin.processEnd() except BaseException as e: self.logError(plugin, e) def error(self, code, message = ''): for plugin in self.plugins: try: plugin.error(code, message) except BaseException as e: self.logError(plugin, e) def newSnapshot(self, snapshot_id, snapshot_path): for plugin in self.plugins: try: plugin.newSnapshot(snapshot_id, snapshot_path) except BaseException as e: self.logError(plugin, e) def message(self, profile_id, profile_name, level, message, timeout = -1): for plugin in self.plugins: try: plugin.message( profile_id, profile_name, level, message, timeout) except BaseException as e: self.logError(plugin, e) def appStart(self): for plugin in reversed(self.plugins): try: plugin.appStart() except BaseException as e: self.logError(plugin, e) def appExit(self): for plugin in reversed(self.plugins): try: plugin.appExit() except BaseException as e: self.logError(plugin, e) def mount(self, profileID = None): for plugin in reversed(self.plugins): try: plugin.mount(profileID) except BaseException as e: self.logError(plugin, e) def unmount(self, profileID = None): for plugin in reversed(self.plugins): try: plugin.unmount(profileID) except BaseException as e: self.logError(plugin, e) def logError(self, plugin, e): logger.error('Plugin %s %s failed: %s' %(plugin.__module__, #plugin name sys._getframe(1).f_code.co_name, #method name str(e)), #exception self, 1) backintime-1.6.1/common/plugins/000077500000000000000000000000001514264426600166105ustar00rootroot00000000000000backintime-1.6.1/common/plugins/usercallbackplugin.py000066400000000000000000000111751514264426600230410ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . import os import pluginmanager import logger import gettext from subprocess import Popen, PIPE from exceptions import StopException _ = gettext.gettext class UserCallbackPlugin(pluginmanager.Plugin): """ Executes a script file at different backup steps to customize behavior Back In Time allows to inform plugins (implemented in Python files) about different steps ("events") in the backup process via the :py:class:`pluginmanager.PluginManager`. This plugin calls a user-defined script file ("user-callback"). By default that file is located in the config folder `$XDG_CONFIG_HOME/backintime/` or another folder if command line optioni `--config` is used. The user-callback script is called with up to five positional arguments: 1. The profile ID from the config file (1=Main Profile, ...) 2. The profile name (from the config file) 3. A numeric code to indicate the reason why Back In Time calls the script (see the method implementation for details about the numeric code) 4. Error code (only if argument 3 has the value "4") or snapshot ID (only if argument 3 has the value "3") 5. Snapshot name (only if argument 3 has the value "3") For more details and script examples see: https://github.com/bit-team/user-callback Notes: The user-callback script file is normally implemented as shell script but could theoretically be implemented in any script language (declared via the hash bang "#!" in the first line of the script file. """ def __init__(self): # Dev note (2025-11, buhtz): Aryoda wrote that line one year ago in # commit 9618d03. Not sure if there really is a need for it. # In context of my syslog sub-identfiers, I need to remove that. # My assumption is that at this point the syslog.openlog() was called. # All this problems will vanish if #2286 is completed. # logger.openlog('USERCALLBACKUP') return def init(self, snapshots): self.config = snapshots.config self.script = self.config.takeSnapshotUserCallback() return os.path.exists(self.script) # TODO 09/28/2022: This method should be private (_callback) def callback(self, *args, profileID=None): if profileID is None: profileID = self.config.currentProfile() profileName = self.config.profileName(profileID) cmd = [self.script, profileID, profileName] cmd.extend(str(x) for x in args) logger.debug(f'Call user-callback: {" ".join(cmd)}', self) stdout, stderr = PIPE, PIPE try: callback = Popen(cmd, stdout=stdout, stderr=stderr, universal_newlines=True) output = callback.communicate() # Stdout if output[0]: logger.info("user-callback returned '" + output[0].strip('\n') + "'", self) # Stderr if output[1]: logger.error("user-callback returned '" + output[1].strip('\n') + "'", self) if callback.returncode != 0: logger.warning( f'user-callback returncode: {callback.returncode}', self) raise StopException() except OSError as e: logger.error( f'Exception when trying to run user callback: {e.strerror}', self) def processBegin(self): self.callback('1') def processEnd(self): self.callback('2') def error(self, code, message): if not message: self.callback('4', code) else: self.callback('4', code, message) def newSnapshot(self, snapshot_id, snapshot_path): self.callback('3', snapshot_id, snapshot_path) def appStart(self): self.callback('5') def appExit(self): self.callback('6') def mount(self, profileID = None): self.callback('7', profileID = profileID) def unmount(self, profileID = None): self.callback('8', profileID = profileID) backintime-1.6.1/common/po/000077500000000000000000000000001514264426600155455ustar00rootroot00000000000000backintime-1.6.1/common/po/README.md000066400000000000000000000015031514264426600170230ustar00rootroot00000000000000 # Overview Translation for Back In Time is done at https://translate.codeberg.org/engage/backintime. Please do NOT change po-files in this folder as they will get overwritten with files exported from translation platform. See [Maintenance documentation about translation and localization](../../doc/maintain/2_localization.md) for details. # Translation credits from removed languages Because of missing translators some languages were removed in the past. The translators' credits are archived here: ``` Interlingua [ie]: - OIS ``` backintime-1.6.1/common/po/ar.po000066400000000000000000002327461514264426600165250ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Jad Madi (@jadmadi) # SPDX-FileCopyrightText: © Maytham Alsudany # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-10-29 20:07+0000\n" "Last-Translator: BishoyEhab \n" "Language-Team: Arabic \n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Weblate 5.13.3\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "كل التراخيص المستخدمه في هذا المشروع موجودة في المجلد {dir_link}. لاستخراج " "أي ترخيص أو حقوق نشر أي ملف بأستخدام بيانات SPDX الوصفية, ارجع إلى " "{readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "تحذير" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "الملف الشخصي الرئيسي" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "تشفير محلي بصيغة EncFS" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (تشفير EncFS)" #: common/config.py:237 msgid "Local" msgstr "محلي" #: common/config.py:240 msgid "Local encrypted" msgstr "مشفرة محليا" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "التعمية" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "مفتاح SSH الخاص" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "الملف الشخصي: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "مُجلد النسخ الاحتياطي غير صالح." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "يجب إختيار مجلد واحد على الأقل للنسخ الاحتياطي." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "مُجلد: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "لا يمكن تضمين هذا المجلد للنسخ الاحتياطي لأنه جزء من وجهة النسخ الاحتياطي " "نفسها." #: common/config.py:366 #, fuzzy, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "يجب أن تكون القيمة ل\"إزالة أقدم نسخة احتياطية إذا كانت المساحة الحرة أقل " "من\" ({val_one}) أقل من أو تساوي الحد ل\"تحذير اذا انخفضت مساحة التخزين عن\"" " ({val_two})" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "جدول udev لا يعمل مع طريقة {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "فشل كتابة crontab جديد." #: common/config.py:1577 #, fuzzy msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "لا يعمل كرون (Cron) رغم توفر أمر crontab. لن يتم تشغيل مهام النسخ الاحتياطي " "المجدولة. قد يكون كرون مثبتًا ولكنه غير مفعل. جرب الأمر \"systemctl enable " "cron\" أو استشر قنوات الدعم لتوزيعة جنو / لينكس الخاصة بك." #: common/configfile.py:101 msgid "Failed to save config" msgstr "فشل في حفظ التكوين" #: common/configfile.py:137 msgid "Failed to load config" msgstr "فشل في جلب التكوين" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "الملف الشخصي \"{name}\" موجود أصلاً." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "لا يستطيع إزالة الملف الشخصي الآخر." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "لا يستطيع ركب '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "لم يوجد التكوين للمجلد المشفر." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "هل تريد انشاء مجلد مشفر جديد؟" #: common/encfstools.py:204 msgid "Cancel" msgstr "إلغاء" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "يرجى إدخال كلمة مرور لـ \"{user}\"." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "كلمة السر ليس مطابق." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "خذ لقطة" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "لا يستطيع ركب '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "لا يستطيع تفكيك {mountprocess} من {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "لم يتم العثور على الأمر \"{command}\". يرجى تثبيته (على سبيل المثال ، " "باستخدام \"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "نقطة التوصيل {mntpoint} ليست فارغة." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "ادخل كلمة المرور لملف التعريف لوضع {mode} يسمى \"{profile}\":" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "لا يستطيع تثبيت قاعدة Udev ماف الشخصي {profile_id}. خدمة DBus " "'{dbus_interface}' ليس كانت موفره" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "لا يستطيع العثور على UUID لـ{path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "فشل" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "إستعادة الأذونات" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "تم" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "تأجيل النسخ الاحتياطي أثناء وجوده على البطارية" #: common/snapshots.py:931 qt/app.py:393 #, fuzzy msgid "Can't find backup directory." msgstr "لم نتمكن من العثور على مجلد اللقطات." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "إن كان على وحدة تخزين خارجية، يرجى توصيلها." #: common/snapshots.py:938 #, fuzzy, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "ينتظر %s ثانية." msgstr[1] "ينتظر %s ثواني." msgstr[2] "ينتظر %s ثانية." msgstr[3] "ينتظر %s ثواني." msgstr[4] "ينتظر %s ثانية." msgstr[5] "ينتظر %s ثواني." #: common/snapshots.py:1005 #, fuzzy, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "فشل بأخذ لقطة {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "الرجاء الانتظار. جاري الانتهاء…" #: common/snapshots.py:1163 #, fuzzy msgid "Can't create directory." msgstr "لا يمكن إنشاء مجلد" #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "يتم حفظ ملف التكوين…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "يتم حفظ الأذونات…" #: common/snapshots.py:1377 #, fuzzy, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "وجد بقايا اللقطة {snapshot_id} ويمكن الاستمرار فيه." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "يتم إزالة مجلد بقايا {snapshot_id} من العملية الاخيرة" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "لا يُمكن إزالة المُجلد" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "نجاح" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "عملية النقل جزئية بسبب حدوث خطأ" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "عملية النقل جزئية بسبب اختفاء ملفات المصدر (انظر 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "انتهت عملية 'rsync' مع رمز الخروج {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "اطلع على 'man rsync' للمزيد من التفاصيل" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "رموز الخروج السلبية لrsync هم ارقام إشارة, اطلع على 'kill -l' و'man kill'" #: common/snapshots.py:1566 #, fuzzy msgid "Nothing changed, no new backup necessary" msgstr "لا شيء تغير, لا حاجة للقطة جديدة" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "لا يمكن إعادة تسمية {new_path} إلى {path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "تطبيق القواعد لإلزالة اللقطات القديمة" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "تطبيق قواعد الإحتفاظ" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "حاول إبقاء حد أدنى من المساحة فارغة" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "محاولة للحفاظ على الحد الأدنى من {perc} ضمن مساحة الـ inode حرة" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "الآن" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "غير ممكن تركيب {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "لم يتم العثور على ssh-agent. يرجى التأكد من أنه مثبت." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "لم يمكن فتح مفتاح SSH الخاص. كلمة المرور خاطئة أو كلمة المرور غير متاحة لـ " "cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "المسار البعيد موجود لكن ليس مجلدا." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "المسار البعيد غير قابل للكتابة." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "المسار المتباعد ليس قابل للتنفيذ." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "لا يمكن إنشاء المسار البعيد." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "المضيف البعيد {host} لا يدعم {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "التأكد من الأوامر على المضيف {host} أعاد بخطأ غير معروف" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "المضيف البعيد {host} لا يدعم الروابط الصلبة" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "نسخ مفتاح SSH العام \"{pubkey}\" إلى المضيف البعيد \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "يرجى إدخال كلمة مرور لـ \"{user}\"." #: common/tools.py:382 #, fuzzy, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "نظام الملفات الوجهة لـ {path} مُنسق باستخدام FAT، والذي لا يدعم الروابط " "الصعبة. يُرجى استخدام نظام ملفات لينكس أصلي." #: common/tools.py:414 #, fuzzy, python-brace-format msgid "{path} is not a valid directory." msgstr "المسار البعيد موجود لكن ليس مجلدا." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "" #: common/tools.py:471 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "نظام الملفات الوجهة لـ {path} مُنسق باستخدام FAT، والذي لا يدعم الروابط " "الصعبة. يُرجى استخدام نظام ملفات لينكس أصلي." #: common/tools.py:482 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "نظام الملفات الوجهة لـ {path} هو مشاركة مُركبة عبر SMB. يُرجى التأكد من أن " "خادم SMB البعيد يدعم الروابط الرمزية أو تفعيل {copyLinks} في " "{expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "نسخ الروابط (فك الارتباط بالروابط الرمزية)" #: common/tools.py:487 msgid "Expert Options" msgstr "خيارات الخبراء" #: common/tools.py:491 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "نظام الملفات الوجهة لـ {path} هو مشاركة مُركبة عبر sshfs. لا يدعم sshfs " "الروابط الصلبة. يُرجى استخدام وضع \"SSH\" بدلاً من ذلك." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "" #: qt/aboutdlg.py:51 #, fuzzy msgid "About Back In Time" msgstr "العودة بالزمن" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 #, fuzzy msgid "Authors:" msgstr "المطورون" #: qt/aboutdlg.py:97 #, fuzzy msgid "Translators:" msgstr "الترجمات" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Jad Madi (@jadmadi)\n" "Maytham Alsudany " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "يبدو أن تطبيق {app_name} يعمل لأول مرة حيث لم يتم العثور على أي إعدادات." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "هل ترغب باستيراد إعدادات موجودة (من مجلد احتياطي أو من حاسوب آخر)؟" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "استخدم وقت التعديل والحجم لاكتشاف تغييرات الملفات." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "خذ لقطة (طريقة المجموعة الاختبارية)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "أستخدم المجامع الاختبارية لكشف التغيُّرات في الملفات." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "أوقف عملية التقاط اللقطة" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "استئناف عملية أخذ اللقطة" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "أوقف عملية أخذ اللقطة" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "حدث قائمة اللقطات" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "أزل اللقطة" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "عرض اخر سجل" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "يجب إختيار مجلد واحد على الأقل للنسخ الاحتياطي." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "عرض اخر سجل" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "إدارة الملفات الشخصية…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "تحرير استدعاء المستخدم" #: qt/app.py:548 msgid "Shutdown" msgstr "أطفئ النظام" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "أطفئ النظام بعد اكتمال أخذ اللقطة." #: qt/app.py:552 msgid "Setup language…" msgstr "إعداد اللغة…" #: qt/app.py:556 msgid "Exit" msgstr "خروج" #: qt/app.py:566 #, fuzzy msgid "man page: Back In Time" msgstr "العودة بالزمن" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "" #: qt/app.py:571 #, fuzzy msgid "man page: Profiles config file" msgstr "ملف إعدادات الملفات الشخصية" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "سجل التغييرات" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" #: qt/app.py:589 msgid "FAQ" msgstr "الأسئلة الأكثر شيوعاً" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "" #: qt/app.py:593 msgid "Ask a question" msgstr "إسأل سُؤالاً" #: qt/app.py:597 msgid "Report a bug" msgstr "بلّغ عن عِلة" #: qt/app.py:600 msgid "Translation" msgstr "الترجمة" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "عرض رسالة المشاركة في الترجمة." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "الإنتقال الى تشفير EncFS" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "عرض الرسالة حول إزالة ميزة التشفير EncFS." #: qt/app.py:615 msgid "About" msgstr "عنْ" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "إسترجع" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "إسترجع الملفات والمجلدات المختارة الى اماكنهم الاصلية." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "إسترجع إلى …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "إسترجع الملفات والمجلدات المختارة إلى موقع جديد." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "إسترجع الملفات والمجلدات الظاهرة وكل محتوياتها الى اماكنهم الاصلية." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "إسترجع الملفات والمجلدات الظاهرة وكل محتوياتها إلى موقع جديد." #: qt/app.py:640 msgid "Up" msgstr "أعلى" #: qt/app.py:643 msgid "Show hidden files" msgstr "أظهر الملفات المخفيّة" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "قارن اللقطات…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "" #: qt/app.py:679 #, fuzzy msgid "Shows the message about this Release Candidate again." msgstr "عرض الرسالة حول إزالة ميزة التشفير EncFS." #: qt/app.py:716 msgid "Back In &Time" msgstr "العودة بالزمن" #: qt/app.py:721 msgid "&Backup" msgstr "النسخ الاحتياطي" #: qt/app.py:733 msgid "&Restore" msgstr "&استرجع" #: qt/app.py:739 msgid "&Help" msgstr "مُساعدة" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "" #: qt/app.py:827 msgid "Text only" msgstr "" #: qt/app.py:830 msgid "Text below icons" msgstr "" #: qt/app.py:833 msgid "Text beside icon" msgstr "" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "هذه المجلد غير موجود\n" "في اللقطة المختارة حاليا." #: qt/app.py:1005 msgid "Add to Include" msgstr "اضف للتضمين" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "اضف للاستبعاد" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "إذا تم إغلاق هذه النافذة، فإن برنامج الاستعادة سيتوقف عن تشغيل النظام عند " "انتهاء اللقطة." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "تم، لا حاجة إلى النسخ الاحتياطي" #: qt/app.py:1285 msgid "Working:" msgstr "يعمل:" #: qt/app.py:1292 msgid "Working" msgstr "يعمل" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "خطأ" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "أُرسل:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "السرعة:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "الوقت المتبقي:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "النسخ الاحتياطي" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "استعادة {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "استرجع {path} إلى …" # ignore-placeholder-compare #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "مرحبا\n" "لقد استخدمت تطبيق العودة في الزمن باللغة العربية عدة مرات من قبل.\n" "لقد تم ترجمة {perc} من برنامج العودة في الزمن إلى اللغة العربية. بغض النظر إلى خبرتك التقنية, بإمكانك المساهمة في الترجمة ومن ثم برنامج العودة في الزمن نفسه.\n" "الرجاء زيارة موقع {translation_platform_url} إذا رغبت في المشاركة. للمزيد من الاستفسارات او المساعدة, الرجاء زيارة {back_in_time_project_website}.\n" "نعتذر للمقاطعة, هذه الرسالة لن تعرض مرة أخرى. بإمكانك الإطلاع على هذه الرسالة في أي وقت عبر قائمة المساعدة.\n" "فريق العودة في الزمن" #: qt/app.py:1709 msgid "translation platform" msgstr "منصة الترجمة" #: qt/app.py:1714 msgid "Website" msgstr "الموقع الإلكتروني" #: qt/app.py:1728 msgid "Your translation" msgstr "ترجمتك" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "" #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "" #: qt/app.py:1781 msgid "Open an issue" msgstr "" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD} تحذير{BOLDEND}: حذف الملفات في جذر نظام الملفات قد يؤدي إلى تعطل " "نظامك بالكامل." #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "النسخ الاحتياطي" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" msgstr[4] "" msgstr[5] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "إعدادات اللغة ستُفعّل فقط بعد إعادة تشغيل برنامج العودة بالزمن." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "لا تُزيل اللقطات المُسماّة." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "سؤال" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "إنشاء نسخ احتياطية ملحقة بـ {suffix}\n" "قبل الكتابة فوق العناصر المحلية أو إزالتها." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "سيتم إعادة تسمية الإصدارات الأحدث من الملفات باستخدام ملحق {suffix} قبل " "الاستعادة. إذا لم تعد تحتاج إليها ، يمكنك إزالتها باستخدام الأمر التالي:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "استعادة العناصر الغير موجودة\n" "أو التي هي أحدث من الموجودة في الوجهة فقط.\n" "باستخدام خيار \"rsync --update\"." #: qt/confirmrestoredialog.py:133 #, fuzzy msgid "Remove newer elements in original directory." msgstr "إزالة العناصر الأحدث في المجلد الأصلي." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "استعادة الملفات أو المجلدات المحددة إلى الوجهة الأصلية مع حذف الملفات أو " "المجلدات غير الموجودة في اللقطة. كن حذراً للغاية لأن هذه العملية ستؤدي إلى " "حذف الملفات والمجلدات التي تم استبعادها أثناء أخذ اللقطة." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "هل تريد حقًا استعادة هذا العنصر إلى المجلد الجديد\n" "{path}؟" msgstr[1] "" "هل أنت متأكد أنك ترغب في استرجاع عنصر واحد إلى المجلد الجديد\n" "{path}؟" msgstr[2] "" "هل تريد حقًا استعادة هذان العنصران إلى المجلد الجديد\n" "{path}؟" msgstr[3] "" "هل أنت متأكد أنك ترغب في استرجاع عناصر إلى المجلد الجديد\n" "{path}؟" msgstr[4] "" "هل أنت متأكد أنك ترغب في استرجاع عنصرًا إلى المجلد الجديد\n" "{path}؟" msgstr[5] "" "هل أنت متأكد أنك ترغب في استرجاع عنصرًا إلى المجلد الجديد\n" "{path}؟" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "لا توجد عناصر لاسترجاعها؟" msgstr[1] "هل أنت متأكد أنك ترغب في استرجاع عنصر واحد؟" msgstr[2] "هل أنت متأكد أنك ترغب في استرجاع عنصرين؟" msgstr[3] "هل أنت متأكد أنك ترغب في استرجاع {n} عناصر؟" msgstr[4] "هل أنت متأكد أنك ترغب في استرجاع {n} عنصرًا؟" msgstr[5] "هل أنت متأكد أنك ترغب في استرجاع {n} عنصرًا؟" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "ضمْن ملفات ومُجلدات" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "إعداد اللغة" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "مترجم: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "الإعدادات الافتراضية للنظام" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "استخدم لغة نظام التشغيل." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "عرض السجل الأخير" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "عرض السجل الأخير" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "الملف الشخصي:" #: qt/logviewdialog.py:86 #, fuzzy msgid "Backups:" msgstr "النسخ الاحتياطي" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "مُرَشِح:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] خطأ، [I] معلومات، [C] تغيير" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "فك تشفير المسارات" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "كل" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "تغييرات" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "أخطاء" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "لا توجد معلومات" msgstr[1] "توجد معلومات واحدة" msgstr[2] "توجد معلومتان" msgstr[3] "معلومات" msgstr[4] "معلومات" msgstr[5] "معلومات" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "فشل نقل rsync (تجريبي)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "إدارة الملفات الشخصية" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "تعديل" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "أضف" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "أزل" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&عام" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&ضمْن" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&استثني" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&خيارات" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "خيارات الخبير" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "استعادة الإعدادات" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "ملف شخصي جديد" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "أعِد تسمية الملف الشخصي" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "هل أنت متأكد أنك تريد حذف الملف الشخصي \"{name}\"؟" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "أوقف عملية التقاط اللقطة" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "إستثني ملف" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "مجلدات النسخ الاحتياطي" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "لا يُمكن إزالة المُجلد" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "أظهر الملفات المخفيّة" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "أوقف عملية أخذ اللقطة" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "إستثني مُجلد" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "الإفتراضي" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "جدول زمني" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "يوم:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "يوم الأسبوع:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "ساعات:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "قم بتشغيل Back In Time بمجرد توصيل محرك الأقراص (مرة واحدة فقط كل X أيام).\n" "سيتم مطالبتك بكلمة مرور sudo الخاصة بك." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "شغل \"Back In Time\" بشكل متكرر. هذا مفيد إذا لم يكن الكمبيوتر قيد التشغيل " "بانتظام." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "كل:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "تفعيل تسجيل رسائل التصحيح" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "يكتب رسائل مستوى التصحيح في سجل النظام عبر \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "تحذير: استخدم هذا مؤقتًا فقط للتشخيص، لأنه يولد كمية كبيرة من البيانات." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "مُعطل" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "في كل إقلاع/إعادة إقلاع" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "كل {n} دقيقة" msgstr[1] "كل {n} دقيقة" msgstr[2] "كل {n} دقيقتان" msgstr[3] "كل {n} دقائق" msgstr[4] "كل {n} دقيقة" msgstr[5] "كل {n} دقيقة" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "كل{n} ساعة" msgstr[1] "كل {n} ساعة" msgstr[2] "كل {n} ساعتين" msgstr[3] "بضع {n} ساعات" msgstr[4] "كل {n} ساعة" msgstr[5] "كل{n} ساعة" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "ساعات مخصصة" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "كل يوم" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "متكررة (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "عند وصل وسيط تخزين (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "كل أسبوع" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "كل شهر" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "كل سنة" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "ساعات" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "يوم(أيام)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "أسبوع(أسابيع)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "شهر(شهور)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "يمكن أن تكون الساعات المخصصة قائمة مفصولة بفواصل من الساعات فقط (مثل " "8،12،18،23) أو */3 للنسخ الاحتياطية الدورية كل 3 ساعات." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "Изберете съществуващ частен ключ (обикновено озаглавен \"id_rsa\" или " "\"id_ed25519\" в по-нови системи)." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "Неуспех при създаване на нов SSH ключ в {path}." #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "Пълен път за моментни архивни копия:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Частен ключ:" #: qt/manageprofiles/sshkeyselector.py:210 #, fuzzy msgid "Use system SSH configuration" msgstr "Вмъкване на конфигурация" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH Прокси" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Хост:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Порт:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Потребител:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Свържете се с отдалечената система чрез прокси (известен също като междинен " "хост). Вижте \"-J\" в документацията на командата \"ssh\" или \"ProxyJump\" " "в страницата с ръководство на \"ssh_config\" за подробности." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}ИНФОРМАЦИЯ{ENDBOLD}: В режим „SSH криптиране“ функционират само " "единични или двойни звездички (напр. {example2}). Други типове заместващи " "символи и шаблони ще бъдат игнорирани (напр. {example1}). Имената на " "файловете са непредвидими в този режим поради криптиране от EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Изключване на пътища, файлове или директории" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Шаблон за изключване" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Добавяне на файл" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Добавяне на директории" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Въпрос" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Изключете файлове, по-големи от:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Изключете файлове, по-големи от: {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Изключете файлове, по-големи от стойността в %(prefix)s. При изключен 'Full " "rsync mode', това ще засегне само новите файлове, защото това е преносна " "опция за rsync, а не изключваща такава. Така че големите файлове, които са " "били архивирани преди, ще останат в моментните копия дори и да са били " "променени." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Шаблон за изключване" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Шаблон за изключване" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Изключване на файл" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Изключване на директории" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Деактивирано, защото този шаблон не функционира в режим „SSH криптиране“." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Тези опции са за експертни настройки. Променете само ако сте напълно наясно " "с техните последици." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Изпълнете 'rsync' посредством '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "като периодична задача" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "върху отдалечен хост" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "когато се изпълнява ръчно моментно копие" #: qt/manageprofiles/tab_expert_options.py:110 #, fuzzy msgid "Please install 'nocache' to enable this option." msgstr "Моля инсталирайте 'nocache', за да активирате тази опция" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "върху настоящата машина" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Пренасочете стандартният изход към /dev/null при периодичните задачи." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron автоматично ще изпрати имейл с прикачен резултат от cronjobs, ако е " "инсталиран MTA." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" "Пренасочете стандартният изход за грешки към /dev/null за периодични задачи." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron автоматично ще изпрати имейл с прикачени грешки на cronjobs, ако е " "инсталиран MTA." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/сек" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Ограничете използваният трафик от rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Запазване на ACL (списък за контрол на достъпа)" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Запазване на разширените атрибути (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Ограничете до една файлова система" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Опциите трябва да бъдат цитирани, напр. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Добавете допълнителни опции към rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Префикс за изпълнение преди всяка команда на отдалечената система." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Променливите трябва да бъдат избегнати с \\$FOO. Това не обхваща rsync. Така" " че, за да добавите префикс за rsync, използвайте \"{example_value}\" с " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "по подразбиране" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Добавете префикс към SSH командите" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Проверете дали отдалеченият хост е онлайн" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Внимание: ако е изключено и отдалечената система не е налична, това може да " "доведе до някои непредвидени грешки." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" "Проверете дали отдалечената система поддържа всички необходими команди." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Внимание: ако е изключено и отдалечената система не поддържа всички " "необходими команди, това може да довете до неочаквани грешки." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(по подразбиране: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "деактивирано" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "активирано" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Режим:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Къде да се запазват моментните архиви" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH настройки" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Път:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Нов профил" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Парола" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Запазете паролата в ключодържателя" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Кеширайте паролата за периодичните задачи (Възможен проблем със сигурността:" " потребител root може да достъпва паролата)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Разширени" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 #, fuzzy msgid "Full backup path:" msgstr "Пълен път за моментни архивни копия:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Паролата не съвпада." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Достоверността на системата {host} не може да бъде потвърдена." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} ключовият отпечатък е:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Моля потвърдете този отпечатък! Бихте ли искали да го добавите към " "'known_hosts' файлът с позволени хостове?" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Създаване на нова криптирана директория?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "Частен SSH ключ" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Неуспех при създаване на нов SSH ключ в {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Включване на файлове и директории" #: qt/manageprofiles/tab_include.py:168 #, fuzzy, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" е пряк път. Целта, към която сочи, няма да бъде архивирана докато не добавите и нея.\n" "Бихте ли искали да добавите крайната цел вместо това?" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Включване на файл" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Включване на директории" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Включване на известяването" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Изключване на моментни архиви при работа на батерия" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Енергийното състояние не е налично от системата" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Изпълнявайте по едно моментно копие наведжъж" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Останалите моментни копия ще бъдат блокирани докато текущото такова не " "приключи. Това е глобална опция и ще повлияе на всички профили на " "потребителя. Но трябва да я изберете също и за останалите потребители." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Архивирайте подменените файлове при възстановяване" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Продължаване при грешки (запазване на непълни моментни архиви)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Използвайте checksum, за да засечете промените" #: qt/manageprofiles/tab_options.py:86 #, fuzzy msgid "Create a new backup whether there were changes or not." msgstr "Направете ново моментно копие независимо дали има промени или не." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Ниво на записа:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Нищо" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "инструкция за употреба" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Следните правила се обработват отгоре надолу. По-късните правила заменят по-" "ранните и не са ограничени от тях. Вижте {manual} за подробности и примери." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Отваряне на инструкцията за употреба я браузъра." #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Запазване на последните архиви." #: qt/manageprofiles/tab_remove_retention.py:241 #, fuzzy msgid "The most up-to-date backup is kept under all circumstances." msgstr "" "Последният или най-нов архив ще бъде запазен без значение от " "обстоятелствата." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Поведението не може да бъде променено." #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Да не се премахват именувани архиви." #: qt/manageprofiles/tab_remove_retention.py:258 #, fuzzy msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Като допълнение на времевият маркер наименувани архиви ще бъдат запазени при" " всякакви обстоятелства и няма да бъдат изтривани." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Година(и)" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Премахване на моментни архиви по-стари от" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Пълни дни. Текущият ден се игнорира." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Календарни седмици с понеделник като първи ден. Текущата седмица се " "игнорира." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12 месечни периоди. Текущият месец се игнорира." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Политика за задържане" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Изпълнява се във фонов режим на отдалечен хост." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Функцията за умно премахване ще бъде извършена директно от отдалечената " "машина. Командите \"bash\", \"screen\" и \"flock\" трябва да бъдат " "инаталирани и достъпни на отдалечената машина." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" "Ако опцията е избрана, Back In Time първо ще тества отдалечената машина." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Преброяването на дни започва от текущият ден." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Пазете всички временни архиви за последните" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "ден (дни)." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Пази едно моментно копие на ден за последните" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Преброяването на седмиците започва от текущата. Седмицата започва в " "понеделник." #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Пазете едно моментно копие на седмица за последните" #: qt/manageprofiles/tab_remove_retention.py:352 #, fuzzy msgid "week(s)." msgstr "седмица(и)" #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Преброените месеци са календарни, започвайки с текущия." #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Пазете едно моментно копие на месец за последните" #: qt/manageprofiles/tab_remove_retention.py:365 #, fuzzy msgid "month(s)." msgstr "месец(и)" #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Преброените години са календарни, започвайки с текущата." #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Запазете последния моментен архив за всяка година за" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "Всички години." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… свободното пространство е по-малко от" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… свободните inodes са по-малко от" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Премахнете най-старите моментни архиви, ако…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Препратки" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Резевни директории" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Профил: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Профил: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Преглед на последния запис" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Стартиране на {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Изпълняване…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Вмъкване на конфигурация" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Вмъкване" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Изпълняване…" #: qt/restoreconfigdialog.py:211 #, fuzzy, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Изберете директорията за моментни архиви, от която трябва да се черпи " "конфигурационният файл. Пътят може да изглежда така: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Ако директорията се намира на външен или отдалечен диск трябва да бъде ръчно" " монтирана предварително." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Показване на скритите файлове" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Включване на файлове и директории" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Неуспех при създаването на файл в следната директория:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Покажи всички записани събития" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Изключване на системата след като моментното архивно копие е готово." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Изключване" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Изключване" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" #: qt/snapshotsdialog.py:63 #, fuzzy msgid "Options about comparing backups" msgstr "Опции за сравняване на моментни архиви" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Команда:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Параметри:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Използване на %1 и %2 за параметри на пътя" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Моля изберете diff команда или изберете Отказ." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Командата {cmd} не е открита на тази система. Моля опитайте друга команда " "или натиснете Отказ." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Не са въведени параметри за diff команда. Използване на стандартна стойност " "{params}." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Резервно копие" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Само различаващи се моментни архиви" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "Покажете само съвпадащи моментни архиви до:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Дълбока проверка (по-точна, но бавна)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Изтриване" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Избиране на всички" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Сравни" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Отиване до" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Настройки" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Наистина ли искате да изтриете {file} от моментния архив {snapshot_id}?" #: qt/snapshotsdialog.py:445 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Наистина ли искате да изтриете {file} от {count} моментни архиви?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "Това действие не може да бъде отменено." #: qt/snapshotsdialog.py:465 #, fuzzy, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Изключете {path} от бъдещите моментни архиви?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Файлова система" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Днес" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Вчера" #: qt/timeline.py:87 msgid "This week" msgstr "Тази седмица" #: qt/timeline.py:95 msgid "Last week" msgstr "Миналата седмица" #: qt/timeline.py:270 #, fuzzy msgid "This is NOT a backup but a live view of the local files." msgstr "Това НЕ е моментно копие, а текущ изглед на локалните Ви файлове" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Последна проверка {time}" backintime-1.6.1/common/po/ca.po000066400000000000000000002360621514264426600165010ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Josep Sanchez # SPDX-FileCopyrightText: © Adolfo Jayme Barrientos , 2025 # SPDX-FileCopyrightText: © Pablo Huguet # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-02 11:33+0000\n" "Last-Translator: Voodoo_Pablo \n" "Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Totes les llicències utilitzades en aquest projecte es troben al directori " "{dir_link}. Per extreure informació de llicència i drets d'autor per fitxer " "mitjançant metadades SPDX, consulteu {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Avís" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Perfil principal" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Local (xifrat amb EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (xifrat amb EncFS)" #: common/config.py:237 msgid "Local" msgstr "Local" #: common/config.py:240 msgid "Local encrypted" msgstr "Xifrat local" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Xifratge" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Clau privada SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Perfil: «{name}»" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "El directori de còpies no és vàlid." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Almenys cal seleccionar un directori per la copia de seguretat." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Directori: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Aquest directori no es pot incloure en la còpia de seguretat perquè forma " "part de la destinació mateixa de la còpia." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "El valor de \"Elimina la còpia de seguretat més antiga si l'espai lliure és " "inferior a\" ({val_one}) ha de ser inferior o igual al llindar de \"Avisa si" " l'espai lliure en disc cau per sota de\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Ajusteu la configuració de manera que el límit d'eliminació de còpies de " "seguretat no sigui superior al límit d'advertència." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "El planificador udev no funciona amb el mode {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "No s'ha pogut escriure el nou crontab ." #: common/config.py:1577 #, fuzzy msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "El cron no s'executa tot i que l'ordre crontab està disponible. Les tasques " "de còpia de seguretat programades no s'executaran. El cron pot estar " "instal·lat però no activat. Proveu l'ordre «systemctl enable cron» o " "consulteu els canals d'assistència de la vostra distribució GNU/Linux." #: common/configfile.py:101 msgid "Failed to save config" msgstr "No s'ha pogut desar la configuració" #: common/configfile.py:137 msgid "Failed to load config" msgstr "No s'ha pogut carregar la configuració" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "El perfil «{name}» ja existeix." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "No es pot eliminar l'últim perfil." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "No s'ha pogut muntar «{command}»" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "No s'ha trobat la configuració de la carpeta xifrada." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Voleu crear una nova carpeta xifrada?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Canceŀla" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "Introduïu una contrasenya per a «{user}»." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "La contrasenya no coincideix." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Fes una instantània" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "No s'ha pogut muntar «{command}»" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "No es pot desmuntar {mountprocess} des de {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "No s'ha trobat {command}. Instal·leu-lo (p. ex. amb «{installcommand}»)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "El punt de muntatge {mntpoint} no és buit." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Introduïu la contrasenya del perfil {mode} «{profile}»:" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "No s'ha pogut instal·lar la regla d'Udev per al perfil {profile_id}. El " "servei de DBus Service {dbus_interface} no estava disponible" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "No s'ha pogut trobar l'UUID per a {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "S'HA PRODUÏT UN ERROR" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Restaura els permisos" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Fet" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Les entrades següents de la llista d'inclusions no tenen cap fitxer o " "directori corresponent a l'origen de la còpia de seguretat:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Es posposa la còpia de seguretat mentre s'utilitza la bateria" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "No es pot trobar el directori de còpies." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "Si es troba en una unitat extraïble, connecteu-la." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Esperant {n} segon." msgstr[1] "Esperant {n} segons." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "No s'ha pogut fer la còpia {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Si us plau, tingueu paciència. S'està finalitzant…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "No es pot crear la carpeta." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "S'està desant el fitxer de configuració …" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "S'estan desant els permisos …" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "S’ha trobat la còpia incompleta «{snapshot_id}» que es pot continuar." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "S'està suprimint la carpeta sobrant de l'última execució: {snapshot_id}" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "No es pot eliminar el directori" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "S'està creant la còpia" #: common/snapshots.py:1517 msgid "Success" msgstr "Èxit" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Transferència parcial deguda a un error" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transferència parcial a causa de la desaparició dels fitxers d'origen (mireu" " «man rsync»)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "«rsync» ha finalitzat amb el codi de sortida {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Consulteu «man rsync» per a més detalls" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Els codis de sortida negatius de l'rsync són números de senyal; vegeu «kill " "-l» i «man kill»" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "No hi ha canvis; no cal una còpia nova" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "No es pot canviar el nom de {new_path} a {path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Aplica regles per a eliminar còpies antigues" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "Aplicar la política de retenció" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Proveu de mantenir un minim d'espai lliure" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Proveu de mantenir mínim un {perc} d'inodes lliures" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Ara" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "No s'ha pogut muntar {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "No s'ha trobat l'ssh-agent. Assegureu-vos que està instal·lat." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "No s'ha pogut desbloquejar la clau privada ssh. O la contrasenya és " "incorrecta o no és disponible per al cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "El camí remot existeix però no és un directori." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "No es pot escriure al camí remot." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "El camí remot no és executable." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "No s'ha pogut crear el camí remot." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "L'amfitrió remot {host} no admet {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "Comproveu les ordres a l'amfitrió {host} ha retornat un error desconegut" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "L'amfitrió remot {host} no admet hardlinks" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Copieu la clau SSH pública «{pubkey}» a l'amfitrió remot «{host}»." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Introduïu una contrasenya per a «{user}»." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "El sistema de fitxers de destinació per a {path} està formatat amb NTFS, que" " té incompatibilitats conegudes amb sistemes de fitxers d'estil Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} no és un directori vàlid." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "La creació del directori següent ha fallat:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "L'accés d'escriptura pot estar restringit." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "El sistema de fitxers de destinació per a {path} està formatat amb FAT que " "no admet enllaços durs. Si us plau, utilitzeu un sistema de fitxers " "GNU/Linux natiu." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "El sistema de fitxers de destinació per a {path} és una compartició muntada " "amb SMB. Assegureu-vos que el servidor remot SMB admet enllaços simbòlics o " "activeu «{copyLinks}» a «{expertOptions}»." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Copia enllaços (dereferencia els enllaços simbòlics)" #: common/tools.py:487 msgid "Expert Options" msgstr "Opcions avançades" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "El sistema de fitxers de destí per a {path} és una compartició muntada amb " "sshfs. Sshfs no admet hard-links. Utilitzeu el mode 'SSH' en el seu lloc." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "La creació del fitxer ha fallat en aquest directori:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Quant al Back in Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Drets de reproducció:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Autoria:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Traducció:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Josep Sanchez \n" "Adolfo Jayme Barrientos , 2025\n" "Pablo Huguet " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Crèdits de traductor no disponibles per a l'idioma actual." #: qt/aboutdlg.py:116 msgid "this link" msgstr "aquest enllaç" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Segueix {thislink} per obtenir crèdits de traductor per a tots els idiomes." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Lloc web del projecte" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Manual d'ús" #: qt/aboutdlg.py:227 qt/app.py:562 #, fuzzy msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Obre el manual d'usuari al navegador (local si està disponible en línia)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versió{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} sembla que sigui el primer cop que s'executa perquè no s'ha " "trobat cap configuració." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Importeu una configuració existent (des d'una carpeta d'una còpia de " "seguretat o d'un altre ordinador)?" #: qt/app.py:395 msgid "Then press OK." msgstr "A continuació, premeu D'acord." #: qt/app.py:499 msgid "Create a backup" msgstr "Crea una còpia" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Utilitza el temps de modificació i mida per a la detecció de canvis de " "fitxers." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Crea una còpia (mode suma de verificació)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Utilitza sumes de verificació per a la detecció de canvis de fitxers." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Pausa el procés de còpia" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Reprèn el procés de còpia" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Atura el procés de còpia" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Actualitza la llista de còpies" #: qt/app.py:524 msgid "Name backup" msgstr "Còpia de seguretat del nom" #: qt/app.py:528 msgid "Remove backup" msgstr "Elimina la còpia" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "Visualitza l'últim registre" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Almenys cal seleccionar un directori per la copia de seguretat." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "Visualitza l'últim registre" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Veure el registre de la darrera còpia de seguretat." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Gestiona els perfils…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Edita user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Aturada" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Apaga el sistema després d'acabar la còpia." #: qt/app.py:552 msgid "Setup language…" msgstr "Configura la llengua…" #: qt/app.py:556 msgid "Exit" msgstr "Surt" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "pàgina de manual: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Mostra la pàgina de manual sobre Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "Página Manual: Perfils de config file" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Mostra la pàgina de manual sobre el fitxer de configuració de perfils " "(backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Obre el lloc web del Back In Time al navegador" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Registre de canvis" #: qt/app.py:586 #, fuzzy msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Obre el manual d'usuari al navegador (local si està disponible en línia)" #: qt/app.py:589 msgid "FAQ" msgstr "Preguntes freqüents" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Obriu Preguntes freqüents (FAQ) al navegador" #: qt/app.py:593 msgid "Ask a question" msgstr "Feu una pregunta" #: qt/app.py:597 msgid "Report a bug" msgstr "Informar d'un error" #: qt/app.py:600 msgid "Translation" msgstr "Traducció" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Mostra de nou el missatge sobre la participació en la traducció." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Transició del xifratge (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Mostra de nou el missatge sobre l'eliminació d'EncFS." #: qt/app.py:615 msgid "About" msgstr "Quant a" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Restaura" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "" "Restaura els fitxers o carpetes seleccionades a la destinació original." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Restaura a …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "Restaura els fitxers o carpetes seleccionades a una destinació nova." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Restaura la carpeta mostrada actualment i tot el seu contingut a la " "destinació original." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Restaura la carpeta mostrada actualment i tot el seu contingut a una nova " "destinació." #: qt/app.py:640 msgid "Up" msgstr "Amunt" #: qt/app.py:643 msgid "Show hidden files" msgstr "Mostra els fitxers ocults" #: qt/app.py:646 msgid "Compare backups…" msgstr "Compara les còpies…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Candidat d'alliberament" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Torna a mostrar el missatge sobre aquest candidat a la versió." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Còpia de seguretat" #: qt/app.py:733 msgid "&Restore" msgstr "&Restaura" #: qt/app.py:739 msgid "&Help" msgstr "&Ajuda" #: qt/app.py:790 msgid "Systray Icon" msgstr "Icona Systray" #: qt/app.py:796 msgid "Automatic" msgstr "Automàtic" #: qt/app.py:800 msgid "Light icon" msgstr "Icona Light" #: qt/app.py:801 msgid "Dark icon" msgstr "Icona Dark" #: qt/app.py:824 msgid "Icons only" msgstr "Només icones" #: qt/app.py:827 msgid "Text only" msgstr "Només text" #: qt/app.py:830 msgid "Text below icons" msgstr "Text a sota de les icones" #: qt/app.py:833 msgid "Text beside icon" msgstr "Text al costat de la icona" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Aquesta carpeta no existeix\n" "a la snapshot seleccionada." #: qt/app.py:1005 msgid "Add to Include" msgstr "Afegeix a la inclusió" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Afegeix a l'exclusió" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Si tanqueu aquesta finestra, el Back In Time no podrà apagar el sistema quan" " s'hagi finalitzat la còpia." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Voleu tancar la finestra de totes maneres?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Fet, no ha estat necessari crear una còpia de seguretat" #: qt/app.py:1285 msgid "Working:" msgstr "S'està treballant:" #: qt/app.py:1292 msgid "Working" msgstr "Treballant" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Error" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Enviat:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Velocitat:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "Còpies:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Restaura {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Restaura {path} a …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hola\n" "Heu utilitzat el Back In Time en l'idioma {language} unes quantes vegades.\n" "La traducció de la vostra versió instal·lada de Back In Time a {language} està un {perc} completada. Independentment del seu nivell d'experiència tècnica, pot contribuir a la traducció i, per tant, en Back In Time mateix.\n" "Visiteu {translation_platform_url} si voleu col·laborar. Per obtenir més assistència i preguntes, visiteu {back_in_time_project_website}.\n" "Demanem disculpes per la interrupció i aquest missatge no es tornarà a mostrar. Aquest diàleg està disponible en qualsevol moment a través del menú d'ajuda.\n" "L'equip de Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "plataforma de traducció" #: qt/app.py:1714 msgid "Website" msgstr "Lloc web" #: qt/app.py:1728 msgid "Your translation" msgstr "la teva traducció" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Al fedivers, a Mastodon: {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Llista de correu {link_and_label}" #: qt/app.py:1774 #, fuzzy, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Llista de correu {link_and_label}" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} al lloc web del projecte." #: qt/app.py:1781 msgid "Open an issue" msgstr "Obre un problema" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Alternativament, podeu utilitzar un altre canal que trieu." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Aquesta versió de Back In Time és una versió candidata i està destinada principalment a proves d'estabilitat en preparació per al proper llançament oficial.\n" "No es recullen dades d'usuari ni telemetria. Tanmateix, l'equip de Back In Time està molt interessat a saber si s'està utilitzant el Release Candidate i si val la pena continuar proporcionant aquestes versions prèvies.\n" "Per tant, l'equip demana amablement un breu comentari sobre si heu provat aquesta versió, fins i tot si no heu trobat cap problema. Fins i tot una prova ràpida d'uns minuts ens ajudaria molt.\n" "Les opcions de contacte següents estan disponibles:\n" "{contact_list}\n" "En aquesta versió, aquest missatge no es tornarà a mostrar, però es pot accedir en qualsevol moment mitjançant el menú d'ajuda.\n" "Gràcies pel vostre suport i per ajudar-nos a millorar Back In Time!\n" "El teu equip de Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Només hi ha {free} espai lliure disponible a la destinació, que està per " "sota del llindar configurat de {threshold}." #: qt/app.py:1897 #, fuzzy msgid "Proceed with the backup?" msgstr "Voleu eliminar aquesta còpia?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Tots els fitxers més nous de {path} s'eliminaran. Voleu continuar?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Tots els fitxers més nous del directori original s'eliminaran. Voleu " "continuar?" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}AVÍS:{BOLDEND} Esborrar fitxers a l'arrel del sistema de fitxers " "podria trencar tot el sistema." #: qt/app.py:2167 msgid "Backup name" msgstr "Nom de la còpia" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Voleu eliminar aquesta còpia?" msgstr[1] "Voleu eliminar aquestes còpies?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "La configuració de la llengua només tindrà efecte després de reiniciar Back " "In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Còpies de seguretat versionades (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "GUI fàcil d'utilitzar per a còpies de seguretat versionades que redueix l'ús" " del disc (mode root)" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "No eliminis les snapshots amb nom." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "GUI fàcil d'utilitzar per a còpies de seguretat versionades que redueix l'ús" " del disc" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Pregunta" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Crea còpies de seguretat amb {suffix} al final abans de\n" "sobreescriure o esborrar fitxers locals." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Les versions més noves dels fitxers es canviaran de nom amb el final " "{suffix} abans de restaurar. Si ja no els necessiteu, podeu eliminar-los amb" " la següent comanda:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Restaura només els fitxers que no existeixen o\n" "són més nous que els de destí.\n" "S'utilitza l'opció «rsync --update»." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Elimina els elements més nous del directori original." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Restaura els fitxers o carpetes seleccionats al destí original i suprimeix " "els fitxers o directoris que no són a la instantània. Aneu amb compte perquè" " això suprimirà els fitxers i carpetes exclosos de la instantània." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Segur que voleu restaurar aquest element al directori nou?" msgstr[1] "Segur que voleu restaurar aquests elements al directori nou?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Segur que voleu restaurar aquest element?" msgstr[1] "Segur que voleu restaurar aquests elements?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "L'script de crida de retorn de l'usuari ha d'incloure un shebang a la " "primera línia (per exemple, {example})." #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Inclou fitxers i carpetes" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Llenguatge de configuració" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Traduït: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "sistema per defecte" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Utilitza la llengua del sistema operatiu." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "Última visualització dels registres" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Última visualització dels registres" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Perfil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Còpies:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtre:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E]Error, [I]Informació, [C]Canvia" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "descodifica rutes" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Tots" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Canvis" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Errors" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informació" msgstr[1] "Informacions" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "Errors de transferència de rsync (experimental)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Gestiona els perfils" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Edita" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Afegeix" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Elimina" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&General" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Inclou" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Exclou" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Eliminar & &Retenir" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Opcions" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Opcions d'e&xperts" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Restaura la configuració" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Perfil nou" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Reanomena el perfil" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Voleu suprimir el perfil «{name}»?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Copiar enllaços simbòlics com a fitxers" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Copia els enllaços simbòlics com a fitxers o directoris reals a la còpia de " "seguretat. Selecciona si es copien tots els enllaços o només els que apunten" " fora de l'origen." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Aquesta opció pot augmentar la mida de la còpia de seguretat." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Desactivat per defecte." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Tots els enllaços simbòlics es substitueixen per fitxers o directoris reals " "als quals apunten. Això augmenta la mida de la còpia de seguretat i pot " "emmagatzemar els mateixos fitxers diverses vegades." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Només extern" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Només es copien com a fitxers els enllaços que apunten fora de l'origen de " "la còpia de seguretat. Això augmenta la mida de la còpia de seguretat i pot " "emmagatzemar els mateixos fitxers diverses vegades." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Editor i fitxers temporals d'Office" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Pausa el procés de còpia" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Exclou el fitxer" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Fitxers d'intercanvi de Vim" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Fitxers temporals de Microsoft Office" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "Fitxers de bloqueig de LibreOffice i altres editors d'OpenDocument" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniatures i imatges temporals" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "Memòria cau de miniatures a GNU/Linux i altres sistemes operatius Unixoid" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Base de dades de miniatures a Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Directori de metadades a MacOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Application-specific bloquejats" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Fitxer de bloqueig de l'aplicació Discord" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Fitxer de bloqueig de sessió de Discord" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Fitxer de bloqueig de Mozilla Firefox i Thunderbird" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Directoris de còpia de seguretat" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Cache de l'aplicació de l'Usuari" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "No es pot eliminar el directori" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Cache dels paquets per a distribucions GNU/Linux basades en Debian" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Repositori d'aplicacions i temps d'execució de Flatpak" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Mostra els fitxers ocults" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Informació del kernel i del procés" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" "Informació del dispositiu i altra informació del maquinari (interfície " "sysfs)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Nodes de dispositiu" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Fitxers del sistema en temps d'execució" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Altres no persistents" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Llista de sistemes de fitxers muntats actualment" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Fitxer d'intercanvi del sistema (memòria virtual)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Punt de muntatge del sistema de fitxers virtual del GNOME" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Objectes del sistema de fitxers recuperats" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Miscelanea" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Directori de metadades a Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Paperera de reciclatge de l'usuari" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Atura el procés de còpia" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Exclou el directori" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Seleccioneu els elements que s'utilitzen habitualment per afegir-los a les " "exclusions de còpia de seguretat." #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "per defecte" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Restableix a la selecció predefinida" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Planificació" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Día:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Entre setmana:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Temps:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Hores:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "després de l'hora" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minuts:" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Executa Back in Time bon punt es connecti la unitat (només una vegada cada X" " dies). Se us demanarà la contrasenya del sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Executa Back In Time repetidament. Això és útil si l'ordinador no s'està " "executant regularment." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Cada:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Activa el registre dels missatges de depuració" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Escriu missatges de nivell de depuració al registre del sistema mitjançant " "«--debug»." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Precaució: utilitzeu-lo només temporalment per a diagnòstics, ja que genera " "una gran quantitat de sortida." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Deshabilitat" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "En cada inici/reinici" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Cada minut" msgstr[1] "Cada {n} minuts" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Cada hora" msgstr[1] "Cada {n} hores" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Hores personalitzades" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Cada dia" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Repetidament (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Quan la unitat es connecti (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Cada setmana" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Cada mes" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Cada any" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Hora(es)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dia(es)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Setmana(es)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mes(os)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Les hores personalitzades només poden ser una llista d'hores separades per " "comes (p.e. 8,12,18,23) o */3 per fer còpies periòdiques cada 3 hores." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Zvolte existující soubor se soukromým klíčem odjinud." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Vytvořit nový SSH klíč (bez heslové fráze)." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Úplný popis umístění: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Soukromý klíč:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Použít nastavení SSH ze systému" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Ponechá soubor s klíčem nevybrán. Připojení k SSH budou spoléhat na " "existující nastavení klienta v systému (např. ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH proxy" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Stroj:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Uživatel:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Připojit k cíli prostřednictvím této proxy (známé také jako tzv. „jump " "host“). Podrobnosti viz „-J“ v dokumentaci příkazu „ssh“ nebo „ProxyJump“ v " "manuálové stránce „ssh_config“." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Pro informaci{ENDBOLD}: V režimu „Přes SSH (v šifrované podobě)“ " "funguje pouze jedna nebo dvě hvězdičky (např. {example2}). Ostatní typy " "zástupných vyjádření a vzorů budou ignorovány (např. {example1}) Názvy " "souborů se totiž v tomto režimu kvůli EncFS šifrování nedají předvídat." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Vynechat zástupně vyjádřené, soubory a složky" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Přidat vzor" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Přidat soubory" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Přidat složky" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Doporučení" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Vyberte z běžně používaných položek pro přidání do seznamu vynechávaných." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Vynechat soubory větší než:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Vynechat soubory větší než hodnota v {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "V případě, že není používán „Úplný rsync režim“, bude se toto týkat pouze " "nově vytvořených souborů, protože pro nástroj rsync je toto předvolba " "přenosu, nikoli vynechání. Takže, velké soubory, které byly zazálohovány už " "dříve, v zálohách zůstanou, i když od té doby byly změněny." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Zástupné vyjádření vynechaného" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Zadejte vzor vynechávaného:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Ohledně nápovědy nahlédněte do manuálové stránky rsync, sekce {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Otevřít manuálovou stránku rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Vynechat soubory" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Vynechat složky" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Vypnuto protože tento vzor není funkční v režimu „Přes SSH (v šifrované " "podobě)“." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Tyto předvolby jsou pro pokročilá nastavení. Měňte je pouze pokud jste si " "plně vědomi jejich důsledků." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Spouštět nástroj rsync s parametrem „{cmd}“:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "když jako naplánovaná úloha (cron)" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "při zálohování na vzdálený stroj" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "při ručně spuštěné záloze" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Pokud chcete zapnout tuto možnost, nainstalujte nástroj „nocache“." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "při ukládání záloh přímo na zálohovaném počítači" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" "U naplánovaných úloh (cron) zahazovat výstup (stdout) (přesměrováním do " "/dev/null)." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Pokud je nainstalován (a nastaven) MTA, cron automaticky pošle e-mail s " "přiloženým výstupem z naplánovaných úloh." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" "U naplánovaných úloh (cron) zahazovat chybový výstup (stderr) (přesměrováním" " do /dev/null)." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Pokud je nainstalován (a nastaven) MTA, cron automaticky pošle e-mail s " "přiloženými chybami naplánovaných úloh." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Omezit využití přenosové kapacity, zabrané nástrojem rsync, na:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Zálohovat včetně seznamů řízení přístupu (ACL)" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Zálohovat včetně rozšířených atributů (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Nepřekračovat (přípojnými body) do dalších souborových systémů" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Je třeba, aby předvolby byly obklopeny uvozovkami, např. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Vložte dodatečné parametry pro rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Předpona kterou spouštět před každým příkazem na vzdáleném stroji." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Proměnné je třeba zbavit jejich významu pomocí zpětného lomítka (příklad: " "\\$NECO). Toto se nedotýká nástroje rsync. Předponu pro rsync tedy přidáte " "pomocí „{example_value}“ s {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "výchozí" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Před příkazy přes SSH přidávat" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Zkontrolujte zda je vzdálený stroj dostupný na síti" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Varování: pokud vypnuto a vzdálený stroj není dostupný, může toto vést k " "některým podivným chybám." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Ověřit zda vzdálený stroj podporuje všechny nezbytné příkazy." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Varování: pokud vypnuto a vzdálený stroj nepodporuje veškeré nezbytné " "příkazy, může toto vést k některým podivným chybám." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(výchozí: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "vypnuto" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "zapnuto" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Režim:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Kam ukládat zálohy" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Nastavení pro SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Umístění:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Soubor s klíčem:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Heslo pro" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Uložit heslo do klíčenky desktopového prostředí" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Uložit heslo pro potřeby plánovače Cron (slabina v zabezpečení: správce " "systému si heslo může přečíst)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Pokročilé" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Úplný popis umístění zálohy:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Plánování je vypnuté protože nebyla nalezena instalace plánovače cron. Pokud" " chcete zapnout plánování záloh, nainstalujte ho." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Je třeba, aby popis umístění cíle zálohy nebyl prázdný." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Šifrovací heslo je třeba vyplnit." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Došlo k chybě při pokusu o přihlášení se ke vzdálenému stroji. Byla vrácena " "následující chybová zpráva:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Chcete-li povolit přihlášení bez hesla, můžete zkopírovat veřejný SSH klíč " "na vzdálený stroj." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Pokračovat kopírováním SSH klíče?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Veřejný SSH klíč nebylo možné zkopírovat. To může být kvůli problému s " "připojením nebo oprávněním." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Nepodvrženost stroje „{host}“ se nepodařilo ověřit." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Otisk {keytype} klíče je:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "Zkontrolujte tento otisk! Přidat ho do souboru „known_hosts“?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Opravdu změnit složku se zálohou?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Vybraný popis cíle zálohování není prázdný." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Pokud chcete použít šifrování, je třeba, aby (složka) byla prázdná." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Neplatný soubor: Není soukromým SSH klíčem" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Vybraný soubor ({path}) je veřejný SSH klíč. Vyberte namísto něho " "odpovídající soukromý klíč (bez přípony „.pub“)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Soubor {path} už existuje. Nebylo možné vytvořit nový SSH klíč s takovým " "názvem." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "V umístění {path} se nepodařilo vytvořit nový SSH klíč." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Zahrnout soubory a složky" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "„{path}“ je symbolický odkaz. Odkazovaný cíl nebude zazálohován, dokud jeho " "umístění také výslovně nezahrnete." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Zahrnout namísto toho cíl symbolického odkazu?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Zahrnout soubory" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Zahrnout složky" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "" "Zobrazovat oznámení (prostřednictvím centra oznámení desktopového prostředí)" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Nezálohovat při provozu na akumulátor" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Údaje o stavu napájení nejsou ze systému k dispozici" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Pořizovat pouze jednu zálohu naráz" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Pořizování ostatních záloh bude blokováno do dokončení té právě probíhající." " Toto je globální předvolba, takže se bude týkat všech profilů tohoto " "uživatele. Zapíná se ale pro každého uživatele zvlášť." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Zazálohovat soubory, které by byly při procesu obnovování nahrazeny" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Pokračovat i v případě výskytu chyb (zachovat i neúplné zálohy)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "" "Zda se soubory, určené k zálohování změnily zjišťovat pomocí jejich " "kontrolního součtu (přesnější)" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Vytvořit novou zálohu i v případě, že nedošlo k žádným změnám." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Varovat pokud volný prostor na disku poklesne pod" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Zobrazí varování pokud volný prostor na disku, na který je směrována záloha," " je menší než zadaná hodnota." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Pokud je zapnuto pravidlo pro „Odstraňování a uchovávání“ a staré zálohy " "jsou odebírány na základě dostupného volného místa, tato hodnota nemůže být " "nižší než hodnota nastavená v pravidle." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Podrobnost zaznamenávání událostí (log):" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nic" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "uživatelská příručka" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Následující pravidla jsou zpracovávána od začátku seznamu směrem k jeho " "konci. Pozdější pravidla přebíjí ta dřívější. Ohledně podrobností a ukázek " "viz {manual_link}." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Otevřít uživatelskou příručku v prohlížeči." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Ponechávat nejnovější zálohu." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Nejnovější záloha je uchovávána v každém případě." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Toto chování není možné změnit." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Neodstraňovat ty zálohy, které uživatel nějak nazval." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Zálohy, kterým byl dán název (nad rámec obvyklého časového razítka), budou " "za všech okolností zachovávány a nebudou odebrány." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Let" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Odstranit zálohy starší než" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Celé dny. Stávající den je ignorován." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Týdny v kalendáři s pondělím coby prvním dnem. Stávající týden je ignorován." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12 měsíční periody. Stávající měsíc je ignorován." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Zásada uchovávání" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Na vzdáleném stroji spustit na pozadí." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Zásada uchovávání bude spuštěna přímo na vzdáleném stroji, nikoli lokálně. " "Na vzdáleném stroji je třeba, aby byly nainstalovány a k dispozici příkazy " "„bash“, „screen“ a „flock“." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Pokud vybráno, Back In Time nejprve vyzkouší vzdálený stroj." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dny jsou počítány ode dneška." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Ponechat všechny zálohy za uplynulých" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "dnů." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Ponechat poslední zálohu z každého dne za uplynulých" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "Týdny jsou počítány od toho stávajícího. Týdny začínají v pondělí." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Ponechat poslední zálohu z každého týdne za uplynulých" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "týdnů." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Měsíce jsou počítány jako kalendářní a začíná se stávajícím měsícem." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Ponechat poslední zálohu z každého měsíce za uplynulých" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "měsíců." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Roky jsou počítány jako kalendářní a začíná se stávajícím rokem." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Ponechat poslední zálohu z každého roku za" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "za všechna leta." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… pokud volného místa zbývá méně než" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "" "… pokud z počtu složek a souborů, které lze na souborovém systému vytvořit " "(inode), zbývá méně než" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Odebrat nejstarší zálohu pokud…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" "Pokud chcete Back In Time spustit jako správce systému (root), je zapotřebí " "se příslušně ověřit." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Pro plánování záloh spouštěných připojeními externího úložného zařízení je " "třeba se ověřit." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Zkratky" #: qt/placeswidget.py:63 msgid "Places" msgstr "Místa" #: qt/placeswidget.py:64 msgid "File System" msgstr "Souborový systém" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Složky zálohy" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: „{profile_name}“" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: „{profile_name}“ (od uživatele „{desktop_user}“)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Zobrazit záznam nedávných událostí" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Spustit {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Zpracování…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "manuálová stránka: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Naimportovat nastavení" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Nevybrána žádná složka" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Naimportovat" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Hledání…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Vyberte složku se zálohami ze které má být naimportován soubor s " "nastaveními. Popis umístění může vypadat jako: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Pokud se složka nachází na externí nebo síťové jednotce – je třeba ji předem" " ručně připojit." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Proskenovat znovu" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Zobrazovat skryté složky" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Zahrnout/skrýt skryté složky (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "V této složce nenalezena žádná nastavení" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Hledání dokončeno." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Zobrazit kompletní záznam událostí" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Odpočet do vypnutí" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Záloha dokončena." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Zrušit vypínání" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Vypnout nyní" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Systém bude vypnut za {n} sekundu." msgstr[1] "Systém bude vypnut za {n} sekundy." msgstr[2] "Systém bude vypnut za {n} sekund." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Předvolby pro porovnávání záloh" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Příkaz:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametry:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Jako parametry umístění použijte %1 a %2" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Nastavte příkaz pro zjišťování rozdílů nebo klikněte na Storno." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Příkaz „{cmd}“ se nepodařilo v systému najít. Zkuste něco jiného nebo " "klikněte na Storno." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Nenastaveny žádné parametry pro příkaz diff. Náhradně bude použita výchozí " "hodnota „{params}“." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Zálohy" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Pouze odlišující se zálohy" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Vypsat pouze zálohy, shodné s:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Hloubková kontrola (přesnější, ale pomalejší)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Smazat" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Vybrat vše" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Porovnat" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Přejít na" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Předvolby" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Není možné porovnat zálohu samu se sebou – takové porovnání by bylo " "zbytečné." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Opravdu vymazat {file_or_dir} v záloze {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Opravdu vymazat {file_or_dir} v {count} zálohách?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "VAROVÁNí: Toto nelze vzít zpět." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Vynechat {path} z budoucích záloh?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Režim správce" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time je v tuto chvíli spuštěné s oprávněními správce systému (root)," " tedy s přístupem kamkoli v systému" #: qt/timeline.py:69 msgid "Today" msgstr "Dnes" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Včera" #: qt/timeline.py:87 msgid "This week" msgstr "Tento týden" #: qt/timeline.py:95 msgid "Last week" msgstr "Minulý týden" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Toto NENÍ zachycený stav, ale pohled přímo do stávajících souborů na tomto " "počítači." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Minulá kontrola {time}" backintime-1.6.1/common/po/da.po000066400000000000000000002273411514264426600165020ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Adam Sjøgren # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-01-28 11:56+0000\n" "Last-Translator: asjo \n" "Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Alle licenser relevante for dette projekt findes i {dir_link}-mappen. For at" " udtrække licens- og ophavsretsinformation i SPDX metadata format per fil, " "se {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Advarsel" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Hovedprofil" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokal (EncFS krypteret)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS krypteret)" #: common/config.py:237 msgid "Local" msgstr "Lokal" #: common/config.py:240 msgid "Local encrypted" msgstr "Lokalt krypteret" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Kryptering" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Privat SSH nøgle" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Tilstandsbillede-mappe er ugyldig." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Mindst en mappe skal vælges til backup." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Mappe: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Denne mappe kan ikke inkluderes i sikkerhedskopien, da den er del af " "sikkerhedskopiens destination." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Værdien for \"Slet ældste tilstandsbillede hvis ledig plads er mindre end\" " "({val_one}) skal være mindre end eller lig med grænsen for \"Advar hvis " "ledig plads falder under\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Juster venligst indstillingen så tilstandsbilledesletningsgrænsen ikke er " "højere end advarselsgrænsen." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udev-planlægning virker ikke med indstilling {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Kunne ikke skrive ny crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron kører ikke, selvom crontab-kommandoen er tilgængelig. Planlagte backup-" "job vil ikke blive kørt. Cron kan være installeret, men ikke aktiveret. Prøv" " kommandoerne “systemctl enable cron” og \"systemctl start cron\" eller " "kontakt hjælpekanalerne for din GNU/Linux-distribution for hjælp." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Kunne ikke gemme konfiguration" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Kunne ikke læse konfiguration" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profil \"{name}\" findes allerede." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Den sidste profil kan ikke slettes." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Kan ikke tilslutte \"{command}\"" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Opsætning for krypteret mappe ikke fundet." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Lav en ny krypteret mappe?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Annullér" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Genindtast venligst EncFS-kodeordet for at bekræfte." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS-kodeordet passer ikke." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Tag et tilstands-billede" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Ude af stand til at initialisere krypteret sti \"{command}\"" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Kan ikke fjerne {mountprocess} fra {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} ikke fundet. Installér venligst (f.eks. med \"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Tilsluttelsespunkt {mntpoint} er ikke tomt." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Indtast adgangskode for {mode} profil \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Kunne ikke installere Udev regel for profil {profile_id}. DBus Service " "'{dbus_interface}' var ikke tilgængelig." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Fandt ikke UUID for {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "MISLYKKEDES" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Gendan tilladelser" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Færdig" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "De følgende indgang i inkluderingslisten har ikke nogen tilsvarende fil " "eller mappe i tilstandsbillede-kilden:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Venter med backup under batteridrift" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Kan ikke finde tilstandsbillede-mappen." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Hvis den er på et flytbar drev, tilslut venligst drevet." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Venter {n} sekund." msgstr[1] "Venter {n} sekunder." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Kunne ikke tage tilstandsbillede {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Hav venligst tålmodighed. Færdigører…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Kan ikke oprette mappe." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Gemmer konfigurationsfil…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Gemmer tilladelser…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Fandt efterladt tilstandsbillede {snapshot_id} som kan fortsættes med." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Sletter efterladt {snapshot_id}-mappe fra seneste kørsel" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Kan ikke fjerne mappe" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Opretter tilstandsbillede" #: common/snapshots.py:1517 msgid "Success" msgstr "Succes" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Delvist overført på grund af fejl" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Delvis overførsel da nogle filer fra kilden er forduftet (se 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' afsluttede med slutværdien {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Kig i 'man rsync' for flere detaljer" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "Negative rsync slutværdier er signalnumre, se 'kill -l' og 'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Ingen ændringer, så et nyt tilstandsbillede er ikke nødvendigt" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Kan ikke omdøbe {new_path} til {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Bruger regler til at fjerne gamle tilstandsbilleder" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Bruger bevaringspolitik" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Prøv at holde minimum fri plads" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Prøver at holde mindst {perc} inoder fri" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Nu" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Kan ikke tilslutte {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "Kan ikke finde ssh-agent. Sørg venligst for at den er installeret." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Kunne ikke fjerne låsen på ssh privat nøgle. Forkert kodeord elle kodeordet " "er ikke tilgængelig for cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Stien findes i den anden ende, men er ikke en mappe." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Stien i den anden ende er ikke skrivbar." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Stien i den anden ende er ikke eksekverbar." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Kan ikke oprette fjernmappe." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Den anden maskine {host} understøtter ikke {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Check-kommandoerne på vært {host} gav en ukendt fejl" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Den anden maskine {host} understøtter ikke hardlinks" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Kopiér offentlig ssh-nøgle \"{pubkey}\" til vært \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Indtast venligst et kodeord for \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Destinationsfilsystem for {path} er formatteret med NTFS, som ikke er fuldt " "kompatibelt med UNIX-lignede filsystemer." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} er ikke en gyldig mappe." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Oprettelse af følgende mappe fejlede:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Skriveadgang kan være begrænset." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Destinationsfilsystem for {path} er formatteret med FAT, som ikke kan " "håndtere hard-links. Brug venligst et understøttet GNU/Linux-filsystem." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Destinationsfilsystem for {path} er delt via SMB. Undersøg venligst om SMB " "serveren understøtter symlinks eller aktiver {copyLinks} i {expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopier links (følg symbolske links)" #: common/tools.py:487 msgid "Expert Options" msgstr "Avancerede indstillinger" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Destinationsfilsystemet for {path} er delt via ssfhs. Sshfs understøtter " "ikke hardlinks. Benyt venligst 'SSH' mode i stedet." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Filoprettelse fejlede i mappe:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Om Back In &Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Ophavsret:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Forfattere:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Oversættere:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Adam Sjøgren " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Oversætterinformation er ikke tilgængelig for det nuværende sprog." #: qt/aboutdlg.py:116 msgid "this link" msgstr "dette link" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "Følg {thislink} for at se oversætterinformation for alle sprog." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Projektets hjemmeside" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Brugervejledning" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Åbn brugervejledning i browser (lokal hvis tilgængelig, ellers på nettet)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Version{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} ser ud til at køre for første gang, eftersom der ingen " "konfiguration var." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Importer en eksisterende konfiguration fra en tilstandsbillede-" "destinationsmappe eller anden computer?" #: qt/app.py:395 msgid "Then press OK." msgstr "Tryk derefter OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Opret et tilstandsbillede" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Brug ændringstid og størrelse til at opdage filændringer." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Opret et tilstandsbillede (checksum modus)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Brug checksummer til at opdage filændringer." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Sæt tilstandsafbildning på pause" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Genoptag tilstandsafbildning" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Stop tilstandsafbildning" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Opdatér tilstandsbillede-liste" #: qt/app.py:524 msgid "Name backup" msgstr "Navngiv tilstandsbillede" #: qt/app.py:528 msgid "Remove backup" msgstr "Fjern tilstandsbillede" #: qt/app.py:532 msgid "Open backup log" msgstr "Åben tilstandsbillede-log" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Se log for det valgte tilstandsbillede." #: qt/app.py:536 msgid "Open last backup log" msgstr "Åben seneste tilstandsbillede-log" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Se log fra det seneste tilstandsbillede." #: qt/app.py:540 msgid "Manage profiles…" msgstr "hovedprofil…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Redigér bruger-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Luk ned" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Luk ned når tilstandsbilledet er færdiggjort." #: qt/app.py:552 msgid "Setup language…" msgstr "Sæt sprog op…" #: qt/app.py:556 msgid "Exit" msgstr "Afslut" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man-side: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Viser man-side om Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man-side: Profilkonfigurationsfil" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "Viser man-side om profilkonfigurationsfil (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Åbn Back In Time hjemmeside i browser" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Ændringslog" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Åbn listen over ændringer i weblæser (lokal hvis tilgængelig, ellers på " "nettet)" #: qt/app.py:589 msgid "FAQ" msgstr "OSS" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Åbn Ofte Stillede Spørgsmål (OSS) i browser" #: qt/app.py:593 msgid "Ask a question" msgstr "Stil et spørgsmål" #: qt/app.py:597 msgid "Report a bug" msgstr "Rapporter en fejl" #: qt/app.py:600 msgid "Translation" msgstr "Oversættelse" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Vis beskeden om deltagelse i oversættelse igen." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Krypteringsovergang (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Vis besked fjernelse af EncFS igen." #: qt/app.py:615 msgid "About" msgstr "Om" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Gendan" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Gendan de valgte filer eller mapper på det oprindelige sted." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Gendan …" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Gendan de valgte filer eller mapper på et nyt sted." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "Gendan den viste mappe og al dens indhold på det oprindelige sted." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "Gendan den viste mappe og al dens indhold på et nyt sted." #: qt/app.py:640 msgid "Up" msgstr "Op" #: qt/app.py:643 msgid "Show hidden files" msgstr "Vis skjulte filer" #: qt/app.py:646 msgid "Compare backups…" msgstr "Sammenlign tilstandsbilleder…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "kandidat til udgivelse" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Vis beskeden om denne udgivelseskandidat igen." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Sikkerhedskopiér" #: qt/app.py:733 msgid "&Restore" msgstr "&Gendan" #: qt/app.py:739 msgid "&Help" msgstr "&Hjælp" #: qt/app.py:790 msgid "Systray Icon" msgstr "Statusikon" #: qt/app.py:796 msgid "Automatic" msgstr "Automatisk" #: qt/app.py:800 msgid "Light icon" msgstr "Lyst ikon" #: qt/app.py:801 msgid "Dark icon" msgstr "Mørkt ikon" #: qt/app.py:824 msgid "Icons only" msgstr "Alene ikoner" #: qt/app.py:827 msgid "Text only" msgstr "Alene tekst" #: qt/app.py:830 msgid "Text below icons" msgstr "Tekst under ikoner" #: qt/app.py:833 msgid "Text beside icon" msgstr "Tekst ved siden af ikon" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Denne mappe findes ikke\n" "i det valgte tilstandsbillede." #: qt/app.py:1005 msgid "Add to Include" msgstr "Tilføj til Inkludér" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Tilføj til Spring over" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Hvis du lukker dette vindue så kan Back In Time ikke lukke din maskine ned " "når tilstandsbilledet er færdigt." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Luk vinduet alligevel?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Færdig, ingen sikkerhedskopiering nødvendig" #: qt/app.py:1285 msgid "Working:" msgstr "Arbejder:" #: qt/app.py:1292 msgid "Working" msgstr "Arbejder" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Fejl" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Sendt:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Hastighed:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 msgid "Backup:" msgstr "&Sikkerhedskopier:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Gendan {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Gendan {path} …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hej\n" "Du har nu brugt Back In Time på {language} et par gange nu.\n" "Oversættelsen af din version af Back In Time i {language} er {perc} færdig oversat. Ligegyldigt af niveau kan du hjælpe med oversættelsen og derved Back In Time.\n" "Besøg venligst {translation_platform_url} hvis du ønsker at kontribuere. For yderlige hjælp eller spørgsmål, besøg venligst {back_in_time_project_website}.\n" "Vi undskylder forstyrrelsen, denne besked vil ikke blive vist igen. Denne dialog box er tilgængelig til enhver tid i 'hjælp' menuen.\n" "Dit Back In Time Team" #: qt/app.py:1709 msgid "translation platform" msgstr "oversættelses platform" #: qt/app.py:1714 msgid "Website" msgstr "Websted" #: qt/app.py:1728 msgid "Your translation" msgstr "Din oversættelse" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "I fødiverset på Mastodon: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Email til {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Emailliste {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} på projektets hjemmeside." #: qt/app.py:1781 msgid "Open an issue" msgstr "Opret en fejlrapport" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Eller du kan benytte en anden mulighed du foretrækker." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Denne udgave af Back In Time er en udgivelseskandidat og er primært tiltænkt stabilitetstest som forberedelse til næste udgivelse.\n" "Ingen brugerdata eller telemetri opsamles. Men, Back In Time-holdet er meget interesseret i at vide om udgivelseskandidaten bliver brugt og om det er værd at fortsætte med at stille sådanne før-udgivelses versioner til rådighed.\n" "Derfor beder holdet dig om kort at tilkendegive om du har prøvet denne udgave, også hvis du ikke oplevede nogle problemer. Selv en hurtig testkørsel på et par minutter hjælper os.\n" "De følgende kontaktmåder findes:\n" "{contact_list}\n" "I denne udgave vises denne besked ikke igen, men du kan altid se den igen i hjælpemenuen.\n" "Tak for din støtte og for at hjælpe os med at gøre Back In Time bedre!\n" "Dit Back In Time-hold" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Kun {free} plads fri på målet, hvilket er under den opsatte grænse på " "{threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Forsæt med at danne tilstandsbillede?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Alle nyere filer i {path} vil blive slettet. Fortsæt?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "Alle nyere filer i den oprindelige mappe vil blive slettet. Fortsæt?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Advarsel{BOLDEND}: Hvis du sletter filer i filsystemets rod risikerer " "du at ødelægge hele dit system." #: qt/app.py:2167 msgid "Backup name" msgstr "Tilstandsbillede-navn" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Slet dette tilstandsbillede?" msgstr[1] "Slet disse tilstandsbilleder?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "Sprogopsætningen ændres først efter genstart af Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Versionerede tilstandsbilleder (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Brugervenligt grafisk interface for versionerede tilstandsbilleder der " "reducerer lagerforbrug (root mode)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Versionerede tilstandsbilleder" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Brugervenligt grafisk interface for versionerede tilstandsbilleder der " "reducerer lagerforbrug" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Spørgsmål" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Opret sikkerhedskopier med {suffix} tilføjet før lokale elementer " "overskrives eller fjernes." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Nyere version af filer vil blive omdøbt med {suffix} tilføjet før " "genddannelse. Hvis du ikke har brug for dem længere, kan de fjernes med " "denne kommando:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Gendan alene elementer som ikke findes eller er nyere end dem der findes. " "Bruger \"{rsync_example}\" parameteren." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Fjern nyere elementer i oprindelsesmappen." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Gendan valgte filer eller mapper på den oprindelige plads og slet filer " "eller mapper som ikke er i tilstandsbilledet. Vær ekstremt forsigtig for " "dette vil slette filer og mapper som blev sprunget over da tilstandsbilledet" " blev dannet." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Er du sikker på at du vil gendanne dette element i den nye mappe?" msgstr[1] "" "Er du sikker på at du vil gendanne disse elementer i den nye mappe?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Er du sikker på at du vil gendanne dette element?" msgstr[1] "Er du sikker på at du vil gendanne disse elementer?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Bruger-kode: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Bruger-kode scriptet skal have en shebang på den første linje (for eksempel " "{example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Vis/skjul skjulte filer og mapper (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Sæt sprog op" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Oversat: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Systemstandard" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Brug styresystemets sprog." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Tilstandsbillede-logvisning" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Se Sidste Log" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "&Sikkerhedskopiér:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filter:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Fejl, [I] Information, [C] Ændre" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "afkod paths" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Alles" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Ændringer" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Fejl" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Information" msgstr[1] "Informationer" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync overførelsesfejl (eksperimentalt)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Håndtér profiler" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Redigér" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Tilføj" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Fjern" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Generelt" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Inkludér" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Ekskludér" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Fjer&rn & Opbevaring" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "I&ndstillinger" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "A&vancerede indstillinger" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Gendan opsætning" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Ny profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Omdøb profil" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Er du sikker på at du vil slette profilen \"{name}\"?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Kopiér symbolske links som filer" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Kopiér symbolske links som rigtige filer eller mapper i tilstandsbilledet. " "Vælg om alle links eller kun dem der peger ud af kilden skal kopieres." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Denne valgmulighed kan øge tilstandsbilledets størrelse." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Slået fra som standard." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Alle symbolske links bliver erstattet med de rigtige filer eller mapper de " "peger på. Dette øger tilstandsbilledets størrelse og kan lagre de samme " "filer flere gange." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Bruger 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Kun eksterne" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Kun links der peger ud af tilstandsbilledets kilde kopieres som filer. Dette" " øger tilstandsbilledets størrelse og kan lagre de samme filer flere gange." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Bruger 'rsync --copy-unsafe-links'." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Editor & Office midlertidige filer" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacs backup filer" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs autogem filer" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Vim swap filer" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Office midlertidige filer" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice & andre OpenDocument programmers låsefiler" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniature- og Midlertidige Billeder" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "Miniaturebillede-cache på GNU/Linux og andre unix-lignende operativsystemer" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Miniaturebillededatabase på Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Metadata-mappe på macOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Applikationsspecifikke låse" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discord applikationslåsefil" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord sessionslåsefil" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Mozilla Firefox & Thunderbird låsefil" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Caches & Midlertidige mapper" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Brugerapplikationscache" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Midlertidig system-mappe" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Pakke-cache for Debian(-baserede) GNU/Linux distributioner" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Flatpak applikations og kørselsmiljø lagringsplads" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Systemkørselsmiljømapper" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Kerne- og processinformation" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Enheds- og anden hardwareinformation (sysfs interface)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Enhedsnoder" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Systemkørselsfiler" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Andre ikke-permanente" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Liste af nuværende monterede filsystemer" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "System swap-fil (virtuel hukommelse)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "GNOME virtuelt filsystem monteringspunkt" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Gendannet filsystem objekter" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Diverse" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Metadata-mappe på Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Bruger skraldespand" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "System tilstandsafbildning filer" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Ekskludéringsforslag" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Vælg ofte brugte elementer til at tilføje til tilstandsafbildning eksklusiv " "liste." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Standard" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Nulstil til forudinstillet valg" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Planlæg" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dag:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Ugedag:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Tid:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Timer:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "hver time" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minutter:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Kør Back In Time så snart drevet tilsluttes (kun en gang hver X'te dag). Du " "vil blive spurgt om dit sudo kodeord." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Kør Back In Time med jævne mellemrum. Dette er praktisk hvis computeren ikke" " er tændt på faste tidspunkter." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Hver:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Aktiver logning af debug beskeder" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "Skriver debugniveau-beskeder ind i system log via \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Advarsel: Brug kun dette midlertidigt til fejlfinding, da det genererer en " "stor mængde output." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Deaktiveret" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Ved hver opstart/genstart" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Hvert minut" msgstr[1] "Hvert {n}. minut" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Hver time" msgstr[1] "Hver {n} timer" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Angiv interval" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Hver dag" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Gentag (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Når drev bliver tilsluttet (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Hver uge" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Hver måned" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Hvert år" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Time(r)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dag(e)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Uge(r)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Måned(er)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Tilpassede timer kan kun være en kommasepareret liste af timer (for eksempel" " 8,12,18,23) eller */3 for periodisk sikkerhedskopiering hver tredje time." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "" "Wählt eine vorhandene private Schlüsseldatei von einem anderen Ort aus." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Erstellt einen neuen SSH-Schlüssel ohne Passphrase." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Vollständiger Pfad: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Privater Schlüssel:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "SSH-Konfiguration des Systems verwenden" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Wählt keine Schlüsseldatei. SSH Verbindungen nutzen die Konfiguration des " "SSH-Clients aus dem System (z.B., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH-Proxy" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Host:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "User:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Verbindet sich mit dem Ziel-Host über diesen Proxy (auch bekannt als Jump-" "Host). Für Details siehe \"-J\" in der Dokumentation des \"ssh\"-Befehls " "oder \"ProxyJump\" in der \"ssh_config\" man page." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Info{ENDBOLD}: Im Modus 'SSH verschlüsselt', funktionieren nur " "einzelne oder doppelte Sternchen (z. B. {example2}). Andere Arten von " "Platzhaltern und Mustern werden ignoriert (z. B. {example1}). Aufgrund der " "Verschlüsselung durch EncFS, sind Dateinamen in diesem Modus nicht " "vorhersehbar." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Muster, Dateien oder Verzeichnisse ausschließen" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Muster hinzufügen" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Dateien hinzufügen" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Verzeichnisse hinzufügen" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Vorschläge" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "Häufig genutzte Elemente für die Ausschlussliste auswählen." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Dateien ausschließen, die größer sind als:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Dateien ausschließen, die größer sind als {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Wenn der „Vollständige rsync-Modus“ deaktiviert ist, wirkt sich diese " "Einstellung nur auf neu erstellte Dateien aus, da rsync sie als " "Übertragungsoption und nicht als Ausschlussregel behandelt. Folglich bleiben" " große Dateien, die bereits gesichert wurden, auch dann in den Sicherungen " "erhalten, wenn sie modifiziert werden." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Ausschlussmuster" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Ausschlussmuster eingeben:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Für Hilfe siehe den Abschnitt {link} der rsync-Manpage." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Öffnet die rsync-Manpage" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Dateien ausschließen" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Verzeichnisse ausschließen" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Deaktiviert, da dieses Muster im Modus »SSH verschlüsselt« nicht " "funktionsfähig ist." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Diese Optionen dienen der fortgeschrittenen Konfiguration. Nur ändern, wenn " "die Auswirkungen vollständig bekannt sind." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Starte »rsync« mit »{cmd}«:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "als cron-job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "auf entfernten Rechnern" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "wenn eine Sicherung manuell erstellt wird" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Bitte 'nocache' installieren, um diese Option freizuschalten." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "auf dem lokalen Rechner" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Leitet stdout in cronjobs nach /dev/null um." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Wenn ein MTA installiert ist, sendet Cron eine automatische E-Mail mit dem " "angehängten Ausgabeprotokoll der Cronjobs." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Leitet stderr in cronjobs nach /dev/null um." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Wenn ein MTA installiert ist, sendet Cron eine automatische E-Mail mit dem " "angehängten Fehlerprotokoll der Cronjobs." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Bandbreitennutzung von rsync begrenzen:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "ACL bewahren" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Erweiterte Attribute (xattr) bewahren" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Auf ein Dateisystem beschränken" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Optionen müssen in Anführungszeichen stehen z.B.: {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Zusätzliche Optionen zu rsync hinzufügen" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Präfix, das vor jedem Befehl auf dem Remote-Host ausgeführt wird." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variablen müssen mit \\$FOO maskiert werden. Das betrifft nicht rsync. Um " "ein Präfix für rsync hinzuzufügen, verwenden Sie »{example_value}« mit " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "Standard" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Präfix zu SSH-Befehl hinzufügen" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Überprüfen, ob der entfernte Rechner online ist" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Warnung: Wenn diese Option deaktiviert ist und der entfernte Rechner nicht " "verfügbar ist, kann es zu einigen verwirrenden Fehlern kommen." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" "Prüfen, ob der entfernte Rechner alle erforderlichen Befehle unterstützt." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Warnung: Wenn diese Option deaktiviert ist und der entfernte Rechner nicht " "alle erforderlichen Befehle unterstützt, kann es zu einigen verwirrenden " "Fehlern kommen." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(Standard: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "Deaktiviert" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "Aktiviert" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modus:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Wo Sicherungen zu speichern sind" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH-Einstellungen" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Pfad:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Schlüsseldatei:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Passwort" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Passwort in Schlüsselbund speichern" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Passwort für Cron zwischenspeichern (Sicherheitsproblem: Systemverwalter " "»root« kann das Passwort lesen)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Erweitert" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Vollständiger Sicherungspfad:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Die Zeitplanung ist deaktiviert, da keine Cron-Installation gefunden wurde. " "Bitte Cron installieren, um geplante Sicherungen zu aktivieren." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Der Pfad für das Sicherungsziel darf nicht leer sein." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Das Verschlüsselungspasswort darf nicht leer sein." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Beim Versuch, sich am Zielrechner anzumelden, ist ein Fehler aufgetreten. " "Die folgende Fehlermeldung wurde zurückgegeben:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Um die passwortlose Anmeldung zu ermöglichen, kann der öffentliche SSH-" "Schlüssel auf das entfernte System kopiert werden." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Mit dem Kopieren des SSH-Schlüssels fortfahren?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Der öffentliche SSH-Schlüssel konnte nicht kopiert werden. Dies kann auf ein" " Verbindungs- oder Berechtigungsproblem zurückzuführen sein." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Die Echtheit des Rechners {host} kann nicht festgestellt werden." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} Fingerabdruck des Schlüssels ist:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Bitte diesen Fingerabdruck überprüfen. Diesen zur Datei »known_hosts« " "hinzufügen?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Wirklich das Sicherungsverzeichnis ändern?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Das ausgewählte Sicherungsziel ist nicht leer." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Es muss leer sein, um die Verschlüsselung zu verwenden." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Ungültige Datei: Der SSH Schlüssel ist nicht privat" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Die ausgewählte Datei {path} ist ein öffentlicher SSH-Schüssel. Bitte " "stattdessen die entsprechende private Schlüsseldatei auswählen (ohne ».pub« " "Endung)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Die Datei {path} ist bereits vorhanden. Es kann kein neuer SSH-Schüssel mit " "diesem Namen erstellt werden." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Neuer SSH-Schlüssel in {path} konnte nicht erstellt werden." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Dateien und Verzeichnisse einbeziehen" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "»{path}« ist ein symbolischer Link (Symlink). Das verlinkte Ziel wird erst " "gesichert, wenn es ebenfalls enthalten wird." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Stattdessen das verlinkte Ziel einbeziehen?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Dateien einbeziehen" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Verzeichnisse einbeziehen" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Benachrichtigungen aktivieren" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Sicherungen deaktivieren, wenn im Akkubetrieb" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Energiestatus des Systems nicht verfügbar" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Nur eine Sicherung gleichzeitig ausführen" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Andere Sicherungen werden blockiert, bis die aktuelle Sicherung " "abgeschlossen ist. Dies ist eine globale Einstellung, die alle Profile " "dieses Benutzers betrifft. Sie muss jedoch auch für alle anderen Benutzer " "aktiviert werden." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Beim Wiederherstellen Dateien ersetzen" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Bei Fehlern fortfahren (unvollständige Sicherungen behalten)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Prüfsumme verwenden, um Änderungen zu erkennen" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" "Neue Sicherung erstellen, egal ob Änderungen vorgenommen wurden oder nicht." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Warne, wenn freier Speicherplatz weniger als" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Zeigt eine Warnung, wenn der freie Speicherplatz am Sicherungsziel geringer " "ist, als der angegebene Wert." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Wenn die Richtlinien zum Löschen & Aufbewahren aktiviert sind und alte " "Sicherungen abhängig vom verfügbaren Speicherplatz gelöscht werden, darf " "dieser Wert nicht niedriger sein als der in der Richtlinie festgelegte Wert." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Protokollierungsstufe:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nichts" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "Benutzerhandbuch" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Die folgenden Regeln werden von oben nach unten verarbeitet. Spätere Regeln " "setzen frühere Regeln außer Kraft. Siehe das {manual_link} für Details und " "Beispiele." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Öffnet Benutzerhandbuch im Browser." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Die aktuellste Sicherung behalten." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Die neueste Sicherung wird unter allen Umständen aufbewahrt." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Das Verhalten kann nicht geändert werden." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Benannte Sicherungen behalten." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Sicherungen, denen zusätzlich zum üblichen Zeitstempel ein Name zugewiesen " "wurde, werden unter allen Umständen bewahrt und nicht entfernt." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Jahr(e)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Entferne Sicherungen, die älter sind als" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Vollständige Tage. Aktueller Tag wird ignoriert." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Kalenderwochen beginnend mit Montag. Aktuelle Woche wird ignoriert." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12 Monats Periode. Aktueller Monat wird ignoriert." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Aufbewahrungs-Richtlinien" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Auf entferntem Rechner im Hintergrund ausführen." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Die Aufbewahrungs-Richtlinien werden direkt auf dem entfernten System " "ausgeführt, nicht lokal. Die Befehle „bash“, „screen“ und „flock“ müssen auf" " dem entfernten System installiert und verfügbar sein." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Wenn ausgewählt, testet Back In Time zunächst das entfernte System." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Die Tage werden gezählt, beginnend mit den aktuellen Tag." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Behalte alle Sicherungen, der letzten" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "Tag(e)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Behalte die letzte Sicherung jeden Tages, für die letzten" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Die Wochen werden ab der aktuell laufenden Woche gezählt. Eine Woche beginnt" " am Montag." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Behalte die letzte Sicherung jeder Woche, für die letzten" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "Woche(n)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "Die Monate werden als Kalendermonate gezählt, beginnend mit dem aktuellen " "Monat." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Behalte die letzte Sicherung jedes Monats, für die letzten" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "Monat(e)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" "Die Jahre werden als Kalenderjahre gezählt, beginnend mit dem aktuellen " "Jahr." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Behalte die letzte Sicherung jedes Jahres, für" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "alle Jahre." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… freier Speicher weniger ist als" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… freie Inodes weniger sind als" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Älteste Sicherung entfernen, wenn …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" "Zur Ausführung von Back In Time als root ist eine Authentifizierung " "erforderlich." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Zur Änderung von Sicherungszeitplänen, die durch den Anschluss externer " "Speichergeräte ausgelöst werden, ist eine Authentifizierung erforderlich." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Verknüpfungen" #: qt/placeswidget.py:63 msgid "Places" msgstr "Orte" #: qt/placeswidget.py:64 msgid "File System" msgstr "Dateisystem" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Sicherungsverzeichnisse" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: {profile_name} (von Nutzer \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Letztes Protokoll ansehen" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "{appname} starten" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "In Arbeit …" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "Manpage: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Konfiguration importieren" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Kein Verzeichnis ausgewählt" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importieren" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Suche …" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Sicherungsverzeichnis wählen, aus dem die Konfiguration importiert werden " "soll. Der Pfad könnte beispielsweise wie folgt aussehen: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Befindet sich das Verzeichnis auf einem externen oder entfernten Laufwerk, " "muss dieses vorher manuell eingehängt werden." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Erneut scannen" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Versteckte Verzeichnisse anzeigen" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Versteckte Verzeichnisse zeigen/ausblenden (Strg+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "In diesem Verzeichnis wurde keine Konfiguration gefunden" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Suche abgeschlossen." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Vollständiges Protokoll zeigen" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Countdown zum Herunterfahren" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Die Sicherung ist abgeschlossen." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Herunterfahren abbrechen" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Jetzt herunterfahren" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Das System wird in {n} Sekunde heruntergefahren." msgstr[1] "Das System wird in {n} Sekunden heruntergefahren." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Optionen zum Vergleichen von Sicherungen" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Befehl:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parameter:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Als Pfadparameter %1 und %2 verwenden" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Bitte Diff-Befehl festlegen oder Abbrechen drücken." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Der Befehl »{cmd}« kann auf dem System nicht gefunden werden. Bitte etwas " "anderes versuchen oder Abbrechen drücken." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Keine Parameter für den diff-Befehl festgelegt. Verwendet wird der " "Defaultwert »{params}«." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Sicherungen" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Nur sich unterscheidende Sicherungen" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Nur Sicherungen auflisten, die gleich sind mit:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Gründliche Prüfung (genauer, aber langsamer)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Löschen" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Alles auswählen" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Vergleichen" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Gehen zu" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Optionen" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Es ist nicht möglich, eine Sicherung mit sich selbst zu vergleichen, da der " "Vergleich redundant wäre." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Soll »{file_or_dir}« in der Sicherung »{backup_id}« wirklich gelöscht " "werden?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Soll »{file_or_dir}« wirklich in {count} Sicherungen gelöscht werden?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "WARNUNG: Dies kann nicht rückgängig gemacht werden." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "»{path}« von zukünftigen Sicherungen ausschließen?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Root-Modus" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time wird derzeit mit Root-Rechten (vollständiger Systemzugriff) " "ausgeführt" #: qt/timeline.py:69 msgid "Today" msgstr "Heute" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Gestern" #: qt/timeline.py:87 msgid "This week" msgstr "Diese Woche" #: qt/timeline.py:95 msgid "Last week" msgstr "Letzte Woche" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Dies ist KEINE Sicherung, aber eine Live-Ansicht der lokalen Daten." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Letzte Überprüfung {time}" backintime-1.6.1/common/po/el.po000066400000000000000000003101341514264426600165070ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Dimitris Tzemos # SPDX-FileCopyrightText: © Iliana Panagopoulou (hpanago) # SPDX-FileCopyrightText: © Paraskevas Leivadaros # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-02 11:33+0000\n" "Last-Translator: gnutechie \n" "Language-Team: Greek \n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Όλες οι άδειες χρήσης που χρησιμοποιούνται σε αυτό το έργο βρίσκονται στον " "κατάλογο {dir_link}. Για να εξαγάγετε πληροφορίες άδειας χρήσης και " "πνευματικών δικαιωμάτων ανά αρχείο χρησιμοποιώντας μεταδεδομένα SPDX, " "ανατρέξτε στο {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Προειδοποίηση" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Κύριο Προφίλ" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Τοπικό (EncFS κρυπτογραφημένο)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS κρυπτογραφημένο)" #: common/config.py:237 msgid "Local" msgstr "Τοπικό" #: common/config.py:240 msgid "Local encrypted" msgstr "Τοπικά κρυπτογραφημένο" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Κρυπτογράφηση" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Ιδιωτικό κλειδί SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Προφίλ: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Ο κατάλογος αντιγράφων ασφαλείας δεν είναι έγκυρος." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Πρέπει να επιλεχτεί τουλάχιστον ένας φάκελος για αντίγραφα ασφαλείας." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Κατάλογος: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Αυτός ο κατάλογος δεν μπορεί να συμπεριληφθεί στο αντίγραφο ασφαλείας, καθώς" " αποτελεί μέρος του ίδιου του προορισμού δημιουργίας αντιγράφων ασφαλείας." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Η τιμή για την επιλογή \"Κατάργηση του παλαιότερου αντιγράφου ασφαλείας εάν " "ο ελεύθερος χώρος είναι μικρότερος από\" ({val_one}) πρέπει να είναι " "μικρότερη ή ίση με το όριο για την επιλογή \"Προειδοποίηση εάν ο ελεύθερος " "χώρος στο δίσκο πέσει κάτω από\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Παρακαλώ προσαρμόστε τις ρυθμίσεις έτσι ώστε το όριο κατάργησης αντιγράφων " "ασφαλείας να μην είναι υψηλότερο από το όριο προειδοποίησης." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Ο χρονοπρογραμματισμός με Udev δεν δουλεύει με τη λειτουργία {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Αποτυχία εγγραφής νέου crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Το Cron δεν εκτελείται, παρόλο που η εντολή crontab είναι διαθέσιμη. Οι " "προγραμματισμένες εργασίες δημιουργίας αντιγράφων ασφαλείας δεν θα " "εκτελεστούν. Το Cron ενδέχεται να είναι εγκατεστημένο αλλά όχι " "ενεργοποιημένο. Δοκιμάστε να εκτελέσετε τις δύο εντολές \"systemctl enable " "cron\" και \"systemctl start cron\" ή συμβουλευτείτε τα κανάλια υποστήριξης " "της διανομής GNU/Linux που χρησιμοποιείται αυτήν τη στιγμή για βοήθεια." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Αποτυχία αποθήκευσης της παραμετροποίησης" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Αποτυχία φόρτωσης της παραμετροποίησης" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Το προφίλ \"{name}\" υπάρχει ήδη." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Το τελευταίο προφίλ δεν μπορεί να αφαιρεθεί." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Αδυναμία προσάρτησης '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Η παραμετροποίηση για κρυπτογραφημένο φάκελο δεν βρέθηκε." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Δημιουργία νέου κρυπτογραφημένου φακέλου;" #: common/encfstools.py:204 msgid "Cancel" msgstr "Ακύρωση" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Παρακαλώ εισάγετε ξανά τον κωδικό πρόσβασης EncFS για επιβεβαίωση." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Οι κωδικοί πρόσβασης του EncFS δεν ταιριάζουν." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Λήψη στιγμιότυπου" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Αδυναμία αρχικοποίησης κρυπτογραφημένου μονοπατιού '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Αδυναμία αποπροσάρτησης {mountprocess} από το {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "Δεν βρέθηκε το {command}. Παρακαλώ εγκαταστήστε το (π.χ. μέσω " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Το σημείο προσάρτησης {mntpoint} δεν είναι κενό." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Καταχώρηση κωδικού για {mode} προφίλ \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Δεν ήταν δυνατή η εγκατάσταση του κανόνα Udev για το προφίλ {profile_id}. Η " "υπηρεσία DBus '{dbus_interface}' δεν ήταν διαθέσιμη." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Δεν βρέθηκε το UUID για το {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "ΑΠΟΤΥΧΙΑ" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Επαναφορά δικαιωμάτων" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Ολοκληρώθηκε" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Οι ακόλουθες καταχωρήσεις από τη λίστα συμπερίληψης δεν έχουν αντίστοιχο " "αρχείο ή κατάλογο στην πηγή αντιγράφων ασφαλείας:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Αναβολή του backup όσο το σύστημα βρίσκεται σε μπαταρία" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Δεν είναι δυνατή η εύρεση του καταλόγου αντιγράφων ασφαλείας.." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Εάν βρίσκεται σε αφαιρούμενη μονάδα δίσκου, συνδέστε την." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Αναμονή {n} δευτερόλεπτο." msgstr[1] "Αναμονή {n} δευτερόλεπτα." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Αποτυχία δημηιουργίας αντιγράφου ασφαλείας {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Παρακαλώ να είστε υπομονετικοί. Οριστικοποίηση…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Δεν είναι δυνατή η δημιουργία καταλόγου." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Αποθήκευση αρχείου ρυθμίσεων…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Αποθήκευση δικαιωμάτων…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Βρέθηκε ένα μη ολοκληρωμένο αντίγραφο ασφαλείας {snapshot_id} του οποίου η " "δημιουργία μπορεί να συνεχιστεί." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Αφαίρεση του ελλιπούς καταλόγου {snapshot_id} από την τελευταία εκτέλεση" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Αδυναμία αφαίρεσης καταλόγου" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Δημιουργία αντιγράφων ασφαλείας" #: common/snapshots.py:1517 msgid "Success" msgstr "Επιτυχία" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Μερική μεταφορά λόγω σφάλματος" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "Μερική μεταφορά λόγω εξαφανισμένων αρχείων πηγής (δείτε 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "Η διεργασία 'rsync' τελείωσε με κωδικό {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Δείτε το 'man rsync' για περισσότερες λεπτομέρειες" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Οι αρνητικοί αριθμοί ως κωδικοί εξόδου του rsync είναι αριθμοί σήματος, " "δείτε 'kill -l' και 'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Δεν άλλαξε τίποτα, δεν χρειάζεται νέο αντίγραφο ασφαλείας" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Αδυναμία μετονομασίας {new_path} σε {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Εφαρμογή κανόνων για την κατάργηση παλιών αντιγράφων ασφαλείας" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Εφαρμόστε πολιτική διατήρησης" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Προσπάθεια διατήρησης ελάχιστου ελεύθερου χώρου" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "" "Προσπαάθεια διατήρησης ελάχιστου ποσοστού {perc} ελεύθερων συστημάτων " "αρχείου (inodes)" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Τώρα" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Αδυναμία προσάρτησης {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" "το ssh-agent δε βρέθηκε. Παρακαλώ βεβαιωθείτε ότι είναι εγκατεστημένο." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Δεν ήταν δυνατό το ξεκλείδωμα του ιδιωτικού κλειδιού SSH. Λάθος κωδικός ή " "δεν υπάρχει διαθέσιμος κωδικός για cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Η απομακρυσμένη διαδρομή υπάρχει αλλά δεν είναι φάκελος." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Η απομακρυσμένη διαδρομή δεν είναι εγγράψιμη." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Η απομακρυσμένη διαδρομή δεν είναι εκτελέσιμη." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Αδυναμία δημιουργίας απομακρυσμένης διαδρομής." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "" "Ο απομακρυσμένος διακομιστής {host} δεν υποστηρίζει την εντολή {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "Οι εντολές ελέγχου στον διακομιστή {host} επέστρεψαν ένα άγνωστο σφάλμα" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "O απομακρυσμένος διακομιστής {host} δεν υποστηρίζει hardlinks" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "" "Αντιγράψτε το δημόσιο κλειδί SSH \"{pubkey}\" στον απομακρυσμένο διακομιστή " "\"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Παρακαλώ επιβεβαιώστε τον κωδικό του \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Το σύστημα αρχείων του προορισμού για το {path} είναι μορφοποιημένο με NTFS," " το οποίο είναι ασύμβατο με συστήματα αρχείων προορισμού Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} δεν είναι έγκυρος κατάλογος." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Η δημιουργία του ακόλουθου καταλόγου απέτυχε:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Τα δικαιώματα εγγραφής μπορεί να είναι περιορισμένα." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Το σύστημα αρχείων του προορισμού για το {path} είναι μορφοποιημένο με FAT " "το οποίο δεν υποστηρίζει hard-links. Παρακαλώ χρησιμοποιήστε ένα εγγενές " "σύστημα αρχείων GNU/Linux." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Το σύστημα αρχείων προορισμού για το {path} είναι ένα κοινόχρηστο στοιχείο " "που προσαρτάται μέσω SMB. Βεβαιωθείτε ότι ο απομακρυσμένος διακομιστής SMB " "υποστηρίζει συμβολικούς συνδέσμους ή ενεργοποιήστε το \"{copyLinks}\" στο " "\"{expertOptions}\"." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Αντιγραφή συνδέσμων (αφαίρεση αναφοράς των συμβολικών συνδέσμων)" #: common/tools.py:487 msgid "Expert Options" msgstr "Προχωρημένες Ρυθμίσεις" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Το σύστημα αρχείων προορισμού για το {path} είναι ένα κοινόχρηστο στοιχείο " "που προσαρτάται μέσω sshfs. Το Sshfs δεν υποστηρίζει σκληρούς συνδέσμους. " "Χρησιμοποιήστε τη λειτουργία \"SSH\"." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Αδυναμία δημιουργίας φακέλου στον κατάλογο:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "ΣΧετικά με Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Πνευματική ιδιοκτησία:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Συγγραφείς:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Μεταφραστές:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Dimitris Tzemos \n" "Iliana Panagopoulou (hpanago)\n" "Paraskevas Leivadaros " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" "Οι έπαινοι του μεταφραστή δεν είναι διαθέσιμοι για την τρέχουσα γλώσσα." #: qt/aboutdlg.py:116 msgid "this link" msgstr "αυτός ο σύνδεσμος" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Ακολουθήστε {thislink} για να λάβετε έπαινους μεταφραστή για όλες τις " "γλώσσες." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Ιστοσελίδα του έργου" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Εγχειρίδιο χρήστη" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Ανοίξτε το εγχειρίδιο χρήστη στο πρόγραμμα περιήγησης (τοπικά εάν είναι " "διαθέσιμο διαφορετικά στο διαδίκτυο)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Έκδοση{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} φαίνεται να εκτελείται για πρώτη φορά χωρίς να εντοπίζεται " "παραμετροποίηση." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Εισαγωγή υπάρχουσας παραμετροποίησης (από κατάλογο ανάκτησης ή από άλλο " "υπολογιστή);" #: qt/app.py:395 msgid "Then press OK." msgstr "Στη συνέχεια, πατήστε OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Δημιουργήστε ένα αντίγραφο ασφαλείας" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Χρήση ώρας τροποποίησης και μεγέθους, για ανίχνευση αλλαγής αρχείου." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Δημιουργία αντιγράφου ασφαλείας (λειτουργία ελέγχου αθροίσματος)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Χρήση των checksum για ανίχνευση αλλαγών αρχείου." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Παύση της διαδικασίας δημιουργίας αντιγράφων ασφαλείας" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Συνέχιση της διαδικασίας δημιουργίας αντιγράφων ασφαλείας" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Διακοπή της διαδικασίας δημιουργίας αντιγράφων ασφαλείας" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Ανανέωση λίστας αντιγράφων ασφαλείας" #: qt/app.py:524 msgid "Name backup" msgstr "Όνομα αντίγραφου ασφαλείας" #: qt/app.py:528 msgid "Remove backup" msgstr "Κατάργηση αντιγράφου ασφαλείας" #: qt/app.py:532 msgid "Open backup log" msgstr "Άνοιγμα αρχείου καταγραφής αντιγράφων ασφαλείας" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Προβολή αρχείου καταγραφής του επιλεγμένου αντιγράφου ασφαλείας." #: qt/app.py:536 msgid "Open last backup log" msgstr "Άνοιγμα αρχείου καταγραφής τελευταίου αντιγράφου ασφαλείας" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Δείτε το αρχείο καταγραφής του τελευταίου αντιγράφου ασφαλείας." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Διαχείριση προφιλ…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Επεξεργασία επανάκλησης χρήστη" #: qt/app.py:548 msgid "Shutdown" msgstr "Τερματισμός" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "" "Τερματίστε τη λειτουργία του συστήματος μετά την ολοκλήρωση της δημιουργίας " "αντιγράφων ασφαλείας." #: qt/app.py:552 msgid "Setup language…" msgstr "Καθορισμός γλώσσας…" #: qt/app.py:556 msgid "Exit" msgstr "Έξοδος" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man page: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Εμφανίζει τη σελίδα χρήστη σχετικά με το Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man page: Αρχείο διαμόρφωσης προφίλ" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Εμφανίζει τη σελίδα χρήστη σχετικά με το αρχείο διαμόρφωσης προφίλ " "(backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Ανοίξτε τον ιστότοπο Back In Time στο πρόγραμμα περιήγησης" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Αρχείο αλλαγών" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Ανοίξτε το εγχειρίδιο χρήστη στο πρόγραμμα περιήγησης (τοπικά εάν είναι " "διαθέσιμο, διαφορετικά στο διαδίκτυο)" #: qt/app.py:589 msgid "FAQ" msgstr "Συχνές Ερωτήσεις" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Ανοίξτε τις Συχνές Ερωτήσεις (FAQ) στο πρόγραμμα περιήγησης" #: qt/app.py:593 msgid "Ask a question" msgstr "Κάνε μια ερώτηση" #: qt/app.py:597 msgid "Report a bug" msgstr "Αναφορά προβλήματος" #: qt/app.py:600 msgid "Translation" msgstr "Μετάφραση" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Εμφανίζει ξανά το μήνυμα σχετικά με τη συμμετοχή στη μετάφραση." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Μετάβαση κρυπτογράφησης (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Εμφανίζει ξανά το μήνυμα σχετικά με την αφαίρεση του EncFS." #: qt/app.py:615 msgid "About" msgstr "Σχετικά" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Επαναφορά" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Επανέφερε τα επιλεγμένα αρχεία ή φακέλους στον αρχικό τους προορισμό." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Επαναφορά στο…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Επανέφερε τα επιλεγμένα αρχεία ή φακέλους σε ένα νέο προορισμό." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Επαναφορά του τρέχοντος εμφανιζόμενου φακέλου και όλων των περιεχομένων του," " στον αρχικό προορισμό." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Επανέφερε τον τρέχοντα εμφανιζόμενο φάκελο και όλα τα περιεχόμενα του σε ένα" " νέο προορισμό." #: qt/app.py:640 msgid "Up" msgstr "Επάνω" #: qt/app.py:643 msgid "Show hidden files" msgstr "Προβολή κρυφών αρχείων" #: qt/app.py:646 msgid "Compare backups…" msgstr "Σύγκριση αντιγράφων ασφαλείας…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Απελευθέρωση υποψηφίου" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Εμφανίζει ξανά το μήνυμα για αυτόν τον υποψήφιο έκδοσης." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Backup" #: qt/app.py:733 msgid "&Restore" msgstr "&Eπαναφορά" #: qt/app.py:739 msgid "&Help" msgstr "&Βοήθεια" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "Μόνο εικονίδια" #: qt/app.py:827 msgid "Text only" msgstr "Κείμενο μόνο" #: qt/app.py:830 msgid "Text below icons" msgstr "Κείμενο κάτω από τα εικονίδια" #: qt/app.py:833 msgid "Text beside icon" msgstr "Κείμενο δίπλα στο εικονίδιο" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Αυτός ο κατάλογος δεν υπάρχει\n" "στο τρέχον επιλεγμένο αντίγραφο ασφαλείας." #: qt/app.py:1005 msgid "Add to Include" msgstr "Προσθήκη στα Περιλαμβανόμενα" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Προσθήκη στα Αποκλειόμενα" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Εάν αυτό το παράθυρο είναι κλειστό, το Back In Time δεν θα μπορεί να " "τερματίσει τη λειτουργία του συστήματός σας όταν ολοκληρωθεί η δημιουργία " "αντιγράφων ασφαλείας." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Να κλείσω το παράθυρο ούτως ή άλλως;" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Ολοκληρώθηκε, δεν χρειάζεται backup" #: qt/app.py:1285 msgid "Working:" msgstr "Εργασία:" #: qt/app.py:1292 msgid "Working" msgstr "Εργασία" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Σφάλμα" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Απεσταλμένα:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Ταχύτητα:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ΕΧΑ:" #: qt/app.py:1490 msgid "Backup:" msgstr "Αντίγραφα ασφαλείας:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Επαναφορά {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Επαναφορά {path} στο…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Γειά\n" "Μέχρι στιγμής έχεις χρησιμοποιήσει μερικές φορές την {language} γλώσσα\n" "Η μετάφραση της εγκατεστημένης έκδοσης του Back In Time στα {language} είναι {perc} ολοκληρωμένη. Ανεξάρτητα απο το τεχνικό σου επίπεδο, μπορείς να συνεισφέρεις στην μετάφραση και κατ' επέκταση στο ίδιο το Back In Time.\n" "Παρακαλώ επισκέψου το {translation_platform_url} εαν επιθμείς να συνεισφέρεις. Για περαιτέρω βοήθεια και ερωτήσεις , παρακαλώ επισκέψου το {back_in_time_project_website}.\n" "Μας συγχωρείς για την διακοπή, και αυτό το μήνυμα δεν θα εμφανιστεί ξανά. Αυτή η ενημέρωση είναι διαθέσιμη οπότε θελήσεις μέσα απο το μενού help.\n" "H ομάδα του Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "πλατφόρμα μετάφρασης" #: qt/app.py:1714 msgid "Website" msgstr "Ιστοσελίδα" #: qt/app.py:1728 msgid "Your translation" msgstr "Η μετάφρασή σου" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Στο Fediverse στο Mastodon: {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Λίστα αλληλογραφίας {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Λίστα αλληλογραφίας {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} στην ιστοσελίδα του έργου." #: qt/app.py:1781 msgid "Open an issue" msgstr "Άνοιξε ένα ζήτημα" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" "Εναλλακτικά, μπορείς να χρησιμοποιήσεις εναλλακτικό κανάλι επικοινωνίας της " "επιλογής σου." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Αυτή είναι μια έκδοση συνεισφοράς του Back In Time και ο πρωταρχικός της σκοπός είναι να δοκιμαστεί η σταθερότητά της κατά το στάδιο προετοιμασίας της επόμενης επίσημης έκδοσης.\n" "Δεν συλλέγονται προσωπικά δεδομένα ή δεδομένα τηλεμετρίας. Ωστόσο η ομάδα του Back In Time ενδιαφέρεται να γνωρίζει εάν αυτή η έκδοση συνεισφοράς χρησιμοποιείται και αν αξίζει να συνεχίσει να προσφέρει αυτές τις εκδόσεις πριν την επίσημη κυκλοφορία.\n" "Συνεπώς, η ομάδα ευγενικά επιθυμεί να σας ζητήσει την ανατροφοδότησή σας σε οτιδήποτε έχετε δοκιμάσει από την συγκεκριμένη έκδοση, ακόμα και αν δεν παρουσιάστηκαν ιδιαίτερα ζητήματα. Ακόμα και ένα γρήγορο τέστ μερικών λεπτών θα ήταν πολύτιμο για εμάς. \n" "Οι ακόλουθοι τρόποι επικοινωνίας είναι διαθέσιμοι:\n" "{contact_list}\n" "Στην συγκεκριμένη έκδοση, αυτό το μήνυμα δεν θα εμφανιστεί εκ νέου όμως θα είναι προσβάσιμο μέσω του μενού βοήθειας.\n" "Σας ευχαριστούμε για την υποστήριξη και για την βοήθεια να εξελίξουμε το Back In Time!\n" "Η δική σου ομάδα του Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Μόνο {free} ελεύθερος χώρος διαθέσιμος στον προορισμό, ο οποίος είναι κάτω " "από το διαμορφωμένο όριο {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Συνέχεια με τη δημιουργία αντιγράφων ασφαλείας;" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" "Όλα τα νεότερα αρχεία στη {path} θα καταργηθούν. Θέλετε να συνεχίσετε;" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Όλα τα νεότερα αρχεία στον αρχικό κατάλογο θα καταργηθούν. Θέλετε να " "συνεχίσετε;" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Προειδοποίηση{BOLDEND}: Η διαγραφή αρχείων στη ρίζα του συστήματος " "αρχείων θα μπορούσε να προκαλέσει βλάβη σε ολόκληρο το σύστημα." #: qt/app.py:2167 msgid "Backup name" msgstr "Όνομα αντιγράφου ασφαλείας" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Κατάργηση αυτού του αντιγράφου ασφαλείας;" msgstr[1] "Να καταργηθούν αυτά τα αντίγραφα ασφαλείας;" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Η επιλογή γλώσσας ενεργοποιείται έπειτα από επανεκκίνηση του Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Aντίγραφα ασφαλείας βάσει εκδόσεων (υπαρχρήστης)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Φιλικό προς το χρήστη γραφικό περιβάλλον χρήστη (GUI) για αντίγραφα " "ασφαλείας με βάση τις εκδόσεις που μειώνει τη χρήση του δίσκου (κατάσταση " "υπερχρήστη)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Aντίγραφα ασφαλείας βάσει εκδόσεων" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Φιλικό προς το χρήστη γραφικό περιβάλλον χρήστη (GUI) για αντίγραφα " "ασφαλείας με βάση τις εκδόσεις που μειώνει τη χρήση του δίσκου" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Ερώτηση" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Δημιουργία αντιγράφων backup με επίθεμα {suffix} πριν την αντικατάσταση ή " "αφαίρεση τοπικών στοιχείων." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Πριν από την επαναφορά, οι νεότερες εκδόσεις των αρχείων θα μετονομαστούν με" " το προσαρτημένο {suffix}. Αυτά τα αρχεία μπορούν να καταργηθούν με την " "ακόλουθη εντολή:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Αποκατάσταση μόνο στοιχείων που δεν υπάρχουν ή είναι νεότερα από αυτά στον " "προορισμό. Χρησιμοποιώντας την επιλογή {rsync_example}." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Αφαίρεσε νέα στοιχεία από τον αρχικό φάκελο." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Επαναφέρετε τα επιλεγμένα αρχεία ή καταλόγους στον αρχικό προορισμό και " "διαγράψτε αρχεία ή καταλόγους που δεν βρίσκονται στο αντίγραφο ασφαλείας. Να" " είστε εξαιρετικά προσεκτικοί, καθώς αυτό θα διαγράψει αρχεία και καταλόγους" " που εξαιρέθηκαν κατά τη δημιουργία του αντιγράφου ασφαλείας." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Θέλετε πραγματικά να επαναφέρετε αυτό το στοιχείο στον νέο κατάλογο;" msgstr[1] "" "Θέλετε πραγματικά να επαναφέρετε αυτά τα στοιχεία στον νέο κατάλογο;" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Θέλετε πραγματικά να επαναφέρετε αυτό το στοιχείο;" msgstr[1] "Πραγματικά να αποκαταστήσετε αυτά τα στοιχεία;" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "User-callback: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Το σενάριο επανάκλησης χρήστη πρέπει να περιλαμβάνει ένα shebang στην πρώτη " "γραμμή (π.χ. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Εμφάνιση/απόκρυψη κρυφών αρχείων και καταλόγων (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Γλώσσα εγκατάστασης" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Μεταφρασμένο: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Προεπιλογή συστήματος" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Χρησιμοποιήστε τη γλώσσα του λειτουργικού συστήματος." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Προβολή αρχείου καταγραφής αντιγράφων ασφαλείας" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Προβολή Τελευταίου αρχείου καταγραφής" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Προφίλ:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Αντίγραφα ασφαλείας:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Φίλτρο:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Σφάλμα, [I] Πληροφορία, [C] Αλλαγή" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "αποκωδικοποίηση μονοπατιών" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Όλα" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Αλλαγές" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Σφάλματα" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Πληροφορία" msgstr[1] "Πληροφορίες" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "αποτυχίες μεταφοράς rsync (πειραματικό)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Διαχείριση προφίλ" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Επεξεργασία" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Προσθήκη" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Αφαίρεση" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Γενικά" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Συμπεριλαμβάνει" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "Ε&ξαίρεση" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Κατάργηση & Διατήρηση" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Επιλογές" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Επιλογές E&expert" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Επαναφορά παραμετροποίησης" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Νέο προφίλ" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Μετονομασία προφίλ" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Διαγραφή του προφίλ \"{name}\";" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Αντέγραψε συμβολικούς συνδέσμους ως αρχεία" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Αντέγραψε συμβολικούς συνδέσμους ως πραγματικά αρχεία ή καταλόγους στο " "αντίγραφο ασφαλείας. Επέλεξε αν θα αντιγραφούν όλοι οι σύνδεσμοι ή μόνο " "αυτοί που δείχνουν έξω από την πηγή." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Η επιλογή αυτή ίσως αυξήσει το μέγεθος του αντίγραφου ασφαλείας." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Απενεργοποιημένο εκ προεπιλογής." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Όλοι οι συμβολικοί σύνδεσμοι αντικαθίστανται από πραγματικά αρχεία ή " "καταλόγους στους οποίους δείχνουν. Αυτό θα αυξήσει το μέγεθος του αντίγραφου" " ασφαλείας και ίσως να αποθηκεύσει τα ίδια αρχεία πολλαπλές φορές." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Χρησιμοποιεί 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Μόνο εξωτερικά" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Παύση της διαδικασίας δημιουργίας αντιγράφων ασφαλείας" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Εξαίρεση αρχείων" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Φάκελοι ανάκτησης" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Αδυναμία αφαίρεσης καταλόγου" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Αποθετήριο εφαρμογής και εκτελέσιμου αρχείου Flatpak" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Εμφάνιση κρυφών αρχείων" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Διακοπή της διαδικασίας δημιουργίας αντιγράφων ασφαλείας" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Εξαίρεση καταλόγων" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "προεπιλογή" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Προγραμματισμός" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Ημέρα:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Καθημερινές:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Ώρα:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Ώρα(ες):" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "μετά την ώρα" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Λεπτά:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Εκτελέστε την επιλογή Back In Time μόλις συνδεθεί η μονάδα δίσκου (μόνο μία " "φορά κάθε X ημέρες). Θα εμφανιστεί ένα μήνυμα κωδικού πρόσβασης sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Τρέξτε το Back In Time επανειλημμένα. Αυτό είναι χρήσιμο εάν ο υπολογιστής " "δεν λειτουργεί τακτικά." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Κάθε:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Ενεργοποίηση καταγραφής μηνυμάτων εντοπισμού σφαλμάτων" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Γράφει μηνύματα σε επίπεδο εντοπισμού σφαλμάτων στο αρχείο καταγραφής " "συστήματος μέσω \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Προσοχή: Χρησιμοποιήστε το μόνο προσωρινά για διαγνωστικά, καθώς παράγει " "μεγάλη ποσότητα εξόδου." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Απενεργοποιημένο" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Σε κάθε εκκίνηση/επανεκκίνηση" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Κάθε {n} λεπτό" msgstr[1] "Κάθε {n} λεπτά" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Κάθε ώρα" msgstr[1] "Κάθε {n} ώρες" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Ώρες που μπορείτε να τις προσαρμόσετε" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Καθημερινά" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Επανειλημμένως" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Όταν συνδέεται δίσκος (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Κάθε εβδομάδα" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Κάθε μήνα" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Κάθε χρόνο" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Ώρα(ες)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Ημέρα(ες)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Εβδομάδα(ες)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Μήνας(ες)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Οι προσαρμοσμένες ώρες μπορούν να είναι μόνο μια λίστα ωρών διαχωρισμένων με" " κόμματα (π.χ. 8,12,18,23) ή */3 για περιοδικά αντίγραφα ασφαλείας κάθε 3 " "ώρες." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Elekti ekzistantan dosieron je privata ŝlosilo de ie alia." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Krei novan SSH-ŝlosilon sen pasfrazo." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Plena vojo: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Privata ŝlosilo:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Uzi SSH-agordon de la sistemo" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Lasas la dosieron je privata ŝlosilo neselektita. Konektoj de SSH fidas al " "la ekzistanta klient-agordo de la sistemo (ekz., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH-prokurilo" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Gastiganto:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Pordo:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Uzanto:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Konekti al la celgastiganto per tio prokurilo (ankaŭ konita kiel \"jump " "host\" aŭ \"salt-gastiganto\"). Por pli multe da detaloj, vidu \"-J\" en la " "dokumentado de la komando \"ssh\" au \"ProxyJump\" en la manpaĝo." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Informo:{ENDBOLD}: Je 'kriptita SSH' reĝimo, sole unuoblaj kaj duoblaj" " asteriskoj funkcii (ekz. {example2}). Aliaj tipoj de ĵokeroj kaj ŝablonoj " "estos ignoritaj (ekz. {example1}). Nomoj de dosieroj estas neantaŭvideblaj " "je tio reĝimo pro la kriptado de EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Ekskluzivi ŝablonojn, dosierojn aŭ dosierujojn" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Aldoni ŝablonon" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Aldoni dosierojn" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Aldoni dosierujojn" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Sugestoj" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "Elektu de ordinare uzitaj eroj por aldoni al la savkopi-ekskludoj." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Ekskluzivi dosierojn pli grandajn ol:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Ekskluzivi dosierojn pli grandajn ol {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Se 'Tuta rsync reĝimo' estas malvalidigita, tio sole influos novajn " "doiserojn, ĉar por rsync tio estas transmet-opcio, ne ekskluziv-opcio. Do " "grandaj dosieroj, kiujn estis savkopiita antaŭe, restos en savkopioj, eĉ se " "ili ŝanĝis." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Ekskludi ŝablonon" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Enigi eksklud-ŝablonon:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Por helpo, vidu la sekcion de la manpaĝo de rsync nomita {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Malfermi la manpaĝon de rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Ekskludi dosierojn" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Ekskludi dosierujojn" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "Malŝaltita, ĉar tio ŝablono ne funkcias je 'kriptita SSH' reĝimo." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Tio ĉi opcioj estas por specialaj agordoj. Modifi sole se plene konscia pri " "ilia rezultatoj." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Startas 'rsync' je '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "kiel cron laboro" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "je la fora gastiganto" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "kiam fari manan savkopion" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Bonvolu instali 'nocache' por ŝalti tion opcion." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "je loka komputilo" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Alidirekti stdout al /dev/null en cron laboro." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron aŭtomate sendos retpoŝto kun la aldonita eligo de la cron laboroj, se " "MTA estas instalita." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Alidirekti stderr al /dev/null en cron laboro." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron aŭtomate sendos retpoŝto kun la aldonita erar-eligo de la cron laboroj," " se MTA estas instalita." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Trafiklimigi rsync-on:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Konservi ACL-ojn" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Konservi etenditajn atributojn (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Limigi al unu dosiersistemo" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Opcioj devas esti citita ekz. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Aldoni pluajn opciojn al rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefikso antaŭ ĉiuj komandoj en la fora gastiganto." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variabloj devas eskapita je \\$FOO. Tio ne afektas rsync. Do por aldoni " "prefikso al rsync, uzi \"{example_value}\" je {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "defaŭlto" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Aldoni prefikso al SSH-komandoj" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Kontroli, ke la fora gastiganto estas konektita" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Averto: se malvalidigita kaj la fora gastiganto ne estas disponebla, tio " "eblas igi kelkaj da bizaraj eraroj." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Kontroli, ke la fora gastiganto subtenas ĉiujn necesajn komandojn." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Averto: Se malvalidigita kaj la fora gastiganto ne subtenas ĉiujn necesajn " "komandojn, tio eblas igi kelkaj da bizaraj eraroj." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(defaŭlto: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "malŝaltita" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "ŝaltita" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Maniero:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Kien savi la savkopiojn" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Agordo de SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Vojo:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Dosiero je privata ŝlosilo:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Pasvorto" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Savi pasvorton je ŝlosilaro" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Kaŝmemorigi pasvorton por cron (Sekureca problemo: ĉefuzanto eblas legi " "pasvorton)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Progresinta" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Plena savkopi-vojo:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "Planado estas malvalidigita ĉar instalo de cron ne estas trovita." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "La cela vojo de la savkopio ne povas esti malplena." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "La ĉifrada pasvorto ne povas esti malplena." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Eraro okazis dum provi ensaluti en la foriga gastiganto. La sekvanta erar-" "mesaĝo estis revenigita:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Por ŝalti ensaluton sen pasvorto, la publika ssh-ŝloliso eblas esti kopiita " "al la foriga gastiganto." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Procedi je kopii la SSH-ŝlosilon?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "La publika SSH-ŝlosilo ne povis esti kopiita. Tio eble estas pro problemo " "kun konekto aŭ permeso." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "La aŭtenteco de la gastiganto {host} ne estis konstatebla." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} ŝlosilfingropremo estas:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Bonvolu konfirmi tion fingropremon! Ĉu vi volas aldoni ĝin al via " "'known_hosts' dosiero?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Vere ŝanĝi la dosierujon por savkopioj?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "La elektita celloko por la savkopio ne estas malplena." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Ĝi devas esti malplena por uzi ĉifradon." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Nevalida dosiero: Ne estas privata ŝlosilo de ssh" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "La elektita dosiero ({path}) estas publika ssh-ŝloliso. Bonvolu elekti la " "korespondantan dosieron je privata ŝlosilo anstataŭe (sen \".pub\")." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "La dosiero {path} ekzistas jam. Ne povas krei novan SSH-ŝlosilon kun tio " "nomo." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Malsukcesi krei novan SSH-ŝlosilon en {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Inkluzivi dosierojn kaj dosierujojn" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" estas simbola ligilo. La ligita celo ne estos savkopiata ĝis vi " "inkludi ĝin ankaŭ." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Ĉu vi volas inkluzivi la celon de la simbola ligilo anstataŭe?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Inkludi dosierojn" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Inkludi dosierujojn" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Aktivigi sciigojn" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Malvalidigi savkopikreado kiam ruli je baterio" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Kurentstato ne estas havebla de la sistemo" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Ne ruli plurajn savkopiojn samtempe" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Aliaj savkopioj estos ŝtopita ĝis la aktuala savkopio estas kreita. Tio " "estas malloka opcio. Do ĝi afekcias ĉiujn profilojn por tiu uzanto. Sed vi " "devas ankaŭ aktivigi tion por ĉiujn aliaj uzanto." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Anstataŭigi dosierojn dum restaŭri" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Kontinui je eraroj (savi nekompletajn savkopiojn)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Uzi kontrolsumo por detekti ŝanĝojn" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Krei novan savkopion eĉ se nenio ŝanĝis." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Averti se la kvanto de libera loko malpliiĝi ol" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Vidigas averton se la kvanto de libera loko je la savkopi-cela disko estas " "malpli ol la specifita valoro." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Se la politiko de Forigado & Konservado estas ŝaltita kaj malnovaj savkopioj" " estas forigata pro la havebla libera loko, tio valoro ne povas esti malpli " "ol la valoro agordita per la politiko." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Nivelo de protokolado:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Neniu" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "uzant-manlibron" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "La sekvantaj reguloj estas prilaborata de la supro al la malsupro. Pli " "malfruaj reguloj anstataŭigas pli fruajn. Vidu la {manual_link} por detaloj " "kaj ekzemploj." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Malfermi uzant-manlibron en la foliumilo." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Ne forigi plej novan savkopion." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "La plej nova savkopio estas konservata ĉiam." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Tio konduto ne povas esti ŝanĝita." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Ne forigi nomitajn savkopiojn." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Savkopioj, kio estas nomita krome havi la ordinaran tempindikon, estos " "konservataj ĉiam kaj ne estos forigataj." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Jaro(j)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Forigi savkopiojn plej malnova ol" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Kompletaj tagoj. La aktuala tago estas ignorata." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Kalendaraj semajnoj kun lundo kiel unua tago. La aktuala semajno estas " "ignorata." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Periodo da 12 monatoj. La aktuala monato estas ignorata." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Politiko de konservado" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Ruli fone je la foriga gastiganto." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "La politiko de konservado rulos senpere sur la fora maŝino, ne loke. La " "komandoj \"bash\", \"screen\" kaj \"flock\" devas esti instalitaj kaj " "haveblaj sur la fora maŝino." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Se elektita, Back In Time testos la fora maŝino unue." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "La tagoj estas kalkulataj ekde hodiaŭ." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Savi ĉiujn savkopiojn de la lasta(j)" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "tago(j)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Savi lastan savkopion po tago je la lasta(j)" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "La semajnoj estas kalkulataj ekde la aktuala semajno. Semajnoj estas " "rigardataj kiel starti kun lundo." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Savi lastan savkopion po semajno je la lasta(j)" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "semajno(j)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "La monatoj estas kalkulataj kiel kalendaraj monatoj ekde la aktuala monato." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Savi lastan savkopion po monato je la lasta(j)" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "monato(j)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Jaroj estas kalkulataj kiel kalendaraj jaroj ekde la aktuala jaro." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Savi lastan savkopion po ano de la lasta(j)" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "ĉiuj jaroj." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… la kvanto de libera loko estas malpli ol" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… la kvanto de liberaj indeksnodoj estas malpli ol" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Malnovaj savkopioj estas forigitaj se …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Aŭtentigo estas necesa por ruli Back In Time kiel administranto." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Aŭtentigo estas necesa por ŝanĝi rezervhorarojn ekigitajn de konektoj de " "eksteraj memoriloj." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Klavkombinoj" #: qt/placeswidget.py:63 msgid "Places" msgstr "Lokoj" #: qt/placeswidget.py:64 msgid "File System" msgstr "Dosiersistemo" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Savkopio-dosierujoj" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profilo: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profilo: \"{profile_name}\" (per uzanto \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Vidi lastan protokolon" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Komencu {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Laborante…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "manpaĝo: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importi agordon" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Neniu dosierujo elektita" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importi" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Serĉanta…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Elekti la savkopi-dosierujon de kie la agord-dosiero devus esti importota. " "La vojo eble aspektas tiel: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Se la dosierujo estas je ekstera aŭ fora disko, ĝi devas esti mane surmetita" " antaŭe." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Skani ree" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Montri kaŝitajn dosierujojn" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Vidigi/malvidigi kaŝitajn dosierujojn (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Neniu agordo trovita en ĉi tiu dosierujo" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Serĉado kompletas." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Vidigi tutan protokolon" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Retronombrado al Sistemfermo" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "La savkopio estas finita." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Nuligi Sistemfermon" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Sistemfermi Nun" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "La sistemo fermos je {n} sekundo." msgstr[1] "La sistemo fermos je {n} sekundoj." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opcioj de kompari savkopiojn" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Komando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametroj:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Uzi %1 kaj %1 por vojparametroj" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Bonvolu agordi diff-komandon aŭ premi \"Ĉesi\"." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Ne eblas trovi la komandon \"{cmd}\" je tio sistemo. Bonvolu provi ian alion" " aŭ premi \"Ĉesi\"." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Neniom da parametroj agordita por la diff-komando. Uzi defaŭltan valoron " "\"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Savkopioj" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Sole malsamaj savkopioj" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Sole listigi savkopiojn samajn al:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Kompleta kontrolo (pli precize, sed pli malrapide)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Forigi" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Elekti ĉion" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Kompari" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Iri al" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opcioj" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "Ne eblas kompari savkopion kun mem, ĉar la komparado estus senutila." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Ĉu vi vere volas forigi {file_or_dir} en savkopio {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Ĉu vi vere volas forigi {file_or_dir} en {count} savkopioj?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "AVERTO: Ĉi tio ne povas esti nuligita." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Ekskluzivi {path} de estontaj savkopioj?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Ĉef-reĝimo" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time nuntempe rulas je la privilegioj de la ĉej-uzanto (aliro al la " "tuta sistemo)" #: qt/timeline.py:69 msgid "Today" msgstr "Hodiaŭ" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Hieraŭ" #: qt/timeline.py:87 msgid "This week" msgstr "Nuna semajno" #: qt/timeline.py:95 msgid "Last week" msgstr "Lasta semajno" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Tio NE estas savkopion, sed viva vido de viaj lokaj dosieroj." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Lasta kontrolo {time}" backintime-1.6.1/common/po/es.po000066400000000000000000002365501514264426600165270ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Francisco Manuel García Claramonte # SPDX-FileCopyrightText: © Mauricio J. Adonis C. # SPDX-FileCopyrightText: © Adolfo Jayme Barrientos , 2025 # SPDX-FileCopyrightText: © Pablo Huguet # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-06 12:48+0000\n" "Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Todas las licencias usadas en este proyecto se encuentran en el directorio " "{dir_link}. Para extraer información de licencia y derechos de autor por " "archivo a través de metadatos SPDX, consulte {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Aviso" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Perfil principal" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Local (cifrado EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (cifrado EncFS)" #: common/config.py:237 msgid "Local" msgstr "Local" #: common/config.py:240 msgid "Local encrypted" msgstr "Cifrado localmente" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Cifrado" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Clave privada SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Perfil: «{name}»" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "El directorio de la copia de seguridad no es válido." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Debe seleccionarse al menos un directorio para la copia de seguridad." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Directorio: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Este directorio no puede incluirse en la copia de seguridad ya que es parte " "del destino de la misma." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "El valor de «Eliminar la copia de seguridad más antigua si el espacio libre " "es inferior a» ({val_one}) debe ser inferior o igual al umbral de «Advertir " "si el espacio libre en disco es inferior a» ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Ajuste las configuraciones de modo que el límite de eliminaciones de backups" " no supere el límite de aviso." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "La programación de Udev no funciona con el modo {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Error al escribir nuevo crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron no se está ejecutando pese a que la orden crontab está disponible. Los " "trabajos de respaldo programados no se ejecutarán. Es posible que Cron esté " "instalado pero no activado. Intente ejecutar las órdenes «systemctl enable " "cron» y «systemctl start cron», o consulte los canales de asistencia de la " "distribución GNU/Linux que usa para obtener ayuda." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Error al guardar la configuración" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Se produjo un fallo al cargar la configuración" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "El perfil «{name}» ya existe." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "No puede eliminar el último perfil." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "No se puede montar «{command}»" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "No se encuentra la configuración del directorio cifrado." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "¿Quiere crear un directorio cifrado nuevo?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Cancelar" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Por favor, vuelve a introducir la contraseña de EncFS para confirmar." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Las contraseñas de EncFS no coinciden." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Tomar instantánea" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "No se puede inicializar la ruta cifrada «{command}»" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "No se puede desmontar {mountprocess} de {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "No se encontró la orden {command} . Instálela (por ejemplo, mediante " "«{installcommand}»)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "El punto de montaje {mntpoint} no está vacío." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Introduzca la contraseña para el perfil {mode} «{profile}»:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "No se pudo instalar la regla Udev para el perfil {profile_id}. El servicio " "DBus «{dbus_interface}» no estaba disponible." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "No se pudo encontrar el UUID de «{path}»" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "Falló" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Restaurar permisos" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Finalizado" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Las entradas siguientes de la lista de inclusiones no tienen correspondencia" " de archivo o carpeta en la fuente del respaldo:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Aplazando la copia de respaldo mientras se usa la batería" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "No se puede encontrar el directorio de respaldos." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Si está en una unidad extraíble, conéctela." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Esperando {n} segundo." msgstr[1] "Esperando {n} segundos." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "No se pudo crear el respaldo {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Aguarde un momento. Finalizando…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "No se puede crear el directorio." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Guardando archivo de configuración…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Guardando permisos…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Se ha encontrado el respaldo incompleto {snapshot_id} que puede continuarse." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Quitando el directorio {snapshot_id} incompleto de la ejecución pasada" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "No se puede eliminar la carpeta" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Creando respaldo" #: common/snapshots.py:1517 msgid "Success" msgstr "Exito" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "La transferencia fue parcial por un error" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transferencia parcial debido a la desaparición de archivos fuente (consulte " "«man rsync»)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "«rsync» finalizó con el código de salida {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Consulte «man rsync» para más detalles" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Los códigos de salida negativos de rsync son números de señales; consulte " "«kill -l» y «man kill»" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Nada ha cambiado; no hace falta un respaldo nuevo" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "No se puede renombrar {new_path} a {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Aplicando reglas para eliminar copias de seguridad antiguas" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Aplicación de la política de retención" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Intentar mantener el espacio libre mínimo" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Intentando mantener un mínimo de {perc} inodos libres" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Ahora" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "No se puede montar {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent no se encuentra. Asegúrese de que está instalado." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "No se pudo desbloquear la clave privada SSH. Contraseña incorrecta o " "contraseña inaccesible para cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "La ruta remota existe pero no es un directorio." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "La ruta remota no admite escritura." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "La ruta remota no es ejecutable." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "No se ha podido crear la ruta remota." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "El anfitrión remoto {host} no admite {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "Verificando comandos en el host {host} que devolvió un error desconocido" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "El anfitrión remoto {host} no admite enlaces duros" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Copiar clave pública SSH «{pubkey}» en el anfitrión remoto «{host}»." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Introduzca una contraseña para «{user}»." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "El sistema de archivos de destino para {path} está formateado con NTFS, que " "tiene incompatibilidades conocidas con los sistemas de archivos de estilo " "Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} no es un directorio válido." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "No se pudo crear el directorio siguiente:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "El acceso de escritura puede estar restringido." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "El sistema de archivos de destino para {path} está formateado con FAT que no" " admite enlaces físicos. Use un sistema de archivos nativo de GNU/Linux." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "El sistema de archivos de destino para {path} es un recurso compartido " "montado a través de SMB. Asegúrese de que el servidor SMB remoto admite " "enlaces simbólicos o active «{copyLinks}» en «{expertOptions}»." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Copiar enlaces (desreferenciar enlaces simbólicos)" #: common/tools.py:487 msgid "Expert Options" msgstr "Opciones avanzadas" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "El sistema de archivos de destino para {path} es un recurso compartido " "montado a través de sshfs. Sshfs no admite enlaces duros. Use el modo «SSH» " "en su lugar." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "La creación del archivo falló en este directorio:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Acerca de Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Derechos de autor:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Autoría:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Traducción:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Francisco Manuel García Claramonte \n" "Mauricio J. Adonis C. \n" "Adolfo Jayme Barrientos , 2025\n" "Pablo Huguet " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Los créditos de traducción no están disponibles en este idioma." #: qt/aboutdlg.py:116 msgid "this link" msgstr "este enlace" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Visite {thislink} para obtener los créditos de traducción de todos los " "idiomas." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Sitio web del proyecto" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Manual de utilización" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Abrir el manual del usuario en el navegador (local si está disponible, de lo" " contrario, en línea)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versión{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} parece estar ejecutándose por primera vez porque no se encuentra " "ninguna configuración." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "¿Importar una configuración existente desde un respaldo o desde otro " "ordenador?" #: qt/app.py:395 msgid "Then press OK." msgstr "Luego, pulse en Aceptar." #: qt/app.py:499 msgid "Create a backup" msgstr "Crear un respaldo" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Utiliza el tiempo de modificación y el tamaño para detectar cambios en los " "archivos." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Crear un respaldo (modo suma de verificación)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Utiliza sumas de verificación para detectar cambios en los archivos." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Pausar el proceso de respaldo" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Reanudar el proceso de respaldo" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Detener el proceso de respaldo" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Actualizar lista de respaldos" #: qt/app.py:524 msgid "Name backup" msgstr "Dar nombre a respaldo" #: qt/app.py:528 msgid "Remove backup" msgstr "Quitar respaldo" #: qt/app.py:532 msgid "Open backup log" msgstr "Abrir registro de respaldos" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Ver el registro de la copia de seguridad seleccionada." #: qt/app.py:536 msgid "Open last backup log" msgstr "Ver el registro de la copia de seguridad seleccionada" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Ver el registro del respaldo más reciente." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Perfil principal…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Editar user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Apagar" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Apagar el sistema al terminar el respaldo." #: qt/app.py:552 msgid "Setup language…" msgstr "Configurar idioma…" #: qt/app.py:556 msgid "Exit" msgstr "Salir" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "Pagina del manual: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Muestra la página de manual sobre Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "Página del manual: Archivo de configuración de los perfiles" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Muestra la página del manual de usuario sobre la configuración de los " "perfiles (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Abrir en el navegador el sitio web de Back In Time" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Novedades" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Abrir el registro de cambios (localmente si está disponible, de lo contrario" " desde la web)" #: qt/app.py:589 msgid "FAQ" msgstr "Preguntas frecuentes" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Abrir en el navegador las preguntas frecuentes" #: qt/app.py:593 msgid "Ask a question" msgstr "Hacer preguntas" #: qt/app.py:597 msgid "Report a bug" msgstr "Informar de un problema" #: qt/app.py:600 msgid "Translation" msgstr "Traducción" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "" "Muestra nuevamente el mensaje sobre la participación en la traducción." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Transición de cifrado (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Muestra nuevamente el mensaje sobre la eliminación de EncFS." #: qt/app.py:615 msgid "About" msgstr "Acerca de" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Restaurar" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "" "Restaura los archivos o directorios seleccionados a su ubicación original." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Restaurar en…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "" "Restaura los archivos o directorios seleccionados a una nueva ubicación." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Restaura el directorio actual y todo su contenido a la ubicación original." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Restaura el directorio actual y todo su contenido a una nueva ubicación." #: qt/app.py:640 msgid "Up" msgstr "Arriba" #: qt/app.py:643 msgid "Show hidden files" msgstr "Mostrar archivos ocultos" #: qt/app.py:646 msgid "Compare backups…" msgstr "Comparar respaldos…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Candidata para publicación" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "" "Muestra nuevamente el mensaje sobre esta versión candidata para publicación." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Copia de respaldo" #: qt/app.py:733 msgid "&Restore" msgstr "&Restaurar" #: qt/app.py:739 msgid "&Help" msgstr "&Ayuda" #: qt/app.py:790 msgid "Systray Icon" msgstr "Icono del área de notificaciones" #: qt/app.py:796 msgid "Automatic" msgstr "Automático" #: qt/app.py:800 msgid "Light icon" msgstr "Icono claro" #: qt/app.py:801 msgid "Dark icon" msgstr "Icono oscuro" #: qt/app.py:824 msgid "Icons only" msgstr "Solamente iconos" #: qt/app.py:827 msgid "Text only" msgstr "Solamente texto" #: qt/app.py:830 msgid "Text below icons" msgstr "Texto bajo los iconos" #: qt/app.py:833 msgid "Text beside icon" msgstr "Texto junto a los iconos" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Este directorio no existe\n" "en el respaldo seleccionado." #: qt/app.py:1005 msgid "Add to Include" msgstr "Añadir a Incluir" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Añadir a Excluir" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Si esta ventana está cerrada, Back In Time no podrá apagar su sistema cuando" " la copia de seguridad haya terminado." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "¿Quiere cerrar la ventana de todos modos?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Hecho; no se necesita una copia de respaldo" #: qt/app.py:1285 msgid "Working:" msgstr "Trabajando:" #: qt/app.py:1292 msgid "Working" msgstr "En curso" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Error" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Enviado:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Velocidad:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Tiempo restante estimado:" #: qt/app.py:1490 msgid "Backup:" msgstr "Copia de seguridad:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Restaurar {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Restaurar {path} en…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hola\n" "Ya has utilizado Back In Time en el idioma {language} unas cuantas veces.\n" "La traducción de su versión instalada de Back In Time al {language} está {perc} completa. Independientemente de su nivel de conocimientos técnicos, puede contribuir a la traducción y, por tanto, al propio Back In Time.\n" "Visite {translation_platform_url} si desea contribuir. Para más ayuda y preguntas, visite el {back_in_time_project_website}.\n" "Le pedimos disculpas por la interrupción, y este mensaje no se volverá a mostrar. Este diálogo está disponible en cualquier momento a través del menú de ayuda.\n" "Su equipo Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "plataforma de traducciones" #: qt/app.py:1714 msgid "Website" msgstr "Sitio web" #: qt/app.py:1728 msgid "Your translation" msgstr "La traducción" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "En el fediverso en Mastodon: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Correo electrónico a {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Lista de correo {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} en la página web del proyecto." #: qt/app.py:1781 msgid "Open an issue" msgstr "Informar de un fallo" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "De forma alternativa, puede usar otro canal de su elección." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Esta versión de Back In Time es preliminar y está destinada principalmente a realizar pruebas de estabilidad para preparar la próxima versión oficial.\n" "No se recogen datos de usuario ni telemetría. No obstante, el equipo de Back In Time está muy interesado en saber si se le da uso a la versión preliminar y si merece la pena seguir brindándolas.\n" "Por ello, el equipo le pide que nos comunique brevemente si ha probado esta versión, aunque no haya encontrado ningún problema. Incluso una prueba rápida de unos minutos nos ayudaría mucho.\n" "Tiene a su disposición las siguientes opciones de contacto:\n" "{contact_list}\n" "En esta versión, este mensaje no se volverá a mostrar pero se podrá acceder a él en cualquier momento a través del menú Ayuda.\n" "¡Gracias por su apoyo y por ayudarnos a mejorar Back In Time!\n" "El equipo de Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Solo {free} de almacenamiento libre en el destino, lo cual es menor al " "límite configurado de {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "¿Proceder con la copia de seguridad?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" "Desaparecerán todos los archivos más recientes en {path}. ¿Quiere continuar?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Desaparecerán todos los archivos más recientes del directorio original. " "¿Quiere continuar?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Atención{BOLDEND}: eliminar archivos en la raíz del sistema de " "archivos podría hacer que todo el sistema deje de funcionar." #: qt/app.py:2167 msgid "Backup name" msgstr "Nombre del respaldo" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "¿Quiere quitar este respaldo?" msgstr[1] "¿Quiere quitar estos respaldos?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "La configuración de idioma solo surte efecto después de reiniciar Back In " "Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Copias de seguridad versionadas (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "GUI para copias de seguridad con menor uso de espacio (modo root)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Copias de seguridad versionadas" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Interfaz gráfica de usuario fácil de usar para copias de seguridad " "versionadas que reduce el uso del disco" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Pregunta" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Crea copias de seguridad con el sufijo {suffix} antes de sobrescribir o " "eliminar elementos locales." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Antes de restaurar, las versiones más recientes de los archivos se " "renombrarán añadiéndoles el sufijo {suffix}. Estos archivos se pueden " "eliminar con el siguiente comando:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Solo restaura los elementos que no existen o que son más recientes que los " "del destino. Usando la opción «{rsync_example}»." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Eliminar los elementos más nuevos del directorio original." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Restaurar los archivos o directorios seleccionados a la ubicación original y" " eliminar los archivos o directorios que no se encuentran en la copia de " "seguridad. Tenga mucho cuidado porque esto eliminará archivos y directorios " "que se excluyeron durante la creación de la copia de seguridad." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "¿Realmente quiere restaurar este elemento en el directorio nuevo?" msgstr[1] "" "¿Realmente quiere restaurar estos elementos en el directorio nuevo?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "¿Realmente quiere restaurar este elemento?" msgstr[1] "¿Realmente quiere restaurar estos elementos?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Retrollamada-usuario: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "El user-callback script debe incluir una shebang en la primera linea (e.g. " "{example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Mostrar/ocultar archivos y directorios ocultos (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Configurar el idioma" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Traducido: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Predeterminado del sistema" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Utilizar el idioma del sistema operativo." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Vista de registros de respaldo" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Ver el último registro" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Perfil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Respaldos:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtrar:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Error, [I] Información, [C] Cambiar" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "descodificar rutas" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Todo" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Cambios" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Errores" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Información" msgstr[1] "Informaciones" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "Fallos en las transferencias rsync (experimental)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Gestionar perfiles" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Editar" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Añadir" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Quitar" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&General" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Incluir" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Excluir" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Elimina&r & retención" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Opciones" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "A&justes avanzados" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Restablecer configuración" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Perfil nuevo" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Cambiar nombre de perfil" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "¿Quiere eliminar el perfil «{name}»?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Copiar enlaces simbólicos como archivos" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Copiar enlaces simbólicos como archivos o directorios reales en la copia de " "seguridad. Seleccione si desea copiar todos los enlaces o solo los que " "apuntan fuera del origen." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Esta opción puede aumentar el tamaño de la copia de seguridad." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Deshabilitado por defecto." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Todos los enlaces simbólicos se reemplazan con los archivos o directorios " "reales a los que apuntan. Esto aumenta el tamaño de la copia de seguridad y " "puede almacenar los mismos archivos varias veces." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Usa 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Solo externa" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Solo se copian como archivos los enlaces que apuntan fuera de la fuente de " "la copia de seguridad. Esto aumenta el tamaño de la copia de seguridad y " "puede almacenar los mismos archivos varias veces." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Usa 'rsync --copy-unsafe-links'." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Archivos temporales del editor y de Office" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Archivos de respaldo de Emacs" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Archivos de autoguardado de Emacs" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Archivos de intercambio de Vim" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Archivos temporales de Microsoft Office" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice y otros editores de OpenDocument bloquean archivos" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniaturas e imágenes temporales" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "Caché de miniaturas en GNU/Linux y otros sistemas operativos Unixoid" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Base de datos de miniaturas en Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Directorio de metadatos en MacOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Application-specific bloqueadas" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Archivo de bloqueo de la aplicación Discord" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Archivo de bloqueo de sesión de Discord" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Archivo de bloqueo de Mozilla Firefox y Thunderbird" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Cachés y directorios temporales" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Caché de la aplicación del usuario" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Directorio temporal del sistema" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Caché de paquetes para distribuciones GNU/Linux basadas en Debian" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Repositorio de aplicaciones y tiempo de ejecución de Flatpak" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Directorios temporales que almacenan datos volátiles" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Información del Kernel y del proceso" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Información del dispositivo y otro hardware (interfaz sysfs)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Nodos de dispositivo" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Archivos del sistema de tiempo de ejecución" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Otras no-persistentes" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Lista de sistemas de archivos montados actualmente" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Archivo de intercambio del sistema (memoria virtual)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Punto de montaje del sistema de archivos virtual de GNOME" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Objetos del sistema de archivos recuperados" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Misceláneas" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Directorio de metadatos en Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Papelera de reciclaje del usuario" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Archivos de la copia de seguridad del sistema" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Excluir sugerencias" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Seleccione elementos de uso común para agregarlos a las exclusiones de " "respaldo." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Por defecto" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Restablecer a la selección predefinida" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Tareas programadas" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Día:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Día laborable:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Tiempo:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Horas:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "Cada hora" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minutos:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Ejecuta Back In Time tan pronto como se conecte la unidad (solo una vez cada" " X días). Aparecerá un aviso de contraseña de sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Ejecuta Back In Time repetidamente. Esto es útil si el equipo no se está " "ejecutando regularmente." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Cada:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Activar el registro de mensajes de depuración" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Escribe mensajes de nivel de depuración en el registro del sistema mediante " "«--debug»." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Precaución: utilícelo solo temporalmente para diagnósticos, ya que genera " "una gran cantidad de salida." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Desactivado" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "En cada arranque/reinicio" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Cada minuto" msgstr[1] "Cada {n} minutos" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Cada hora" msgstr[1] "Cada {n} horas" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Horario personalizado" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Todos los días" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Repetidamente (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Cuando la unidad se conecta (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Semanalmente" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Mensualmente" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Anualmente" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Hora(s)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Día(s)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Semana(s)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mes(es)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Las horas personalizadas solo pueden ser una lista de horas separadas por " "comas (por ejemplo, 8,12,18,23) o */3 para copias de respaldo periódicas " "cada 3 horas." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Vali olemasolev privaatvõtme fail kusagilt mujalt." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Loo uus ilma salafraasita SSH võti." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Täisasukoht: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Privaatvõti:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Kasuta süsteemi SSH-seadistusi" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Sellega jääb võtmefail valimata. SSH ühendused sõltuvad süsteemi üldistest " "kliendi seadistustest (nt. ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH proksi" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Host:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Kasutaja:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Ühenduseks välise seadmega kasuta seda proksit (tuntud ka hüppeserverina). " "Vaata „ssh“ käsu juhendist „-J“ võtit või „man ssh_config“ juhendist " "„ProxyJump“ lõiku." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Lisateave{ENDBOLD}: Kui töörežiimiks on „SSH krüptituna“, siis " "toimivad vaid ühe- ja kahekordsed tärnid (näiteks: {example2}). Muud " "metamärgid ja mustrid ei ole kasutusel (näiteks: {example1}). Kuna kasutusel" " on krüptimine EncFSiga, siis selles režiimis on failide nimed " "ettearvamatud." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Jäta välja mustrid, failid või kaustad" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Lisa muster" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Lisa faile" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Lisa kaustu" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Soovitused" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "Vali näiteid tüüpilisest välistusloendist." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Jäta välja failid, mis on suuremad, kui:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Jäta välja failid, mis on suuremad, kui {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Kui töörežiim „Täiemahuline sünkroniseerimine rsynci abil“ pole kasutusel, " "siis see eelistus mõjutab vaid uusi faile (tegemist on failide liigutamise " "eelistusega, mitte välistamise eelistusega). Seetõttu varem varundatud " "suured failid jäävad varukoopiatesse ka siis, kui neid on hiljem muudetud." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Jäta välja mustri alusel" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Jäta välja järgneva mustri alusel:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Abiteavet leiad käsuga „man rsync“ alalõigust {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Ava rsynci abiteabe leht" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Välista failid" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Välista kaustad" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Kuna selline muster pole režiimis „SSH krüptituna“ funktsionaalne, siis " "eelistus on välja lülitatud." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Need eelistused on mõeldud asjatundjatele ja keerukamate kasutusjuhtumite " "jaoks. Muuda neid ainult siis, kui täpselt tead, mida teed." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Käivita „rsync“ käsuga „{cmd}“:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "kasutades ajastamist croniga" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "välises seadmes" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "kui teed varukoopiat käsitsi" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Selle eelistuse kasutamiseks palun paigalda „nocache“." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "kohalikus arvutis" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" "Croniga ajastatud tööde puhul suuna standardväljund nulli (stdout > " "/dev/null)." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Kui e-kirjade edastamine on seadistatud, siis cron saadab automaatselt " "kirja, mille manuseks on croni tehtud töö väljund." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" "Croniga ajastatud tööde puhul suuna standardviga nulli (stderr > /dev/null)." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Kui e-kirjade edastamine on seadistatud, siis cron saadab automaatselt " "kirja, mille manuseks on croni tehtud töös tekkinud vead." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/sek" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Piira rsync'i ribalaiust:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Säilita pääsuloend (ACL)" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Säilita failide laiendatud metainfo (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Piirdu ühe failisüsteemiga" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Lisatingimused peavad olema jutumärkide vahel, näiteks {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Lisa rsync-ile täiendavad suvandeid" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Välises seadmes käivita iga käsu ees see prefiks." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Muutujad peavad olema tähistatud $FOO paomärkidega. See ei käi rsynci kohta." " Seega, lisamaks rsyncile prefikseid kasuta „{example_value}“ koos " "„{rsync_options_value}“." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "vaikimisi" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Lisa SSH käsule eesliiteid" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Kontrolli, kas väline seade on võrgus" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Hoiatus: kui see eelistus on välja lülitatud ja väline seade pole võrgus, " "siis võib tekkida imelikke vigu." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" "Kontrolli, kas väline seade võimaldab kõikide vajalike käskude kasutamist." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Hoiatus: kui see eelistus on välja lülitatud ja väline ei toeta kõiki " "vajalikke käske, siis võib tekkida imelikke vigu." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(vaikimisi: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "pole kasutusel" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "kasutusel" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Töörežiim:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Kuhu salvestame varukoopiad" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH seadistused" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Asukoht:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Võtmefail:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Salasõna" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Salvesta salasõna tarkvaralises võtmerõngas" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Puhverda salasõna croni jaoks (See on ka turvaprobleem: juurkasutajal on " "võimalik salasõna lugeda)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Täiendavad seadistused" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Varukoopiate täpne asukoht:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Kuna croni paigaldust ei leidu, siis ajastamine pole kasutusel. Kui soovid, " "et varukoopiate tegemine toimuks etteantud graafiku alusel, siis paigalda " "arvutisse cron." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Varunduse sihtkaust ei saa jääda tühjaks." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Krüptimise salasõna ei saa jääda tühjaks." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Kaugseadmesse logimisel tekkis viga. Tegevuse kohta on teada selline " "veateade:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Kui tahad kasutada salasõnata sisselogimist, siis kopeeri vastava kasutaja " "avalik SSH-võti kaugseadmesse." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Kas jätkame SSH-võtme kopeerimisega?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Avaliku SSH võtme kopeerimine ei õnnestunud. See võis juhtuda ühenduse vea " "või õiguste puudumise tõttu." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Hosti „{host}“ autentsust pole võimalik tuvastada." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} võtme sõrmejälg on:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Palun kontrolli, et tegemist on õige sõrmejäljega. Kas sa sooviksid teda " "lisada ka „known_hosts“ faili?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Kas tõesti muudame varukoopiate kausta?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Valitud varunduse sihtkaust pole tühi." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Krüptimise kasutamiseks peab ta olema tühi." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Vigane fail: see pole SSH privaatvõti" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Valitud fail ({path}) tundub olema avalik SSH võti. Palun vali privaatvõtme " "fail (selline, kus pole .pub laiendit)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "{path} fail on juba olemas. Sellise nimega SSH-võtit ei saa luua." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Uue SSH võtme loomine asukohta „{path}“ ei õnnestunud." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Kaasa failid ja kaustad" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "„{path}“ on sümbollink. Lingi sihtkausta või -faili ei varundata seni, kuni " "sa pole teda kaasanud." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Kas kaasad selle asemel sümbollingi kausta?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Kaasa failid" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Kaasa kaustad" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Luba teavitused" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Kui arvuti on akutoitel, siis ära tee varukoopiaid" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Toitesüsteemi oleks pole siin arvutis tuvastatav" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Tee korraga vaid üks varukoopia" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Muude varukoopiate tegemine on seni blokeeritud, kuni hetkel töös olev " "varukoopia on tehtud. See on rakenduse üldine eelistus ja seega mõjutab " "selle kasutaja kõiki profiile. Aga sa pead ta aktiveerima kõikide teiste " "kasutajate jaoks." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Taastamisel tee asendatud failidest varukoopia" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Vigade puhul jätka tööd (säilita poolikud varukoopiad)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Muutuste tuvastamiseks kasuta kontrollsummat" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" "Tee uus varukoopia hoolimata sellest, kas arvutis tekkis muutusi või mitte." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Hoiata, kui vaba andmeruumi on vähem, kui" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Rakendus kuvab hoiatuse, kui varunduse sihtkaustas on määratud mahust vähem " "vaba ruumi." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Kui „Eemaldamise ja säilitamise“ reeglid on kasutusel ja vanad varukoopiad " "eemaldatakse vaba andmeruumi alusel, siis see väärtus ei saa olla väiksem, " "kui reeglites on määratud." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Logitase:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Määramata" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "kasutusjuhendis" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Järgnevaid reegleid töödeldakse suunaga ülevalt alla. Hilisemad reeglid " "alati asendavad varasemaid ega ole varasemaist kuidagi mõjutatud. " "Üksikasjade ja näidete teave leidub siin: {manual_link}." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Ava kasutusjuhend veebibrauseris." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Säilita viimane varukoopia." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Viimane ja kõige värskem varukoopia säilib igal juhul." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Seda reeglit pole mitte kuidagi võimalik muuta." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Ära kustuta nimedega varukoopiaid." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Varukoopiad, millel lisaks tavapärasele ajatemplile on eraldi nimi, jäävad " "kõikides olukordades alles ega kuulu kustutamisele." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Aasta(t)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Eemalda varukoopiad, mis on vanemad kui" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Täispäevades ja tänane päev ei lähe arvesse." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Esmaspäevaga algavates kalendrinädalates ja see nädal ei lähe arvesse." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12-kuulistes ajavahemikes ja praegune kuu ei lähe arvesse." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Säilitamise reeglid" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Käivita välises seadmes taustal." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Säilitusreegleid järgitakse otseselt välisseadmes, mitte kohalikus seadmes. " "Selleks peavad välisseadmes olema paigaldatud „bash“, „screen“ ja „flock“." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Kui valitud, siis Back In Time esmalt testib välisseadet." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Päevi loendame alates tänasest." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Säilita kõik varukoopiad viimase" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "päeva kestel." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Säilita viimane varukoopia iga päeva kohta viimase" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "Nädalaid loendame alates sellest nädalast. Nädal algab esmaspäevaga." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Säilita viimane varukoopia iga nädala kohta viimase" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "nädala jooksul." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Kuid loendame kalendrikuudena alates sellest kuust." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Säilita viimane varukoopia iga kuu kohta viimase" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "kuu kestel." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Aastaid loendame kalendriaastatena alates sellest aastast." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Säilita viimane varukoopia iga aasta kohta" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "läbi aastate." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… kui vaba ruumi on vähem kui" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… kui vabu indekssõlmesid on vähem kui" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Eemalda vanimad varukoopiad, kui…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" "Et saaksid Back In Time'i käivitada peakasutaja õigustes, pead end " "autentima." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Kui soovid muuta varunduse ajastamist, mis käivituvad väliste andmekandjate " "ühendamisel, siis pead end autentima." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Otseteed" #: qt/placeswidget.py:63 msgid "Places" msgstr "Asukohad" #: qt/placeswidget.py:64 msgid "File System" msgstr "Failisüsteem" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Tagavarakoopia kaustad" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profiil: „{profile_name}“" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profiil: „{profile_name}“ (kasutajalt „{desktop_user}“)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Vaata viimast logi" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Käivita {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Töötan…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "Abiteabe leht: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Impordi seadistused" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Sa pole valinud ühtegi kausta" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Impordi" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Otsin…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Vali varukoopiate kaust, kust soovid seadistuste faili importida. Asukoht " "võiks olla midagi sellist: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Kui vastav kaust asub välisel andmekandjal või kaugseadmes, siis esmalt " "palun haagi ta käsitsi." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Skaneeri uuesti" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Näita peidetud kaustu" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Näita/peida peidetud kaustu (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Selles kaustas ei leidunud ühtegi seadistust" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Otsing on lõppenud." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Näita tervet logi" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Pöördloendus väljalülitamiseni" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Varukoopia tegemine on lõppenud." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Katkesta väljalülitamine" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Lülita välja kohe" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Arvuti lülitub välja {n} sekundi pärast." msgstr[1] "Arvuti lülitub välja {n} sekundi pärast." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Varukoopiate võrdlemise valikud" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Käsk:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parameetrid:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Asukoha parameetritena kasuta „%1“ ja „%2“" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Palun seadista „diff“ käsk või vajuta „Katkesta“." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Käsku „{cmd}“ ei leidu selles seadmes. Palun proovi midagi muud või vajuta " "„Katkesta“." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Diff käsu parameetrid puuduvad. Kasutan vaikimisi väärtust „{params}“." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Varukoopiad" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Vaid siis, kui varukoopiad erinevad" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Näita vaid varukoopiaid, mis võrduvad järgnevaga:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Põhjalik kontroll (palju täpsem, aga ka aeglasem)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Kustuta" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Vali kõik" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Võrdle" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Mine" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Valikud" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Kuna võrdlus oleks siis liigne, pole võimalik teha varukoopiat iseendasse." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Kas sa kindlasti soovid kustutada „{file_or_dir}“ hetktõmmises nr " "{backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "" "Kas sa kindlasti soovid kustutada „{file_or_dir}“ kokku {count}-s " "varukoopias?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "HOIUATUS: seda tegevust ei saa tagasi pöörata." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Kas soovid välistada tulevastest varukoopiatest asukoha „{path}“?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Juurkasutaja režiim" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time töötab hetkel juurkasutaja õigustes (ehk täisligipääsuga " "sellele süsteemile)" #: qt/timeline.py:69 msgid "Today" msgstr "Täna" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Eile" #: qt/timeline.py:87 msgid "This week" msgstr "Sel nädalal" #: qt/timeline.py:95 msgid "Last week" msgstr "Eelmisel nädalal" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "See EI OLE varukoopia, vaid sinu kohaliku failisüsteemi failide tegelik " "vaade." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Viimati kontrollitud {time}" backintime-1.6.1/common/po/eu.po000066400000000000000000002247571514264426600165370ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Alexander Gabilondo # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-11-19 19:10+0000\n" "Last-Translator: alexgabi \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.14\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Proiektu honetan erabiltzen diren lizentzia guztiak {dir_link} direktorioan " "daude. Fitxategiaren lizentzia eta copyrightari buruzko informazioa SPDX " "metadatuak erabiliz ateratzeko, ikusi {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Abisua" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Profil nagusia" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokala (EncFS zifratua)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS zifratua)" #: common/config.py:237 msgid "Local" msgstr "Lokala" #: common/config.py:240 msgid "Local encrypted" msgstr "Lokalki zifratua" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Zifraketa" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH giltz pribatu" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profila: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Babeskopien direktorioa ez da baliozkoa." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Gutxienez direktorio bat hautatu behar da babeskopia egiteko." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Direktorioa: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Karpeta hau ezin da babeskopian sartu babeskopiaren helburu beraren zatia " "baita." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "\"Kendu babeskopiarik zaharrena, leku librea hau baino txikiagoa bada\" " "({val_one}) balioak \"Abisatu diskoko leku librea behera badoa\" ({val_two})" " atalasea baino txikiagoa edo berdina izan behar du." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Mesedez, doitu ezarpenak babeskopia ezabatzeko muga abisu-muga baino " "handiagoa izan ez dadin." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Programatutako Udev-a ez dabil {mode} moduarekin" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Huts egin du crontab berria idazten." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron ez da exekutatzen crontab agindua eskuragarri egon arren. " "Programatutako babeskopia lanak ez dira exekutatuko. Baliteke Cron " "instalatuta egotea baina gaituta ez egotea. Saiatu \"systemctl enable cron\"" " eta \"systemctl start cron\" komandoak exekutatzen edo kontsultatu zure " "GNU/Linux banaketaren laguntza kanalak." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Huts egin du ezarpenak gordetzen" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Huts egin du ezarpenak kargatzen" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "\"{name}\" profila badago honezkero." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Ezin da azken profila kendu." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "'{command}' ezin da muntatu" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Zifratutako karpetaren ezarpenak ez dira aurkitu." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Karpeta zifratu berri bat sortu?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Utzi" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Sartu berriro EncFS pasahitza berresteko." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS pasahitzak ez datoz bat." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Egin babeskopia" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "'{command}' ezin da muntatu" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Ezin da {mountprocess} desmuntatu {mountpoint}-tik." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} ez da aurkitu. Mesedez instalatu (adibidez \"{installcommand}\"ren" " bidez)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "{mntpoint} muntatze-puntua ez dago hutsik." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Idatzi {mode} \"{profile}\" profilaren pasahitza:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Ezin izan da Udev araua instalatu {profile_id} profilarentzat. " "'{dbus_interface}' DBus zerbitzua ez zegoen erabilgarri." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Ezin da UUID aurkitu \"{path}\"-erako" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "HUTS EGIN DU" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Leheneratu baimenak" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Eginda" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Zerrendako sarrera hauek ez dute dagokien fitxategi edo direktoriorik " "babeskopiaren iturburuan:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Atzeratu babeskopia bateriaz dabilen bitartean" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Ezin da aurkitu babeskopien direktorioa." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Unitate eramangarri batean badago konekta ezazu." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Segundo {n} itxaroten." msgstr[1] "{n} segundo itxaroten ." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Huts egin du {snapshot_id} babeskopia egiten." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Mesedez, izan pazientzia. Amaitzen…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Ezin da karpeta sortu." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Gorde ezarpenen fitxategia…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Baimenak gordetzen…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "'{snapshot_id}' jarraitu daitekeen osatu gabeko babeskopia aurkitu da." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Azken exekuziotik '{snapshot_id}' karpeta osatu gabea kentzen" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Ezin da karpeta ezabatu" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Babeskopia sortzen" #: common/snapshots.py:1517 msgid "Success" msgstr "Ongi" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Transferentzia partziala errorea dela eta" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transferentzia partziala desagertutako iturburu-fitxategiengatik (ikus 'man " "rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "\"rsync\" amaitu da irteera-kode honekin {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Ikus 'man rsync' xehetasun gehiagorako" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Rsync irteera kode negatiboak seinale zenbakiak dira, ikusi 'kill -l' eta " "'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Ez dago aldaketarik. Ez da babeskopia berririk egin behar" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Ezin zaio {new_path}-(r)i {path} izena jarri." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Aplikatu babeskopia zaharrak ezabatzeko arauak" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Aplikatu atxikipen politika" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Saiatu espazio minimoa mantentzen" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Saiatu gutxienez {perc} nodo libre mantentzen" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Orain" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Ezin da {sshfs} muntatu" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent ez da aurkitu. Ziurtatu instalatuta dagoela." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Ezin da SSH-ren gako pribatua desblokeatu. Okerreko pasahitza edo cron-" "entzat baliozkoa ez den pasahitza." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Urrutiko bide-izena badago baina ez da direktorio bat." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Urrutiko bide-izenak ez dauka idazteko baimenik." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Urrutiko bide-izena ez da exekutagarria." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Ezin da sortu urrutiko bide-izena." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Urruneko {host} ostalariak ez du {command} onartzen" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "{host} ostalariaren egiaztatzeko komandoek errore ezezaguna itzuli dute" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "{host} urrutiko ostalariak ez ditu esteka gogorrak onartzen" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Kopiatu \"{pubkey}\" ssh-gako publikoa \"{host}\" urrutiko ostalarira." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Sartu \"{user}\"-entzako pasahitza bat." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "'{path}'-(r)en helburuko fitxategi-sistemaren formatua NTFS da. NTFS ezaguna" " da Unix estikoko fitxategi-sistemekin konpatibilitate arazoak izatearren." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} ez da direktorio balido bat." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Ezin izan da hurrengo direktorioa sortu:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Baliteke idazteko sarbidea mugatuta egotea." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "'{path}'-(r)en helburuko fitxategi-sistemaren formatua FAT da eta ez du " "esteka gogorrik onartzen. Erabili Linux jatorriko fitxategi-sistema bat." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "'{path}'-(r)en helburuko fitxategi-sistema SMB-ez muntatutako partekatutako " "karpeta da. Egiaztatu urruneko SMB zerbitzariak esteka sinbolikoak onartzen " "dituela edo gaitu '{copyLinks}' '{expertOptions}'-en." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopiatu estekak (erreferentzia kendu esteka sinbolikoei)" #: common/tools.py:487 msgid "Expert Options" msgstr "Aukera aurreratuak" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "'{path}'-(r)en helburuko fitxategi-sistema sshfs-ez muntatutako " "partekatutako karpeta da. sshfs-ek ez du esteka gogorrik onartzen. Erabili " "'SSH' haren ordez." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Ezin izan da fitxategia sortu direktorio honetan:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Back In Time aplikazioari buruz" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Egile-eskubideak:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Egileak:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Itzultzaileak:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Alexander Gabilondo " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Itzultzailearen kredituak ez daude erabilgarri hizkuntza honetarako." #: qt/aboutdlg.py:116 msgid "this link" msgstr "esteka hau" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "Jarraitu {thislink} hizkuntza guztien itzultzaile kredituak lortzeko." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Proiektuaren webgunea" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Erabiltzailearen eskuliburua" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Ireki erabiltzailearen eskuliburua nabigatzailean (tokikoa eskuragarri " "badago, bestela lineakoa)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Bertsioa{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} lehen aldiz exekutatzen ari dela dirudi, ez baita konfiguraziorik" " aurkitzen." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Lehendik dagoen konfigurazio bat inportatu (babeskopia batetik edo beste " "ordenagailu batetik)?" #: qt/app.py:395 msgid "Then press OK." msgstr "Ondoren, sakatu Ados." #: qt/app.py:499 msgid "Create a backup" msgstr "Sortu babeskopia bat" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Erabili denbora eta tamaina aldaketak fitxategi-aldaketak hautemateko." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Egin babeskopia (kontrol baturarekin)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Erabili kontrol-batura aldaketak detektatzeko." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Pausatu babeskopia prozesua" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Babeskopia prozesuaren txosten laburra egin" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Gelditu babeskopia prozesua" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Freskatu babeskopien zerrenda" #: qt/app.py:524 msgid "Name backup" msgstr "Izena eman babeskopiari" #: qt/app.py:528 msgid "Remove backup" msgstr "Kendu babeskopia" #: qt/app.py:532 msgid "Open backup log" msgstr "Ikusi babeskopiaren erregistroa" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Ikusi hautatutako babeskopiaren erregistroa." #: qt/app.py:536 msgid "Open last backup log" msgstr "Ireki azken babeskopiaren erregistroa" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Ikusi azken babeskopiaren erregistroa." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Kudeatu profilak…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Editutatu erabiltzailearen atzeradeia" #: qt/app.py:548 msgid "Shutdown" msgstr "Itzali" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Itzali sistema babeskopia bukatu ondoren." #: qt/app.py:552 msgid "Setup language…" msgstr "Konfiguratu hizkuntza…" #: qt/app.py:556 msgid "Exit" msgstr "Irten" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man orria: Back In &Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Back In Time-ren man orria erakusten du (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man orria: profilen konfigurazio fitxategia" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Konfigurazio fitxategien gaineko man orria erakusten du (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Ireki Back In Time-ren webgunea nabigatzailean" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Aldaketen egunkaria" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Ireki aldaketen erregistroa (tokikoa eskuragarri badago, bestela webekoa)" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Ireki ohiko galderak (FAQ) nabigatzailean" #: qt/app.py:593 msgid "Ask a question" msgstr "Zerbait galdetu" #: qt/app.py:597 msgid "Report a bug" msgstr "Akats baten berri eman" #: qt/app.py:600 msgid "Translation" msgstr "Itzulpena" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Itzulpenean parte hartzeari buruzko mezua erakusten du berriro." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Enkriptazio-trantsizioa (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "EncFS kentzeari buruzko mezua erakusten du berriro." #: qt/app.py:615 msgid "About" msgstr "Honi buruz" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Berreskuratu" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "" "Leheneratu hautatutako fitxategiak edo karpetak jatorrizko kokalekura." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Leheneratu hona …" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "" "Leheneratu hautatutako fitxategiak edo karpetak kokaleku berri batera." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Leheneratu begi-bistako karpeta eta haren eduki guztia jatorrizko " "kokalekura." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Leheneratu begi-bistako direktorioa eta bere eduki guztia kokaleku berri " "batera." #: qt/app.py:640 msgid "Up" msgstr "Gora" #: qt/app.py:643 msgid "Show hidden files" msgstr "Erakutsi ezkututko fitxategiak" #: qt/app.py:646 msgid "Compare backups…" msgstr "Konparatu babeskopiak…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Askatzeko bertsio hautagaia" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Bertsio hautagai honi buruzko mezua erakusten du berriro." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Babeskopia" #: qt/app.py:733 msgid "&Restore" msgstr "&Leheneratu" #: qt/app.py:739 msgid "&Help" msgstr "L&aguntza" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "Ikonoak bakarrik" #: qt/app.py:827 msgid "Text only" msgstr "Testua bakarrik" #: qt/app.py:830 msgid "Text below icons" msgstr "Testua ikonoen azpian" #: qt/app.py:833 msgid "Text beside icon" msgstr "Testua ikonoen ondoan" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Direktorio hau ez da existitzen\n" "une honetan hautatutako babeskopian." #: qt/app.py:1005 msgid "Add to Include" msgstr "Gehitu sartu beharrekoetan" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Gehitu kanpoan utzi beharrekoetan" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Leiho hau ixten baduzu Back In Time-k ezin izango du zure sistema itzali " "babeskopia bukatzean." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Leihoa itxi edonola?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Egina, ez da babeskopia egin behar" #: qt/app.py:1285 msgid "Working:" msgstr "Lanean:" #: qt/app.py:1292 msgid "Working" msgstr "Lanean" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Errorea" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Bidalita:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Abiadura:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 msgid "Backup:" msgstr "Babeskopia:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Berreskuratu {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Leheneratu {path} hona…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Kaixo\n" "Dagoeneko hainbat aldiz erabili duzu Back In Time aplikazioa {language} hizkuntzan.\n" "Instalatuta duzun Back In Time-ren bertsioaren {language}-zko itzulpenaren {perc} eginda dago. Itzulpena egiten lagundu zenezake eta modu horretan Back In Time lagunduko duzu, jakintza teknikorik izan gabe.\n" "Bisitatu {translation_platform_url} ekarpenak egin nahi badituzu. Laguntza edo galderak badituzu, bisitatu {back_in_time_project_website}.\n" "Barkatu eragozpenak, mezu hau ez da berriro agertuko. Mezu hau berriz ikusi dezakezu laguntza menua erabiliz.\n" "Zure Back In Time taldea" #: qt/app.py:1709 msgid "translation platform" msgstr "Itzulpenetarako plataforma" #: qt/app.py:1714 msgid "Website" msgstr "Webgunea" #: qt/app.py:1728 msgid "Your translation" msgstr "Zure Itzulpena" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Fedibertsoko Mastodonen: {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Posta-zerrenda {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Posta-zerrenda {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} proiektuaren webgunean." #: qt/app.py:1781 msgid "Open an issue" msgstr "Arazo baten berri eman" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Bestela, nahi duzun kanala erabil dezakezu." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Back In Time-ren bertsio hau hautagaia da eta hurrengo bertsio ofizialerako prestatzeko egonkortasun-probak egiteko da.\n" "Ez da erabiltzailearen daturik edo telemetriarik biltzen. Hala ere, Back In Time taldeari asko interesatzen zaio Release Candidate erabiltzen ari ote den eta ea merezi duen jakitea aurreko bertsioak ematen jarraitzea.\n" "Hori dela eta, taldeak iritzi labur bat eskatzen dizu bertsio hau probatu duzun ala ez jakiteko, nahiz eta arazorik ez aurkitu. Minutu gutxiko proba azkar batek ere asko lagunduko liguke.\n" "Harremanetarako aukera hauek daude eskuragarri:\n" "{contact_list}\n" "Bertsio honetan, mezu hau ez da berriro erakutsiko, baina edonoiz atzi dezakezu laguntza-menuaren bidez.\n" "Eskerrik asko zure laguntzagatik eta Back In Time hobetzen laguntzeagatik!\n" "Zure Back In Time taldea" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Helmugan libre dagoen {free}-ko lekua soilik, konfiguratutako {threshold}-ko" " atalasearen azpitik dagoena." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Ekin babeskopia egiteari?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "{path}-eko fitxategi guztiak ezabatuko dira. Ekin?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "Jatorrizko direktorioko fitxategi berri guztiak ezabatuko dira. Ekin?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Kontuz{BOLDEND}: fitxategi-sistemaren erroko fitxategiak ezabatzeak " "sistema osoa hondatu dezake." #: qt/app.py:2167 msgid "Backup name" msgstr "Babeskopiaren izena" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Ezabatu babeskopia hau?" msgstr[1] "Ezabatu babeskopia hauek?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Hizkuntza-ezarpenek Back In Time berrabiarazi ondoren bakarrik izango dute " "eragina." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "Mantendu izena duten babeskopiak." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Galdera" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Egin babeskopia '{suffix}' atzizkiarekin elementu lokalak gainidatzi edo " "ezabatu aurretik." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Leheneratu baino lehen, fitxategien bertsio berriak berrizendatuko dira " "'{suffix}' gehituta. Ez badituzu gehiago behar ezabatu ditzakezu honako " "aginduarekin:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Leheneratu soilik falta diren fitxategiak edo helburuko tokikoak baino " "berriagoak direnak, \"{rsync_example}\" aukera erabiliz." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Ezabatu jatorrizko karpetako fitxategirik berrienak." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Leheneratu hautatutako fitxategiak edo direktorioak jatorrizko kokalekura " "eta ezabatu babeskopian ez dauden fitxategi edo direktorioak. Kontu handiz " "egin, honek babeskopia egitean baztertutako fitxategi eta karpetak ezabatuko" " ditu." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Seguru zaude elementu hau direktorio berrian leheneratu nahi duzula?" msgstr[1] "" "Seguru zaude fitxategi hauek direktorio berrian leheneratu nahi dituzula?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Ziur zaude fitxategi hau berreskuratu nahi duzula?" msgstr[1] "Ziur zaude fitxategi horiek berreskuratu nahi dituzula?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Erabiltzaile-deia itzultzea: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Erabiltzailearen deia itzultzeko script-ak shebang bat (#!) izan behar du " "lehen lerroan (adib. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Erakutsi/ezkutatu ezkutuko fitxategiak eta direktorioak (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Konfiguratu hizkuntza" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Itzulia: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Sistemak lehenetsia" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Erabili sistema eragilearen hizkuntza." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Babeskopiaren erregistroaren ikuspegia" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Azken erregistroaren ikuspegia" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profila:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Babeskopiak:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Iragazi:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Errorea, [I] Informazioa, [C] Aldaketa" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "dekodetu bide-izenak" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Guztiak" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Aldaketak" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Akatsak" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informazioa" msgstr[1] "Informazioak" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync transferentzia akatsak (esperimentala)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Kudeatu profilak" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Editatu" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Gehitu" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Kendu" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Orokorra" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Sartu" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Kanpoan utzi" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Ezabatu atxikipena" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Aukerak" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "A&ukera aurreratuak" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Leheneratu konfigurazioa" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Profil berria" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Berrizendatu profila" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Seguru zaude \"{name}\" profila ezabatu nahi duzula?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Pausatu babeskopia prozesua" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Baztertu fitxategiak" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Babeskopia direktorioak" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Ezin da karpeta ezabatu" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Erakutsi ezkutuko direktorioak" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Gelditu babeskopia prozesua" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Baztertu direktorioak" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "lehenetsia" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Programaketa" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Eguna:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Asteguna:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Ordua:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Orduak:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "orduaren ondoren" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minutuak:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Exekutatu Back In Time unitatea konektatu bezain pronto (X egunean behin " "bakarrik). Zure sudo pasahitza eskatuko zaizu." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Erabili Back In Time behin eta berriz. Egin bereziki ordenagailua ez badabil" " ongi." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Bakoitza:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Gaitu arazketa-mezuen erregistroa" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Arazketa-mailako mezuak idazten ditu sistemaren erregistroan \"--debug\" " "bidez." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Kontuz: diagnostikoetarako soilik erabili aldi baterako, irteera kopuru " "handia sortzen baitu." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Ezgaituta" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Abiatze/berrabiaratze guztietan" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "minutuero" msgstr[1] "{n} minutuan behin" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Orduro" msgstr[1] "{n} orduro" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Ordu pertsonalizatuak" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Egunero" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Behin eta berriz (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Unitatea konektatzean (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Astero" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Hilero" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Urtero" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Ordu" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Egun(ak)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "aste" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Hilabete" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Ordu pertsonalizazuak komaz banatutako ordu-zerrenda izan daiteke bakarrik " "(adib. 8,12,18,23) edo */3 hiru orduz behin babeskopia egiteko." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "یک فایل کلید خصوصی موجود را انتخاب کنید (معمولاً با نام **\"id_ed25519\"** و" " در تنظیمات قدیمی‌تر **\"id_rsa\"**)." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "ایجاد کلید SSHجدید در {path} ناموفق بود." #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "مسیر کامل پشتیبان:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "کلید خصوصی:" #: qt/manageprofiles/sshkeyselector.py:210 #, fuzzy msgid "Use system SSH configuration" msgstr "وارد کردن پیکربندی" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "پروکسی SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "میزبان(هاست):" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "پورت:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "کاربر:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "اتصال به میزبان هدف از طریق این پروکسی (که به عنوان Jump Host نیز شناخته " "می‌شود). برای جزئیات بیشتر، به گزینه \"-J\" در مستندات دستور ssh یا " "\"ProxyJump\" در صفحه man ssh_config مراجعه کنید." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}اطلاعات{ENDBOLD}: در حالت 'SSH encrypted' فقط ستاره‌های تکی یا دوتایی " "قابل استفاده هستند (مثلاً {example2}). سایر انواع الگوها و کاراکترهای " "جایگزین نادیده گرفته خواهند شد (مثلاً {example1}). در این حالت، به دلیل " "رمزگذاری توسط EncFS، نام پرونده‌ها غیرقابل پیش‌بینی خواهند بود." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "الگوها، پرونده‌ها یا پوشه‌ها را استثنا کن" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "استثنا کردن الگو" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "اضافه کردن فایل" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "اضافه کردن پوشه" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "سوال" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "استثنا کردن پرونده‌های بزرگتر از:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "استثنا کردن پرونده‌ها با اندازه بزرگتر از {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "با غیرفعال بودن «حالت کامل rsync»، این تنظیم تنها بر روی پرونده‌های جدیدی که" " ایجاد میشود تأثیر می‌گذارد، زیرا rsync با آن به عنوان گزینه انتقال در نظر " "می‌گیرد نه یک قاعده برای استثنا. در نتیجه، پرونده‌های بزرگ که قبلا " "پشتیبان‌گیری شده‌اند، حتی اگر تغییر کرده باشند، در پشتیبان‌ها باقی خواهند " "ماند." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "استثنا کردن الگو" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "استثنا کردن الگو" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "استثنا کردن فایل" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "استثنا کردن پوشه" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "غیرفعال شده زیرا این الگو در حالت 'SSH encrypted' قابل استفاده نیست." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "این گزینه‌ها برای تنظیمات پیشرفته هستند. فقط در صورتی آن‌ها را تغییر دهید که" " به طور کامل از تأثیراتشان آگاه باشید." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "'rsunc' را با '{cmd}' اجرا کن:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "به عنوان کار کرون" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "برروی هاست ریموت" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "وقتی درحال پشتیبان‌گیری دستی است" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "برای فعال‌سایزی این گزینه لطفا 'nocache' را نصب کنید." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "برروی ماشین محلی" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "stdout را به /dev/null در کار‌های کرون منتقل کنید." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "اگر یک MTA نصب شده باشد، Cron به‌صورت خودکار ایمیلی حاوی خروجی وظایف " "زمان‌بندی‌شده ارسال خواهد کرد." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "stderr را به /dev/null در کار‌های کرون منتقل کنید." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "اگر یک MTA نصب شده باشد، Cron به‌صورت خودکار ایمیلی حاوی خروجی خطاهای وظایف " "زمان‌بندی‌شده ارسال خواهد کرد." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/ثانیه" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "استفاده rsync از پهنای باند را محدود کن:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "حفظ ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "حفظ ویژگی‌های گسترده (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "محدود کردن به یک پرونده سامانه" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "گزینه‌ها باید بین نویسه‌های نقل‌قول قرار بگیرند مثل {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "پیست گزینه های اضافه به rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "پیشوندی که قبل از اجرای هر دستور در میزبان راه دور اجرا می‌شود." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "متغیرها باید به‌صورت \\$FOO فرار داده شوند. این مقدار بر rsync تأثیر " "نمی‌گذارد، بنابراین برای افزودن یک پیشوند به rsync از \"{example_value}\" " "همراه با {rsync_options_value} استفاده کنید." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "پیشفرض" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "اضافه کردن پیشوند به دستورات SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "بررسی کن اگر هاست ریموت آنلاین هست" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "هشدار: اگر این گزینه غیرفعال باشد و میزبان راه دور در دسترس نباشد، ممکن است " "باعث بروز خطاهای غیرمنتظره شود." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" "بررسی کن که آیا میزبان راه‌دور از تمامی دستورات ضروری پشتیبانی می‌کند یا " "خیر." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "هشدار: اگر این گزینه غیرفعال باشد و میزبان راه دور از تمام دستورات موردنیاز " "پشتیبانی نکند، ممکن است باعث بروز خطاهای غیرمنتظره شود." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(پیشفرض: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "غیرفعال" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "فعال" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "حالت:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "پیشتیبان‌ها کجا ذخیره شوند" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "تنظیمات SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "مسیر:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "نمایه جدید" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "رمز عبور" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "رمز عبور را در دسته کلید ذخیره کنید" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "رمز عبور کش برای کرون (مشکل امنیتی: ریشه می‌تواند رمز عبور را بخواند)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "پیشرفته" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "مسیر کامل پشتیبان:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "کلمه‌عبور مطابقت ندارد." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 #, fuzzy msgid "Proceed with copying the SSH key?" msgstr "با پشتیبان گیری ادامه می دهید؟" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "اصالت میزبان {host} قابل تأیید نیست." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "اثر انگشت کلید {keytype} عبارت است از:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "لطفا این اثر انگشت را تأیید کنید. آیا به پرونده 'known_hosts' اضافه شود؟" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "آیا واقعا میخواهید پوشه پشتیبان‌گیری را تغییر دهید؟" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "کلید خصوصی SSH" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "ایجاد کلید SSHجدید در {path} ناموفق بود." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "پرونده‌ها و پوشه‌ها را شامل کن" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" یک لینک نمادین است. از مقصد پیوند شده تا زمانی که شامل آن نگردد " "پشتیبان‌گیری انجام نخواهد شد." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "آیا در عوض هدف لینک نمادین را شامل آن می‌کنید؟" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "شامل کردن فایل" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "شامل کردن پوشه" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "فعال کردن اعلان‌ها" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "غیرفعال کردن پشتیبان‌گیری‌ها زمان استفاده از باتری" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "وضعیت باتری از طرف سیستم در دسترس نیست" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "اجرای فقط یک پشتیبان‌گیری در زمان" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "سایر پشتیبان‌گیری‌ها تا زمانی که پشتیبان‌گیری فعلی کامل نشده مسدود خواهند " "شد. این یک تنظیم سراسری است، به این معنا که بر تمام نمایه‌های این کاربر " "تأثیر خواهد گذاشت. با این حال، باید برای سایر کاربران نیز فعال شود." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "پشتیبان‌گیری از فایل‌های تغییر مکان یافته در هنگام بازگردانی" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "ادامه در صورت بروز خطا (نگه‌داشتن پشتیبان‌های کامل نشده)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "از سرجمع برای شناسایی تغییرات استفاده کن" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "چه تغییرات صورت گرفته باشد یا نه، یک پشتیبان جدید ایجاد کن." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "سطح لاگ:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "هیچکدام" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "راهنمای کاربر" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "قوانین زیر از بالا به پایین پردازش می‌شوند. قوانین بعدی بر قوانین قبلی " "اولویت دارند. برای جزئیات و نمونه‌ها به {manual} مراجعه کنید." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "باز کردن راهنمای کاربر در مرورگر." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "جدیدترین پشتیبان را نگه دار." #: qt/manageprofiles/tab_remove_retention.py:241 #, fuzzy msgid "The most up-to-date backup is kept under all circumstances." msgstr "آخرین یا جدیدترین پشتیبان تحت هر شرایطی حفظ می‌شود." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "رفتار نمی تواند تغییر کند." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "پشتیبان‌های نام‌گذاری‌شده را نگه دار." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "پشتیبان‌هایی که علاوه بر زمان‌سنجی معمول، نام‌گذاری شده‌اند، تحت هر شرایطی " "حفظ خواهند شد و حذف نخواهند شد." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "سال(ها)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "حذف پشتیبان‌های قدیمی‌تر از" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "روزهای کامل. روز جاری نادیده گرفته می‌شود." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "هفته‌های تقویم با دوشنبه به عنوان اولین روز. هفته جاری نادیده گرفته می‌شود." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "دوره‌های ۱۲ ماهه. ماه جاری نادیده گرفته می‌شود." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "سیاست‌های نگهداری" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "در پس‌زمینه برروی میزبان راه‌دور اجرا کن." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "فرآیند حذف هوشمند مستقیما روی ماشین راه دور اجرا می‌شود، نه به‌صورت محلی. " "دستورات \"bash\"، \"screen\" و \"flock\" باید روی ماشین راه دور نصب و در " "دسترس باشند." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" "اگر این گزینه انتخاب شود، Back In Time ابتدا ماشین راه دور را آزمایش خواهد " "کرد." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "روزها از امروز شمرده می‌شوند." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "تمام پشتیبان‌ها را برای همیشه نگه دار" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "روز‌(ها)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "آخرین پشتیبان هر روز را برای همیشه نگه دار" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "هفته‌ها از هفته جاری که در حال اجرا است شروع می‌شوند. هفته از روز دوشنبه " "آغاز می‌شود." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "آخرین پشتیبان هر هفته را برای همیشه نگه دار" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "هفته(ها)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "ماه‌ها به‌عنوان ماه‌های تقویمی از ماه جاری شمرده می‌شوند." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "آخرین پشتیبان هر ماه را برای همیشه نگه دار" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "ماه(ها)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "سال‌ها به‌عنوان سال‌های تقویمی از سال جاری شمرده می‌شوند." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "آخرین پشتیبان هر سال را نگه دار برای" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "تمام سال ها." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "... فضای آزاد کمتر باشد از" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "... در صورتی که تعداد inode آزاد کمتر باشد از" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "قدیمی‌ترین پشتیبان را حذف کن اگر …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "میانبرها" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "پوشه‌های پشتیبان" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "نمایه: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "نمایه: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "آخرین لاگ را ببین" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "اجرای {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "درحال کار…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "وارد کردن پیکربندی" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "وارد کردن" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "درحال کار…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "پوشه پشتیبان را که پرونده پیکربندی باید از آن وارد شود را انتخاب کنید. مسیر " "ممکن است به شکل زیر باشد: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "اگر دایرکتوری بر روی یک درایو خارجی یا راه دور قرار دارد، باید پیش از آن " "به‌صورت دستی سوار شود." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "نمایش فایل های مخفی" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "پرونده‌ها و پوشه‌ها را شامل کن" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "ایجاد پرونده در این پوشه ناموفق بود:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "لاگ را کامل نشان بده" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "شمارش معکوس برای خاموشی" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "پشتیبان‌گیری به پایان رسید." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "لغو خاموشی" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "خاموشی فوری" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "سامانه پس از {n} ثانیه خاموش خواهد شد." msgstr[1] "سامانه پس از {n} ثانیه دیگر خاموش خواهد شد." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "گزینه‌ها درباره مقایسه پشتیبان‌ها" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "دستور:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "پارامتر ها:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "از ۱٪ و ۲٪ برای پارامترهای مسیر استفاده کن" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "لطفا دستور diff را تنظیم کنید یا روی لغو کلیک کنید." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "دستور \"{cmd}\" در این سامانه یافت نشد. لطفا دستور دیگری امتحان کنید یا روی " "لغو کلیک کنید." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "هیچ پارامتری برای دستور diff تنظیم نشده است. از مقدار پیش‌فرض \"{params}\" " "استفاده می‌شود." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "پشتیبان‌ها" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "فقط پشتیبان‌های متفاوت" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "فقط پشتیبان‌هایی را لیست کن که برابر هستند با:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "بررسی ژرفناک (بیشتر دقیق، ولی کند)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "پاک کردن" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "انتخاب همه" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "مقایسه" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "برو به" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "گزینه‌ها" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "مقایسه یک پشتیبان با خودش ممکن نیست، زیرا یک مقایسه تکراری خواهد بود." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "آیا واقعا می‌خواهید {file_or_dir} را در پشتیبان {backup_id} حذف کنید؟" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "آیا واقعا می‌خواهید {file_or_dir} را در {count} پشتیبان حذف کنید؟" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "هشدار: این عمل قابل بازگشت نیست." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "آیا می‌خواهید {path} را از پشتیبان‌گیری‌های آینده مستثنی کنید؟" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "ریشه" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "امروز" #: qt/timeline.py:77 msgid "Yesterday" msgstr "دیروز" #: qt/timeline.py:87 msgid "This week" msgstr "این هفته" #: qt/timeline.py:95 msgid "Last week" msgstr "آخرین هفته" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "این یک پشتیبان نیست بلکه نمای زنده از پرونده‌های محلی است." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "آخرین بررسی {time}" backintime-1.6.1/common/po/fi.po000066400000000000000000002263411514264426600165130ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Ellen Rönnholm # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-01-31 12:36+0000\n" "Last-Translator: artnay \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Kaikki tässä projektissa käytetyt lisenssit sijaitsevat hakemistossa " "{dir_link}. Katso {readme_link} tiedostokohtaisten lisenssi- ja " "tekijänoikeustietojen purkamiseksi SPDX-metatietoja käyttämällä." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Varoitus" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Pääprofiili" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Paikallinen (EncFS salattu)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS salattu)" #: common/config.py:237 msgid "Local" msgstr "Paikallinen" #: common/config.py:240 msgid "Local encrypted" msgstr "Paikallinen salattu" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Salaus" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Yksityinen SSH-avain" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profiili: ”{name}”" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Varmuuskopioiden hakemisto ei ole kelvollinen." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Vähintään yksi hakemisto on valittava varmuuskopiointia varten." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Hakemisto: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Tätä hakemistoa ei voi sisällyttää varmuuskopioon, koska se on osa itse " "varmuuskopion kohdetta." #: common/config.py:366 #, fuzzy, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Arvon \"Poista vanhin varmuuskopio, jos vapaata tilaa on vähemmän kuin\" " "({val_one}) on oltava pienempi tai yhtä suuri kuin kynnysarvo \"Varoita, jos" " vapaata levytilaa on vähemmän kuin\" ({val_two}):lle." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Säädä asetuksia niin, että varmuuskopioiden poistoraja ei ole korkeampi kuin" " varoitusraja." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udevin ajoittaminen ei toimi tilassa {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Uuden crontabin kirjoittaminen epäonnistui." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron ei ole käynnissä, vaikka crontab-komento on käytettävissä. Ajoitetut " "varmuuskopiointityöt eivät käynnisty. Cron saattaa olla asennettuna, mutta " "ei ole käytössä. Kokeile suorittaa kaksi komentoa \"systemctl enable cron\" " "ja \"systemctl start cron\" tai ota yhteyttä käytössä olevan GNU/Linux-" "jakelun tukikanaviin saadaksesi apua." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Määrityksen tallentaminen epäonnistui" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Määrityksen lataaminen epäonnistui" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profiili ”{name}” on jo olemassa." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Tätä ei voi kumota." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Ei voi liittää '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Salatun hakemiston määritystä ei löytynyt." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Luodaanko uusi salattu hakemisto?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Peru" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Vahvista syöttämällä EncFS-salasana uudelleen." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS-salasanat eivät täsmää." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Ota otos" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Ei voi liittää '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Ei voi irrottaa {mountprocess} kohteesta {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "Komentoa \"{command}\" ei löytynyt. Ole hyvä ja asenna se (esim. " "\"{installcommand}\" kautta)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Liitospiste {mntpoint} ei ole tyhjä." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Syötä salasana {mode} profiilille \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Profiilille {profile_id} ei voitu asentaa udev-sääntöä. DBus-palvelu " "”{dbus_interface}” ei ole käytettävissä." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Kohteelle ”{path}” ei löytynyt UUID:tä" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "EPÄONNISTUI" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Palauta käyttöoikeudet" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Valmis" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Seuraavilla sisällytysluettelon merkinnöillä ei ole vastaavaa tiedostoa tai " "hakemistoa varmuuskopiointilähteessä:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Viivästetään varmuuskopiointia akkukäytön ajan" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Varmuuskopioiden hakemistoa ei löydy." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Jos se on irrotettavalla asemalla, kytke se." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Odotetaan {n} sekunti." msgstr[1] "Odotetaan {n} sekuntia." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Varmuuskopion {snapshot_id} luominen epäonnistui." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Ole kärsivällinen; viimeistellään…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Hakemistoa ei voi luoda." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Tallennetaan määritystiedostoa…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Tallennetaan käyttöoikeuksia…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Löytyi epätäydellinen varmuuskopio {snapshot_id}, jota voidaan jatkaa." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Poistetaan epätäydellinen {snapshot_id}-hakemisto viime suorituskerrasta" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Ei voi poistaa hakemistoa" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Luodaan varmuuskopiota" #: common/snapshots.py:1517 msgid "Success" msgstr "Onnistui" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Osittain siirretty johtuen virheestä" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Osittain siirretty johtuen puuttuvista lähdetiedostoista ( kts. 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' päättyi paluukoodilla {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Katso lisätietoja: 'man rsync'" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negatiiviset rsync-poistumiskoodit ovat signaalinumeroita, katso 'kill -l' " "ja 'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Mikään ei ole muuttunut: uusi varmuuskopio ei ole tarpeen" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Ei voi uudelleennimetä {new_path} {path}:ksi." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Toteuta säännöt poistaaksesi vanhat varmuuskopiot" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "Sovella säilytyskäytäntö" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Yritetään pitää vapaa vähimmäistila" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Yritetään pitää vähintään {perc} inodeja vapaana" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Nyt" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Ei voi liittää {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agentia ei löytynyt. Varmista, että se on asennettu." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Yksityisen SSH-avaimen lukitusta ei voida avata. Salasana on väärin tai ei " "käytettävissä cronia varten." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Etäsijainti on olemassa muttei kansio." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Etäsijaintiin ei voi kirjoittaa." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Etäsijainti ei ole ohjelmatiedosto." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Etäsijaintia ei voitu luoda." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Etäkone {host} ei tue komentoa {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Check-komennot palvelimella {host} antoivat tuntemattoman virheen" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Etäkone {host} ei tue kovia linkkejä" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Kopioi julkinen ssh-avain \"{pubkey}\" palvelimelle \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Ole hyvä ja syötä käyttäjän \"{user}\" salasana." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Kohdetiedostojärjestelmä kohteelle {path} on alustettu NTFS:llä, jolla on " "tunnettuja yhteensopimattomuuksia UNIX-tyylisten tiedostojärjestelmien " "kanssa." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} ei ole kelvollinen hakemisto." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Seuraavan hakemiston luominen epäonnistui:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Kirjoitusoikeutta saatetaan rajoittaa." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Kohdetiedostojärjestelmä kohteelle {path} on alustettu FATilla, joka ei tue " "kiintolinkkejä. Käytä alkuperäistä GNU/Linux-tiedostojärjestelmää." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Kohdetiedostojärjestelmä kohteelle {path} on SMB:n kautta liitetty jako. " "Varmista, että SMB-etäpalvelin tukee symbolisia linkkejä tai aktivoi " "\"{copyLinks}\" kohdassa \"{expertOptions}\"." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopioi linkit (ratkaise symboliset linkit)" #: common/tools.py:487 msgid "Expert Options" msgstr "Asiantuntija-asetukset" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Kohdetiedostojärjestelmä kohteelle {path} on sshfs:n kautta liitetty jako. " "Sshfs ei tue kiinteitä linkkejä. Käytä sen sijaan tilaa \"SSH\"." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Tiedoston luominen epäonnistui tässä hakemistossa:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Tietoja - Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Tekijänoikeus:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Tekijät:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Käännökset:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Ellen Rönnholm" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Käännösten tekijöiden tietoja ei ole saatavilla nykyiselle kielelle." #: qt/aboutdlg.py:116 msgid "this link" msgstr "tätä linkkiä" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "Napsauta {thislink} nähdäksesi kaikkien kielten kääntäjien tiedot." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Projektin verkkosivusto" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Käyttöopas" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Avaa käyttöopas selaimessa (paikallinen jos saatavilla, muuten verkossa)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versio{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} näyttää käynnistettävän ensimmäistä kertaa, koska asetuksia ei " "löytynyt." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Tuodaanko olemassa oleva kokoonpano (varmuuskopion kohdehakemistosta tai " "toisesta tietokoneesta)?" #: qt/app.py:395 msgid "Then press OK." msgstr "Paina sitten OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Luo varmuuskopio" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Käytä muokkausajankohtaa ja kokoa tiedoston muokkauksen havaitsemiseen." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Luo varmuuskopio (tarkistussummatila)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Havaitse muutokset tarkistussummista." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Keskeytä varmuuskopiointi" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Jatka varmuuskopiointia" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Pysäytä varmuuskopiointi" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Päivitä varmuuskopioiden luettelo" #: qt/app.py:524 msgid "Name backup" msgstr "Nimeä varmuuskopio" #: qt/app.py:528 msgid "Remove backup" msgstr "Poista varmuuskopio" #: qt/app.py:532 msgid "Open backup log" msgstr "Näytä varmuuskopioinnin loki" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Näytä valittujen varmuuskopioiden loki." #: qt/app.py:536 msgid "Open last backup log" msgstr "Avaa viimeisin varmuuskopion loki" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Näytä viimeisimmän varmuuskopion loki." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Hallinnoi profiileja…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Muokkaa käyttäjäkutsua" #: qt/app.py:548 msgid "Shutdown" msgstr "Sammuta" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Sammuta järjestelmä varmuuskopioinnin valmistuttua." #: qt/app.py:552 msgid "Setup language…" msgstr "Asennuskieli…" #: qt/app.py:556 msgid "Exit" msgstr "Lopeta" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "'man'-sivu: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Näyttää 'man'-sivun Back In Time (backintime) :stä" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "'man'-sivu: Profiilien konfigurointitiedosto" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Näyttää 'man'-sivun profiilien konfigurointitiedostosta (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Avaa Back In Time -verkkosivusto selaimessa" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Muutosloki" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "Avaa muutosloki (paikallinen jos saatavilla, muuten verkossa)" #: qt/app.py:589 msgid "FAQ" msgstr "UKK" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Avaa Usein kysytyt kysymykset (UKK) selaimessa" #: qt/app.py:593 msgid "Ask a question" msgstr "Esitä kysymys" #: qt/app.py:597 msgid "Report a bug" msgstr "Ilmoita ohjelmavirheestä" #: qt/app.py:600 #, fuzzy msgid "Translation" msgstr "Käännös" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Näytä viesti kääntämiseen osallistumisesta uudelleen." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Encryption Transition (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Näyttää viestin EncFS:n poistosta uudelleen." #: qt/app.py:615 msgid "About" msgstr "Tietoa" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Palauta" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Palauta valitut tiedostot tai hakemistot alkuperäiseen sijaintiin." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Palauta kohteeseen…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Palauta valitut tiedostot tai hakemistot uuteen sijaintiin." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Palauta tällä hetkellä näytettävä hakemisto ja kaikki sen sisältö " "alkuperäiseen sijaintiin." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "Palauta näytettävä hakemisto ja kaikki sen sisältö uuteen sijaintiin." #: qt/app.py:640 msgid "Up" msgstr "Ylös" #: qt/app.py:643 msgid "Show hidden files" msgstr "Näytä piilotiedostot" #: qt/app.py:646 msgid "Compare backups…" msgstr "Vertaa varmuuskopioita…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Julkaisuehdokas" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Näyttää viestin tästä julkaisuehdokkaasta uudelleen." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Varmuuskopio" #: qt/app.py:733 msgid "&Restore" msgstr "&Palauta" #: qt/app.py:739 msgid "&Help" msgstr "&Ohje" #: qt/app.py:790 msgid "Systray Icon" msgstr "Ilmoitusalueen kuvake" #: qt/app.py:796 msgid "Automatic" msgstr "Automaattinen" #: qt/app.py:800 msgid "Light icon" msgstr "Vaalea kuvake" #: qt/app.py:801 msgid "Dark icon" msgstr "Tumma kuvake" #: qt/app.py:824 msgid "Icons only" msgstr "Vain kuvakkeet" #: qt/app.py:827 msgid "Text only" msgstr "Vain teksti" #: qt/app.py:830 msgid "Text below icons" msgstr "Teksti kuvakkeiden alla" #: qt/app.py:833 msgid "Text beside icon" msgstr "Teksti kuvakkeen vieressä" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Tätä hakemistoa ei ole olemassa nykyisessä\n" "valitussa varmuuskopiossa." #: qt/app.py:1005 msgid "Add to Include" msgstr "Lisää mukaan otettaviin" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Lisää pois jätettäviin" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Jos tämä ikkuna suljetaan, Back In Time ei voi sammuttaa järjestelmää " "varmuuskopioinnin valmistuttua." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Suljetaanko ikkuna silti?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Valmis, varmuuskopiota ei tarvittu" #: qt/app.py:1285 msgid "Working:" msgstr "Käsitellään:" #: qt/app.py:1292 msgid "Working" msgstr "Käsitellään" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Virhe" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Lähetetty:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Nopeus:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Arvioitu saapumisaika (ETA):" #: qt/app.py:1490 msgid "Backup:" msgstr "Varmuuskopio:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Palauta {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Palauta {path} kohteeseen…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hei,\n" "Olet käyttänyt Back In Time -sovellusta kielellä: {language} jo jonkin aikaa.\n" "Ohjelmaversiosi käännös kielelle {language} on {perc} valmis. Riippumatta teknisestä osaamisestasi voit osallistua käännöksen ja sitä kautta myös Back In Time -ohjelman kehitykseen itsekin.\n" "Siirry osoitteeseen {translation_platform_url} jos haluat osallistua. Lisätietoja saat myös osoitteesta: {back_in_time_project_website}.\n" "Pyydämme anteeksi keskeytystä eikä tätä ilmoitusta näytetä uudestaan. Tämä viesti on saatavilla koska tahansa help -menun kautta.\n" "Sinun Back In Time Team" #: qt/app.py:1709 #, fuzzy msgid "translation platform" msgstr "Käännökset" #: qt/app.py:1714 msgid "Website" msgstr "Sivusto" #: qt/app.py:1728 #, fuzzy msgid "Your translation" msgstr "Käännökset" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Fediversumissa Mastodonissa: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Sähköposti {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Postituslista {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} projektin verkkosivustolla." #: qt/app.py:1781 msgid "Open an issue" msgstr "Avaa vikalippu" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Vaihtoehtoisesti voit käyttää toista valitsemaasi kanavaa." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Tämä Back In Time -versio on Julkaisuehdokas, ja se on tarkoitettu ensisijaisesti vakauden testaamiseen seuraavaa virallista julkaisua varten.\n" "Käyttäjätietoja tai telemetriaa ei kerätä. Back In Time -joukkue on kuitenkin hyvin kiinnostunut tietämään, käytetäänkö Julkaisuehdokasta ja kannattaako tällaisten julkaisua edeltävien versioiden tarjoamista jatkaa.\n" "Siksi joukkue pyytää ystävällisesti lyhyttä palautetta siitä, oletko testannut tätä versiota, vaikka et olisi kohdannut mitään ongelmia. Jopa muutaman minuutin mittainen nopea testiajo auttaisi meitä paljon.\n" "Käytettävissä ovat seuraavat yhteydenottovaihtoehdot:\n" "{contact_list}\n" "Tässä versiossa tätä viestiä ei enää näytetä, mutta se on käytettävissä milloin tahansa ohjevalikon kautta.\n" "Kiitos tuestasi ja siitä, että autat meitä parantamaan Back In Timea!\n" "Back In Time -joukkueesi" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Kohteessa on käytettävissä vain {free} vapaata tilaa, joka on alle " "määritetyn kynnysarvon {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Jatketaanko varmuuskopiointia?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Kaikki uudemmat tiedostot polussa {path} poistetaan. Jatketaanko?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Kaikki uudemmat tiedostot alkuperäisessä hakemistossa poistetaan. " "Jatketaanko?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Varoitus{BOLDEND}: Tiedostojen poistaminen tiedostojärjestelmän " "juuressa voi rikkoa koko järjestelmän." #: qt/app.py:2167 msgid "Backup name" msgstr "Varmuuskopion nimi" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Poistetaanko tämä varmuuskopio?" msgstr[1] "Poistetaanko nämä varmuuskopiot?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "Kielivalinta astuu voimaan uudelleenkäynnistyksen jälkeen." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Versioidut varmuuskopiot (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Versioidut varmuuskopiot" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Kysymys" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Luo varmuuskopiot, joiden lopussa on {suffix} ennen paikallisten elementtien" " korvaamista tai poistamista." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Ennen palauttamista tiedostojen uudemmat versiot nimetään uudelleen ja " "niihin lisätään {suffix}. Nämä tiedostot voidaan poistaa seuraavalla " "komennolla:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Palauta vain elementtejä, joita ei ole olemassa tai jotka ovat uudempia kuin" " kohteessa olevat. Käytetään vaihtoehtoa \"{rsync_example}\"." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Poista uudemmat elementit alkuperäisestä hakemistosta." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Palauta valitut tiedostot tai hakemistot alkuperäiseen sijaintiinsa ja " "poista tiedostot tai hakemistot, joita ei ole varmuuskopiossa. Ole erittäin " "varovainen, koska tämä poistaa tiedostot ja hakemistot, jotka poistettiin " "varmuuskopion luomisen aikana." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Haluatko todella palauttaa tämän elementin uuteen hakemistoon?" msgstr[1] "Haluatko todella palauttaa nämä elementit uuteen hakemistoon?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Haluatko varmasti palauttaa tämän elementin?" msgstr[1] "Haluatko varmasti palauttaa nämä elementit?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Käyttäjän takaisinkutsu: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "user-callback-skriptin ensimmäisellä rivillä on oltava shebang (esim. " "{example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Näytä/piilota piilotetut tiedostot ja hakemistot (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Asennuskieli" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Käännetty: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Järjestelmän oletus" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Käytä käyttöjärjestelmän kieltä." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Varmuuskopiolokin näkymä" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Viimeisin lokinäkymä" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profiili:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Varmuuskopiot:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Suodatin:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Virhe, [I] Tietoa, [C] Muutokset" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "dekoodaa polut" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Kaikki" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Muutokset" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Virheet" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Tieto" msgstr[1] "Tiedot" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync-siirtoviat (kokeellinen)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Hallinnoi profiileja" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Muokkaa" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Lisää" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Poista" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Yleisasetukset" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Ota mukaan" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Jätä pois" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Poista & säilyttäminen" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Valinnat" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "A&siantuntija-asetukset" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Palauta määritys" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Uusi profiili" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Muuta profiilin nimeä" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Haluatko poistaa profiilin \"{name}\"?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Kopioi symboliset linkit tiedostoina" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Tämä valinta saattaa kasvattaa varmuuskopion kokoa." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Pois käytöstä oletusarvoisesti." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacs-varmuuskopiotiedostot" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs-automaattitallennuksen tiedostot" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Officen väliaikaistiedostot" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOfficen ja muiden OpenDocument-muokkainten lukkotiedostot" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discord-sovelluksen lukkotiedosto" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord-istunnon lukkotiedosto" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Mozilla Firefoxin ja Thunderbirdin lukkotiedosto" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Varmuuskopiohakemistot" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Ei voi poistaa hakemistoa" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Näytä piilotetut hakemistot" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Sekalaiset" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Pysäytä varmuuskopiointi" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Jätä pois hakemistot" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Oletusasetukset" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Aikataulu" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Päivä:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Viikonpäivä:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Aika:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Tunnit:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "tunnin jälkeen" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minuutit:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Suorita Back in time heti, kun asema on kytketty (vain kerran X päivässä). " "sudo-salasanan kehote tulee näkyviin." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Suorita BackInTime toistuvasti. Tästä on apua, ellei kone ole aina " "käynnissä." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Joka:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Ota viankorjausviestien lokiin kirjaaminen käyttöön" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Kirjoittaa viankorjaustason viestejä järjestelmälokiin komennon '--debug' " "myötä." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Huomio: Käytä tätä vain väliaikaisesti diagnostiikkaan, koska se tuottaa " "suuren määrän ulostuloa." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Ei käytössä" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Käynnistysten yhteydessä" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Minuutin välein" msgstr[1] "{n} minuutin välein" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Tunnin välein" msgstr[1] "Joka {n} tunti" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Mukautetut tunnit" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Päivittäin" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Toistuva (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Asemaa kytkettäessä (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Viikoittain" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Kuukausittain" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Joka vuosi" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Tunti/Tunnit" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Päivä(ä)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Viikko(a)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Kuukausi/Kuukaudet" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Mukautettujen tuntien on oltava pilkuin erotettu tuntiluettelo (esim. " "8,12,18,23) tai */3 varmuuskopioille kolmen tunnin välein." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "" #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "" #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "SSH privatur lykil:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Vertur:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Brúkari:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Legg fílu til" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Legg skjáttu til" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "" #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Tak fílu við" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Tak skjáttur við" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "" #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Hvar skullu støðumyndirnar goymast" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Nýtt umhvarv" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Framkomið" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Loyniorðið er ikki líka." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "" #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Gera eina nýggja bronglaða mappu?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "SSH privatur lykil" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "" #: qt/manageprofiles/tab_include.py:48 #, fuzzy msgid "Include files and directories" msgstr "Tak skjáttur við" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Tak fílu við" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Tak skjáttur við" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Virkja kunningar" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Útseta trygaravrit ímeðan streymur ikki er tilsettur" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Einki" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Tak støðumynd burtur." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Tak støðumynd burtur." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Ár" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Tak støðumynd burtur" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "Dag(ar)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "Vika(ur)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:389 #, fuzzy msgid "… the free space is less than" msgstr "Um tað tøka plássið er minni enn:" #: qt/manageprofiles/tab_remove_retention.py:394 #, fuzzy msgid "… the free inodes are less than" msgstr "Um tað tøka plássið er minni enn:" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Tak gamlar støðumyndir burtir" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Snarvegir" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 #, fuzzy msgid "Backup directories" msgstr "Trygdarritingar-skjáttur" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Umhvarv: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Umhvarv: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Arbeiði…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Arbeiði…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Vís fjaldar fílur" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Tak skjáttur við" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "" #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "" #: qt/snapshotsdialog.py:70 #, fuzzy msgid "Command:" msgstr "Stýriboð" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "" #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Útseta trygaravrit ímeðan streymur ikki er tilsettur" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Far til" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Kostir" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "" #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Rót" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Í dag" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Í gjár" #: qt/timeline.py:87 msgid "This week" msgstr "Henda vikan" #: qt/timeline.py:95 msgid "Last week" msgstr "Fyrra vikan" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "" backintime-1.6.1/common/po/fr.po000066400000000000000000002413721514264426600165250ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © bubu of Debian-l10n-fr # SPDX-FileCopyrightText: © Michel Corps (@jej) # SPDX-FileCopyrightText: © milimarg # SPDX-FileCopyrightText: © Loufute # SPDX-FileCopyrightText: © Iann # SPDX-FileCopyrightText: © Over_score # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-06 12:48+0000\n" "Last-Translator: Loufute \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Les licences utilisées dans ce projet sont stockées dans le répertoire " "{dir_link}. Pour extraire chaque fichier de licence et les informations de " "copyright en utilisant les métadonnées SPDX, consulter le {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Avertissement" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Profil principal" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Local (chiffré avec EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (chiffré avec EncFS)" #: common/config.py:237 msgid "Local" msgstr "Local" #: common/config.py:240 msgid "Local encrypted" msgstr "Chiffré localement" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Chiffrement" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Clé privée SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil : \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Le répertoire des sauvegardes n'est pas valide." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Au moins un répertoire doit être sélectionné pour la sauvegarde." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Répertoire : {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Ce répertoire ne peut pas être inclus dans la sauvegarde, car il fait partie" " de la destination de la sauvegarde." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "La valeur pour \"Supprimer la plus ancienne sauvegarde si l'espace libre est" " inférieur à\" ({val_one}) doit être inférieure ou égale au seuil de " "\"Avertir si l'espace libre du disque est inférieur à\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Veuillez ajuster les paramètres pour que la limite de suppression des " "sauvegardes ne soit pas supérieure à limite d'alerte." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "La planification Udev ne fonctionne pas avec le mode {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Échec d'écriture de la nouvelle crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron n'est pas lancé, alors que la commande crontab est pourtant disponible." " Les sauvegardes planifiées ne seront pas exécutées. Il se pourrait que Cron" " soit installé mais pas activé. Essayez les commandes \"systemctl enable " "cron\" et \"systemctl start cron\", ou contactez le support de votre " "distribution GNU/Linux pour obtenir de l'aide." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Échec de l'enregistrement de la configuration" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Échec du chargement de la configuration" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Le profil \"{name}\" existe déjà." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Le dernier profil ne peut pas être supprimé." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Impossible de monter '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "La configuration du répertoire chiffré est introuvable." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Créer un nouveau répertoire chiffré ?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Annuler" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Veuillez entrer à nouveau le mot de passe EncFS pour confirmation." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Les mots de passe EncFS ne correspondent pas." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Prendre un instantané" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Impossible de monter le répertoire chiffré \"{command}\"" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Impossible de démonter {mountprocess} depuis {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} non trouvé. Veuillez l'installer (par exemple avec " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Le point de montage {mntpoint} n'est pas vide." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Entrez le mot de passe pour le profil {mode} \"{profile}\" :" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Échec d'installation de la règle Udev pour le profil {profile_id}. Le " "service DBus '{dbus_interface}' n'était pas disponible." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Impossible de trouver l'UUID pour {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "ÉCHEC" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Restaurer les permissions" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Terminé" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Les entrées suivantes de la liste d'inclusion ne correspondent à aucun " "fichier ou répertoire dans la source de sauvegarde :" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Différer la sauvegarde lors du fonctionnement sur batterie" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Répertoire de sauvegarde non trouvé." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "S'il se trouve sur un disque externe, veuillez le connecter." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Attendre {n} seconde." msgstr[1] "Attendre {n} secondes." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Échec de création de la sauvegarde {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Veuillez patienter. Finalisation…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Échec de création du répertoire." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Enregistrement du fichier de configuration…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Enregistrement des permissions…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "La sauvegarde {snapshot_id} est incomplète et peut être poursuivie." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Suppression du répertoire incomplet {snapshot_id} de la dernière exécution" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Échec de suppression du répertoire" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Création de la sauvegarde" #: common/snapshots.py:1517 msgid "Success" msgstr "Succès" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Transfert partiel en raison d'une erreur" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transfert partiel dû à la disparition de fichiers sources (voir 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' s'est terminé avec le code d'état {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Voir 'man rsync' pour plus de détails" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Les codes d'état négatifs de rsync sont des numéros de signal, voir 'kill " "-l' et 'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Pas de changement, nouvelle sauvegarde non nécessaire" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Échec de renommage de {new_path} en {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Appliquer les règles pour supprimer les anciennes sauvegardes" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Appliquer la stratégie de conservation" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Tentative de garder un minimum d'espace libre" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Tentative de garder un minimum de {perc} inodes libres" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Maintenant" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Impossible de monter {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent introuvable. Assurez-vous qu'il soit installé." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Impossible de déverrouiller la clé privée SSH. Mot de passe incorrect ou non" " disponible pour cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Le chemin d'accès distant existe, mais n'est pas un répertoire." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Le chemin d'accès distant n'est pas accessible en écriture." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Le chemin d'accès distant n'est pas exécutable." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Impossible de créer le chemin distant." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "L'hôte distant {host} n'accepte pas {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "La vérification des commandes sur l'hôte {host} a renvoyé une erreur " "inconnue" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "L'hôte distant {host} ne prend pas en charge les liens physiques" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Copie de la clé SSH publique \"{pubkey}\" sur l'hôte distant \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Veuillez entrer le mot de passe pour \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Le système de fichiers de destination pour {path} est au format NTFS, qui a " "des incompatibilités avec les systèmes de fichiers de style Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "Le chemin {path} n'est pas un répertoire valable." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Échec de création du répertoire suivant :" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "L'accès en écriture peut être restreint." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Le système de fichiers de destination pour {path} est au format FAT, qui ne " "prend pas en charge les liens physiques. Veuillez utiliser un système de " "fichiers GNU/Linux natif." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Le système de fichiers de destination pour {path} est un partage SMB. " "Assurez-vous que le serveur SMB distant autorise les liens symboliques ou " "activez \"{copyLinks}\" dans \"{expertOptions}\"." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Copier les liens (suivre les liens symboliques)" #: common/tools.py:487 msgid "Expert Options" msgstr "Options pour expert" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Le système de fichiers de destination pour {path} est un partage sshfs, qui " "ne prend pas en charge les liens physiques. Veuillez utiliser le mode 'SSH' " "à la place." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Échec de création du fichier dans le répertoire suivant :" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "À propos de Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Copyright :" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Auteurs :" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Traductions :" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "bubu of Debian-l10n-fr\n" "Michel Corps (@jej)\n" "milimarg \n" "Loufute\n" "Iann\n" "Over_score" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Attribution des traductions non disponible dans la langue utilisée." #: qt/aboutdlg.py:116 msgid "this link" msgstr "ce lien" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Suivez {thislink} pour consulter les contributions de traduction pour toutes" " les langues." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Site web du projet" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Manuel d'utilisation" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Ouvrir le manuel d'utilisation dans le navigateur (en local si disponible, " "sinon en ligne)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Version{BOLDEND} : {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} semble s'exécuter pour la première fois, aucune configuration " "n'ayant été trouvée." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Importer une configuration existante à partir d'un emplacement de sauvegarde" " ou d'un autre ordinateur ?" #: qt/app.py:395 msgid "Then press OK." msgstr "Appuyez ensuite sur OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Créer une sauvegarde" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Utiliser la date de modification et la taille pour détecter les changements " "des fichiers." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Créer une sauvegarde (mode somme de contrôle)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "" "Utiliser les sommes de contrôle pour détecter les changements des fichiers." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Mettre la sauvegarde en pause" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Reprendre la sauvegarde" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Arrêter la sauvegarde" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Actualiser la liste des sauvegardes" #: qt/app.py:524 msgid "Name backup" msgstr "Nommer la sauvegarde" #: qt/app.py:528 msgid "Remove backup" msgstr "Supprimer la sauvegarde" #: qt/app.py:532 msgid "Open backup log" msgstr "Afficher le journal des sauvegardes" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Voir le journal de la sauvegarde sélectionnée." #: qt/app.py:536 msgid "Open last backup log" msgstr "Ouvrir le journal de la dernière sauvegarde" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Voir le journal de la dernière sauvegarde." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Gérer les profils…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Éditer le script de rappel utilisateur (user-callback)" #: qt/app.py:548 msgid "Shutdown" msgstr "Arrêt" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Éteindre le système après la fin de la sauvegarde." #: qt/app.py:552 msgid "Setup language…" msgstr "Configurer la langue…" #: qt/app.py:556 msgid "Exit" msgstr "Quitter" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "manuel : Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Afficher le manuel de Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "manuel : fichier de configuration des profils" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Afficher le manuel du fichier de configuration des profils (backintime-" "config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Ouvrir le site de Back In Time dans le navigateur" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Notes de version" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Ouvrir le journal des modifications (localement si disponible, sinon en " "ligne)" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Ouvrir la Foire Aux Questions (FAQ) dans le navigateur" #: qt/app.py:593 msgid "Ask a question" msgstr "Poser une question" #: qt/app.py:597 msgid "Report a bug" msgstr "Signaler un bogue" #: qt/app.py:600 msgid "Translation" msgstr "Traduction" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "" "Affiche à nouveau le message au sujet de la participation à la traduction." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Transition de chiffrement (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Affiche à nouveau le message au sujet de la suppression d'EncFS." #: qt/app.py:615 msgid "About" msgstr "À propos" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Restaurer" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "" "Restaurer les fichiers ou répertoires sélectionnés à leur emplacement " "d'origine." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Restaurer vers …" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "" "Restaurer les fichiers ou répertoires sélectionnés vers un nouvel " "emplacement." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Restaurer le répertoire actuellement affiché et tout son contenu à " "l'emplacement d'origine." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Restaurer le répertoire actuellement affiché et tout son contenu vers un " "nouvel emplacement." #: qt/app.py:640 msgid "Up" msgstr "Dossier parent" #: qt/app.py:643 msgid "Show hidden files" msgstr "Afficher les fichiers cachés" #: qt/app.py:646 msgid "Compare backups…" msgstr "Comparer des sauvegardes…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Version candidate" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Affiche à nouveau le message de cette version candidate." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Sauvegarde" #: qt/app.py:733 msgid "&Restore" msgstr "&Restaurer" #: qt/app.py:739 msgid "&Help" msgstr "&Aide" #: qt/app.py:790 msgid "Systray Icon" msgstr "Icône de la zone de notification (system tray)" #: qt/app.py:796 msgid "Automatic" msgstr "Automatique" #: qt/app.py:800 msgid "Light icon" msgstr "Icône claire" #: qt/app.py:801 msgid "Dark icon" msgstr "Icône sombre" #: qt/app.py:824 msgid "Icons only" msgstr "Icônes uniquement" #: qt/app.py:827 msgid "Text only" msgstr "Texte uniquement" #: qt/app.py:830 msgid "Text below icons" msgstr "Texte sous les icônes" #: qt/app.py:833 msgid "Text beside icon" msgstr "Texte à côté des icônes" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Ce répertoire n'existe pas\n" "dans la sauvegarde sélectionnée." #: qt/app.py:1005 msgid "Add to Include" msgstr "Ajouter aux inclusions" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Ajouter aux exclusions" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Si vous fermez cette fenêtre, Back In Time ne sera pas en mesure d'arrêter " "votre système lorsque la sauvegarde sera terminée." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Fermer quand même la fenêtre ?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Terminé, il n'y a rien à sauvegarder" #: qt/app.py:1285 msgid "Working:" msgstr "En cours :" #: qt/app.py:1292 msgid "Working" msgstr "En cours" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Erreur" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Envoyé :" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Vitesse :" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA :" #: qt/app.py:1490 msgid "Backup:" msgstr "Sauvegarde :" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Restaurer {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Restaurer {path} vers…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Bonjour\n" "Vous avez utilisé Back In Time en {language} un certain nombre de fois.\n" "La traduction en {language} de la version de Back In Time que vous avez installée est désormais {perc} terminée. Quel que soit votre niveau de connaissances techniques, vous pouvez contribuer à la traduction et donc à Back In Time même.\n" "Veuillez visiter {translation_platform_url} si vous souhaitez y participer. Pour de plus amples informations et pour toute question, veuillez visiter {back_in_time_project_website}.\n" "Nous nous excusons pour l'interruption, ce message n'apparaîtra plus. Ce dialogue est accessible à tout moment via le menu Aide.\n" "L'équipe Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "plateforme de traduction" #: qt/app.py:1714 msgid "Website" msgstr "Site Web" #: qt/app.py:1728 msgid "Your translation" msgstr "Votre traduction" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Dans le Fediverse chez Mastodon : {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Courriel à {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Liste de diffusion {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} sur le site web du projet." #: qt/app.py:1781 msgid "Open an issue" msgstr "Créer un ticket" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Ou aussi, par tout moyen à votre convenance." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Cette version de Back In Time est une version candidate, dont l'objectif principal est d'en vérifier la stabilité, en vue de la prochaine version officielle.\n" "Il n'y a pas de collecte des données d'utilisation ni de télémétrie. Cependant, l'équipe de Back In Time aimerait beaucoup savoir si cette version candidate est utilisée, et s'il y a un intérêt à poursuivre la diffusion de telles versions candidates.\n" "L'équipe vous demande donc un retour rapide de votre part, pour savoir si vous avez testé cette version, et ce même si vous n'avez pas identifié de problème. Même un retour sur un rapide essai de quelques minutes serait d'une aide importante.\n" "Vous pouvez faire un retour de plusieurs manières :\n" "{contact_list}\n" "Ce message n'apparaîtra plus, mais peut être affiché à tout moment via le menu d'aide.\n" "Merci pour votre soutien et pour l'aide apportée à l'amélioration de Back In Time !\n" "Votre équipe Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Il y a seulement {free} d'espace libre disponible pour la destination, ce " "qui est plus bas que le seuil configuré {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Procéder à la sauvegarde ?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" "Tous les fichiers plus récents situés dans {path} seront supprimés. " "Continuer ?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Tous les fichiers plus récents situés dans le répertoire d'origine seront " "supprimés. Continuer ?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Avertissement{BOLDEND} : Supprimer des fichiers à la racine du système" " de fichiers pourrait endommager l'ensemble de votre système." #: qt/app.py:2167 msgid "Backup name" msgstr "Nom de la sauvegarde" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Supprimer cette sauvegarde ?" msgstr[1] "Supprimer ces sauvegardes ?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Le changement de langue ne prend effet qu'après le redémarrage de Back In " "Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Sauvegardes versionnées (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Interface facile pour sauvegardes versionnées prenant moins d'espace (mode " "root)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Sauvegardes versionnées" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "Interface facile pour sauvegardes versionnées prenant moins d'espace" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Question" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Créer des copies de sauvegarde avec le suffixe '{suffix}' avant d'écraser ou" " de supprimer des éléments locaux." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Les versions les plus récentes des fichiers seront renommées avec le suffixe" " '{suffix}' avant la restauration. Si vous n'en avez plus besoin, vous " "pouvez les supprimer avec la commande suivante :" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Restaurer seulement les fichiers qui n'existent pas ou qui sont plus récents" " que ceux de la destination. Utilise l'option \"{rsync_example}\"." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Supprimer du répertoire d'origine les éléments plus récents." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Restaurer les fichiers et répertoires sélectionnés vers leur emplacement " "d'origine et supprimer les fichiers et répertoires qui ne font pas partie de" " la sauvegarde. Prudence extrême requise : cette option va supprimer les " "fichiers et répertoires qui n'étaient pas inclus dans la sauvegarde." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Voulez-vous vraiment restaurer cet élément dans le nouveau répertoire ?" msgstr[1] "" "Voulez-vous vraiment restaurer ces éléments dans le nouveau répertoire ?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Voulez-vous vraiment restaurer cet élément ?" msgstr[1] "Voulez-vous vraiment restaurer ces éléments ?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Rappel-utilisateur : \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Le script de rappel utilisateur (user-callback) doit contenir un shebang sur" " la première ligne (e.g. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Afficher/masquer les fichiers et répertoires cachés (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Configurer la langue" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Traduit à : {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Langue du système" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Utiliser la langue du système." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Voir le dernier journal de sauvegarde" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Voir le dernier journal" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil :" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Sauvegardes :" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtre :" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Erreur, [I] Information, [C] Modification" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "décoder les chemins" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Tous" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Modifications" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Erreurs" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Information" msgstr[1] "Informations" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "Échecs de transfert rsync (expérimental)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Gérer les profils" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Modifier" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Ajouter" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Retirer" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Général" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Inclure" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Exclure" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Suppression et Conservation" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Options" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "O&ptions avancées" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Restaurer la configuration" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Nouveau profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Renommer le profil" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Êtes-vous sûr(e) de vouloir supprimer le profil \"{name}\" ?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Copie les fichiers pointés par les liens symboliques" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Copie les liens symboliques en tant que fichiers ou répertoires réels dans " "la sauvegarde. Sélectionnez si tous les liens ou seulement ceux pointant " "hors du répertoire source doivent être copiés." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Cette option peut augmenter la taille de la sauvegarde." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Désactivé par défaut." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Tous les liens symboliques sont remplacés par les fichiers ou répertoires " "réels vers lesquels ils pointent. Cela augmente la taille de la sauvegarde " "et peut entraîner le fait qu'un fichier soit sauvegardé en plusieurs " "exemplaires." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Utilise 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Uniquement les liens externes" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Seuls les liens symboliques pointant hors du répertoire source sont " "sauvegardés en tant que fichiers. Cela augmente la taille de la sauvegarde " "et peut entraîner le fait qu'un fichier soit sauvegardé en plusieurs " "exemplaires." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Utilise 'rsync --copy-unsafe-links'." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Fichiers temporaires d'éditeurs et d'Office" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Fichiers de sauvegarde Emacs" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Fichiers de sauvegarde automatique Emacs" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Fichiers d'échange (swap) Vim" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Fichiers temporaires Microsoft Office" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" "Fichiers de verrouillage LibreOffice et d'autres éditeurs OpenDocument" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniatures et images temporaires" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "Cache des miniatures sous GNU/Linux et les autres systèmes d'exploitation " "(OS) de type Unix" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Base de données des miniatures sous Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Répertoire de métadonnées sur macOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Verrous spécifiques aux applications" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Fichier de verrouillage de l'application Discord" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Fichier de verrouillage de session Discord" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Fichier de verrouillage Mozilla Firefox et Thunderbird" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Caches et répertoires temporaires" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Cache de l'application du compte utilisateur" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Répertoire temporaire du système" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" "Cache des paquets pour les distributions GNU/Linux (basées sur) Debian" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Dépôt des applications et d'exécution (runtime) Flatpak" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Répertoires d'exécution du système (runtime)" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Informations noyau et de processus" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" "Informations sur l'appareil et les autres périphériques (interface sysfs)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Nœuds de périphériques" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Fichiers système d'exécution (runtime)" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Autres éléments non persistants" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Liste des systèmes de fichiers actuellement montés" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Fichier d'échange système (mémoire virtuelle)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Point de montage du système de fichiers virtuel GNOME" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Objets récupérés du système de fichiers" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Divers" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Répertoire de métadonnées sous Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Corbeille du compte utilisateur" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Fichiers de sauvegarde système" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Suggestion d’exclusions" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Choisir les éléments fréquemment utilisés à ajouter aux exclusions de " "sauvegarde." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Par défaut" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Remettre la sélection prédéfinie" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Planification" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Jour :" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Jour de la semaine :" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Heure :" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Heures :" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "de chaque heure" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minutes :" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Exécuter Back In Time dès que le lecteur est connecté (seulement une fois " "tous les X jours). Une invitation à saisir votre mot de passe super-" "utilisateur apparaîtra." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Exécuter Back In Time à plusieurs reprises. Ce réglage est utile si " "l'ordinateur n'est pas allumé régulièrement." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Tous les :" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Activer l'enregistrement des messages de débogage" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Écrit des messages de niveau débogage dans le journal du système via \"--" "debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Attention : n'utilisez cette fonction que temporairement pour des " "diagnostics, car elle génère une grande quantité de données." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Désactivée" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "À chaque démarrage/re-démarrage" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Chaque minute" msgstr[1] "Toutes les {n} minutes" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Chaque heure" msgstr[1] "Toutes les {n} heures" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Horaires personnalisées" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Tous les jours" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "À plusieurs reprises (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Quand le disque est connecté (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Chaque semaine" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Chaque mois" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Chaque année" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Heure(s)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Jour(s)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Semaine(s)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mois" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Les heures personnalisées doivent être séparées par une virgule (ex : " "8,12,18,23) ou */3 pour les sauvegardes périodiques toutes les 3 heures." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Escolla un ficheiro de chave privada existente noutro lugar." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Crear unha nova chave SSH sen contrasinal." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Ruta completa: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Chave privada:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Usar a configuración SSH do sistema" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Deixe o ficheiro de chaves sen escoller. As conexións SSH dependerán da " "configuración do cliente existente no sistema (p. ex., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proxy SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Servidor:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Porto:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Usuario:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Conéctese ao servidor de destino a través deste proxy (tamén coñecido como " "servidor de salto). Consulte «-J» na documentación da orde «ssh» ou " "«ProxyJump» na páxina de man «ssh_config» para obter máis detalles." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Información{ENDBOLD}: no modo «Cifrado SSH», só funcionan os " "asteriscos simples ou dobres (p. ex., {example2}). Ignoraranse outros tipos " "de comodíns e patróns (p. ex., {example1}). Os nomes de ficheiros son " "imprevisíbeis neste modo por mor do cifrado de EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Excluír os patróns, ficheiros ou directorios" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Engadir o patrón" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Engadir ficheiros" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Engadir directorios" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Suxestións" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Seleccione entre os elementos de uso común para engadilos á lista de " "exclusión." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Excluír ficheiros maiores de:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Excluír os ficheiros máis grandes que o valor en {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Co «Modo rsync completo» desactivado, esta opción só afecta aos ficheiros " "creados recentemente, xa que rsync trátao como unha opción de transferencia " "no canto dunha regra de exclusión. En consecuencia, os ficheiros grandes dos" " que xa se fixeron copias de seguranza permanecerán nas copias de seguranza " "aínda que sexan modificadas." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Excluír o patrón" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Introduza un patrón de exclusión:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" "Para obter axuda, consulte a sección da páxina de «man» de rsync {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Abrir a páxina do «man» de rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Excluír ficheiros" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Excluír directorios" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Foi desactivado porque este patrón non funciona no modo «SSH cifrado»." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Estas opcións son para configuracións avanzadas. Modifíqueas só se é " "plenamente consciente das implicacións." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Executar «rsync» con «{cmd}»:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "como un traballo de cron" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "nun servidor remoto" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "ao facer unha copia de seguranza manual" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Instale «nocache» para activar esta opción." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "na máquina local" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Redirixir stdout a /dev/null en cronjobs." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron enviará automaticamente un correo coa saída adxunta de cronjobs se hai " "un MTA instalado." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Redirixir stderr a /dev/null en cronjobs." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron enviará automaticamente un correo con erros de cronjobs adxuntos se hai" " un MTA instalado." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Limitar o uso do largo de banda de rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Preservar ACL (listas de control de acceso)" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Preservar os atributos estendidos (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Restrinxir a un sistema de ficheiros" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "As opcións deben levar comiñas p.e. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Pegar as opcións adicionais a rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefixo a executar antes de cada orde no servidor remoto." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "As variábeis deben escaparse con \\$FOO. Isto non afecta a rsync. Polo " "tanto, para engadir un prefixo para rsync, use «{example_value}» con " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "predeterminado" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Engadir prefixo ás ordes de SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Comprobar se o servidor remoto está en liña" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Advertencia: se está desactivado e o servidor remoto non estiver dispoñíbel," " poderíanse producir erros estraños." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Comprobar se o servidor remoto acepta todas as ordes necesarias." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Advertencia: se está desactivado e o servidor remoto non admite as ordes " "necesarias, poderíanse producir erros estraños." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(predeterminado: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "desactivado" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "activado" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modo:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Onde gardar as copias de seguranza" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Axustes SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Ruta:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Ficheiro de chaves:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Contrasinal" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Gardar o contrasinal no chaveiro" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Gardar o contrasinal de Cron na memoria tobo (problema de seguranza: root " "pode ler o contrasinal)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avanzado" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Ruta completa á copia de seguranza:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "A programación está desactivada por mor de que non se atopou ningunha " "instalación de cron. Instale cron para activar as copias de seguranza " "programadas." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "A ruta de destino da copia de seguranza non pode estar baleira." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "O contrasinal de cifrado non pode estar baleiro." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Produciuse un erro ao intentar acceder no servidor remoto. Devolveuse a " "seguinte mensaxe de erro:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Para activar o acceso sen contrasinal, a chave SSH pública pode ser copiada " "no servidor remoto." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Quere continuar coa copia da chave SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Non foi posíbel copiar a chave SSH pública. Isto pode deberse a un incidente" " de conexión ou permisos." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Non é posíbel estabelecer a autenticidade do servidor {host}." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "A pegada dixital da chave {keytype} é:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Verifique esta pegada dixital! Quere engadila ao ficheiro «known_hosts»?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Confirma que quere cambiar o directorio de copia de seguranza?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "O destino da copia de seguranza seleccionado non está baleiro." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Debe estar baleiro para usar o cifrado." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Ficheiro incorrecto: Non é unha chave SSH privada" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "O ficheiro seleccionado ({path}) é unha chave SSH pública. Escolla en " "troques o ficheiro de chave privada correspondente (sen «.pub»)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Xa existe o ficheiro {path}. Non foi posíbel crear unha nova chave SSH con " "ese nome." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Produciuse un fallo ao crear a nova chave SSH en {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Incluír os ficheiros e os directorios" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "«{path}» é unha ligazón simbólica. Non se fará unha copia de seguranza do " "destino ligado ata que tamén o inclúa." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Quere incluír o destino da ligazón simbólica?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Incluír ficheiros" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Incluír directorios" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Activar as notificacións" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Desactivar as copias de seguranza cando se emprega a batería" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "O estado da alimentación non está dispoñíbel no sistema" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Executar só unha copia de seguranza á vez" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "As outras copias de seguranza van ser bloqueadas ata que se complete a copia" " de seguranza actual. Este é un axuste global, o que significa que afectará " "a todos os perfís deste usuario. Mais tamén debe ser activado para o resto " "de usuarios." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Copia de seguranza dos ficheiros substituídos na restauración" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Continuar en erros (manter as copias de seguranza incompletas)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Usar a suma de comprobación para detectar cambios" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Crear unha nova copia de seguranza, houber cambios ou non." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Avisar se o espazo libre no disco cae por baixo de" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Amosa un aviso cando o espazo libre no disco de destino da copia de " "seguranza é menor que o valor especificado." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Se a directiva de Retirada e retención está activada e as copias de " "seguranza antigas son eliminadas en función do espazo libre dispoñíbel, este" " valor non pode ser inferior ao valor definido na directiva." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Nivel do rexistro:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Ningún" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "manual do usuario" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "As seguintes regras procésanse de arriba abaixo. As regras posteriores " "anulan as anteriores. Consulte o {manual_link} para obter máis detalles e " "exemplos." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Abrir o manual de usuario no navegador." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Conservar a copia de seguranza máis recente." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" "A última ou máis recente das copias de seguranza conservase en todas as " "circunstancias." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Non é posíbel cambiar este comportamento." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Conservar as copias de seguranza con nome." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "As copias de seguranza ás que se lles deu un nome, ademais da marca de tempo" " habitual, conservaranse en todas as circunstancias e non se eliminarán." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Ano(s)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Retirar as copias de seguranza anteriores a" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Días completos. O día actual ignorase." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Semanas naturais co luns como primeiro día. A semana actual ignorase." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Períodos de 12 meses. O mes actual ignórase." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Directiva de retención" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Executar en segundo plano no servidor remoto." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "A directiva de retención executarase directamente na máquina remota, non " "localmente. As ordes «bash», «screen» e «flock» deben estar instaladas e " "dispoñíbeis na máquina remota." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Se se selecciona, Back In Time probará primeiro a máquina remota." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Os días cóntanse a partir de hoxe." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Conservar todas as copias de seguranza dos últimos" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "día(s)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Conservar a última copia de seguranza de cada día para o último" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "As semanas cóntanse a partir da semana actual. Unha semana comeza o luns." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Conservar a última copia de seguranza por semana para a última" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "semana(s)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Os meses cóntanse como meses naturais a partir do mes en curso." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Conservar a última copia de seguranza de cada mes para o último" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "mes(es)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Os anos cóntanse como anos naturais a partir do ano en curso." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Conservar a última copia de seguranza de cada ano para" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "todos os anos." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… o espazo libre é inferior a" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… os inodos libres son menos do" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Retirar as copias de seguranza antigas se…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "É necesaria a autenticación para executar Back In Time como «root»." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "É necesaria a autenticación para cambiar a programación de copias de " "seguranza activadas pola conexión de dispositivos de almacenamento externos." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Atallos" #: qt/placeswidget.py:63 msgid "Places" msgstr "Lugares" #: qt/placeswidget.py:64 msgid "File System" msgstr "Sistema de ficheiros" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Directorios de copia de seguranza" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Perfil: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Perfil: {profile_name} (polo usuario «{desktop_user}»)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Ver o último rexistro" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Iniciar {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "En proceso…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "Páxina de «man»: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importar a configuración" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Non foi seleccionado ningún directorio" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importar" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Buscando…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Seleccione o directorio de copia de seguranza desde o que se debe importar o" " ficheiro de configuración. A ruta pode ter este aspecto: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Se o directorio está situado nunha unidade externa ou remota, debe montarse " "previamente de xeito manual." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Escanear de novo" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Amosar os directorios agochados" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Amosar/agochar os directorios agochados (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Non se atopou ningunha configuración neste directorio" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Completouse a busca." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Amosar o rexistro completo" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Conta atrás para o apagado" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Rematou a copia de seguranza." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Cancelar o apagado" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Apagar agora" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "O sistema apagarase e {n} segundo." msgstr[1] "O sistema apagarase e {n} segundos." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opcións sobre a comparanza de copias de seguranza" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Orde:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parámetros:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Usar %1 e %2 como parámetros da ruta" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Defina unha orde diff ou prema en Cancelar." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Non é posíbel atopar a orde «{cmd}» neste sistema. Tente outra cousa ou " "prema en Cancelar." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Non se definiu ningún parámetro para a orde diff. Usando o valor " "predeterminado «{params}»." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Copias de seguranza" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Só copias de seguranza con diferenzas" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Listar só as copias de seguranza que sexan iguais a:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Comprobación exhaustiva (máis precisa pero máis lenta)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Eliminar" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Seleccionar todo" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Comparar" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Ir a" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opcións" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Non é posíbel comparar unha copia de seguranza consigo mesma, xa que a " "comparación sería redundante." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Confirma que quere eliminar {file_or_dir} na copia de seguranza {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "" "Confirma que quere eliminar {file_or_dir} en {count} copias de seguranza?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "ADVERTENCIA: isto non se pode revogar." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Excluír {path} de copias de seguranza futuras?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Modo raíz" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time está en execución neste momento con privilexios de raíz (root) " "con acceso completo ao sistema" #: qt/timeline.py:69 msgid "Today" msgstr "Hoxe" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Onte" #: qt/timeline.py:87 msgid "This week" msgstr "Esta semana" #: qt/timeline.py:95 msgid "Last week" msgstr "A semana pasada" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Esta NON é unha copia de seguranza senón unha vista actual dos ficheiros " "locais." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Última comprobación {time}" backintime-1.6.1/common/po/he.po000066400000000000000000002363171514264426600165150ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Yaron Shahrabani # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-08-04 20:46+0000\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Weblate 5.12.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "כל הרישיונות בהם המיזם הזה משתמש נמצאים בתיקייה {dir_link}. כדי לחלץ רישיון " "ופרטי זכויות יוצרים לפי קובץ באמצעות נתוני על מסוג SPDX, יש לפנות אל " "{readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "אזהרה" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "פרופיל ראשי" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "מקומי (בהצפנת EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (בהצפנת EncFS)" #: common/config.py:237 msgid "Local" msgstr "מקומי" #: common/config.py:240 msgid "Local encrypted" msgstr "בהצפנה מקומית" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "הצפנה" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "מפתח SSH פרטי" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "פרופיל: „{name}”" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "תיקיית הגיבוי שגויה." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "יש לבחור לפחות תיקייה אחת לגיבוי." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "תיקייה: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "אי אפשר לכלול את התיקייה בגיבוי כיוון שהיא חלק מיעד הגיבוי עצמו." #: common/config.py:366 #, fuzzy, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "הערך עבור „הסרת הגיבוי הישן ביותר אם המקום הפנוי קטן מאשר” ({val_one}) חייב " "להיות קטן או שווה לסף „להזהיר אם המקום הפנוי יורד מתחת ל־” ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "נא לכוון את ההגדרות כדי שהסרת הגיבויים לא עולה על מגבלת האזהרה." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "תזמון udev לא עובד עם המצב {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "כתיבת crontab חדש נכשלה." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron לא פעיל למרות שהפקודה crontab זמינה. משימות גיבוי מתוזמנות לא תרוצנה. " "כנראה ש־Cron מותקן אבל לא מופעל. כדאי לנסות להריץ את שתי הפקודות „systemctl " "enable cron” ואת „systemctl start cron” או להיוועץ בערוצי התמיכה של הפצת " "הגנו/לינוקס שלך לקבלת עזרה." #: common/configfile.py:101 msgid "Failed to save config" msgstr "שמירת ההגדרות נכשלה" #: common/configfile.py:137 msgid "Failed to load config" msgstr "טעינת ההגדרות נכשלה" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "הפרופיל „{name}” כבר קיים." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "אי אפשר להסיר את הפרופיל האחרון." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "אי אפשר לעגן את ‚{command}’" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "לא נמצאו הגדרות לתיקייה מוצפנת." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "ליצור תיקייה מוצפנת חדשה?" #: common/encfstools.py:204 msgid "Cancel" msgstr "ביטול" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "נא למלא את סיסמת ה־EncFS מחדש כדי לאשר." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "סיסמאות ה־EncFS לא תואמות." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "שמירת תמונת מצב" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "אי אפשר לעגן את ‚{command}’" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "לא ניתן לנתק את העיגון {mountprocess} מ־{mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "פקודה {command} לא נמצאה. אפשר להתקין את הפקודה (בעזרת \"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "נקודת העיגון {mntpoint} לא ריקה." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "הכנס סיסמא בשביל {mode} משתמש \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "לא ניתן להתקין כלל Udev לפרופיל {profile_id}. שירות ה־D-Bus‏ " "‚{dbus_interface}’ לא היה זמין." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "לא ניתן למצוא מזהה ייחודי ל־{path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "נכשל" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "שחזור הרשאות" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "בוצע" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "לרשומות הבאות מרשימת ההכללה אין קובץ או תיקייה תואמים במקור הגיבוי:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "הגיבוי מושהה בעת שימוש בסוללה" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "לא ניתן למצוא את תיקיית הגיבויים." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "אם היא נמצאת על כונן נשלף, יש לחבר אותו." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "בהמתנה של שנייה אחת." msgstr[1] "בהמתנה של {n} שניות." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "יצירת הגיבוי {snapshot_id} נכשלה." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "נא להתאזר בסבלנות. התהליך מסתיים…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "לא ניתן ליצור את התיקייה." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "קובץ ההגדרות נשמר…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "הרשאות נשמרות…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "נמצאו שאריות של הגיבוי {snapshot_id} שאפשר להמשיך." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "התיקייה {snapshot_id} החלקית שנשארה מהריצה האחרונה נמחקת" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "לא ניתן להסיר תיקייה" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "נוצר גיבוי" #: common/snapshots.py:1517 msgid "Success" msgstr "הצלחה" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "שגיאה: בוצעה העברה חלקית בלבד" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "העברה חלקית עקב קובצי מקור שנעלמו (ר׳ ‚man rsync’)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "‚rsync’ הסתיים עם קוד היציאה {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "קרא את 'man rsync' לפרטים נוספים" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "קודים שליליים ביציאה של rsync הם מספרי אותות, ר׳ ‚kill -l’ ו־‚man kill’" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "דבר לא השתנה, לא צריך גיבוש חדש" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "לא ניתן לשנות את השם {new_path} ל־{path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "החלת כללים להסרת גיבויים ישנים" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "החלת מדיניות שימור" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "מתבצע ניסיון לשמור על מקום פנוי מזערי" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "מתבצע ניסיון לשמור לפחות {perc} מה־inodes פנויים" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "עכשיו" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "לא ניתן לעגן את {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent לא נמצא. נא לוודא שהוא מותקן." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "לא ניתן לשחרר את נעילת מפתח ה־ssh הפרטי. הסיסמה שגויה או שהסיסמה לא זמינה " "ל־cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "הנתיב המרוחק קיים אך הוא לא תיקייה." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "לא ניתן לכתוב לנתיב המרוחק." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "הנתיב המרוחק לא ניתן להפעלה." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "לא ניתן ליצור את הנתיב המרוחק." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "מארח מרוחק {host} לא תומך בפקודה {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "פקודות הבדיקה שרצו על {host} החזירו שגיאה לא ידועה" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "המארח המרוחק {host} לא תומך בקישורים קשיחים" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "העתקת מפתח ה־SSH הציבורי „{pubkey}” למארח המרוחק „{host}”." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "נא למלא סיסמה למשתמש „{user}”." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "מערכת הקבצים המיועדת ל־{path} מפורמטת ל־NTFS, שידועה בחוסר התאימות שלה " "למערכות קבצים תואמות יוניקס." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} אינה תיקייה תקפה." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "יצירת התיקייה הבאה נכשלה:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "גישת הכתיבה כנראה מוגבלת." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "מערכת הקבצים המיועדת ל־{path} מפורמטת ל־FAT שבה אין תמיכה בקישורים קשיחים. " "נא להשתמש במערכת קבצים טבעית של גנו/לינוקס." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "מערכת היעד עבור {path} היא שיתוף SMB מעוגן. נא לוודא ששרת ה־SMB המרוחק תומך " "בקישורים סמליים או להפעיל את„ {copyLinks}” תחת „{expertOptions}”." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "העתקת קישורים (ביטול הפניה של קישורים סמליים)" #: common/tools.py:487 msgid "Expert Options" msgstr "אפשרויות מתקדמות" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "מערכת הקבצים המיועדת עבור {path} היא שיתוף בעיגון sshfs. ב־sshfs אין תמיכה " "בקישורים קשיחים. נא להשתמש במצב „SSH” במקום." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "יצירת קבצים בתיקייה הזאת נכשלה:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "על חזרה בזמן" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "זכויות יוצרים:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "יוצרים:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "מתרגמים:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Yaron Shahrabani" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "אין תודות מתרגמים לשפה הנוכחית." #: qt/aboutdlg.py:116 msgid "this link" msgstr "לקישור הזה" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "אפשר לגשת {thislink} כדי לצפות בתודות למתרגמים בכל השפות." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "אתר המיזם" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "מדריך למשתמשים" #: qt/aboutdlg.py:227 qt/app.py:562 #, fuzzy msgid "Open user manual in browser (local if available, otherwise online)" msgstr "פתיחת מדריך המשתמש בדפדפן (מקומי אם זמין או מקוון אם לא)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}גרסה{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "נראה כי {app_name} עולה לראשונה כיוון שלא נמצאו הגדרות." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "לייבא הגדרות קיימות (מתיקיית יעד גיבוי או ממחשב אחר)?" #: qt/app.py:395 msgid "Then press OK." msgstr "ואז ללחוץ על אישור." #: qt/app.py:499 msgid "Create a backup" msgstr "יצירת גיבוי" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "להשתמש בזמן השינוי ובגודל לזיהוי שינויים בקובץ." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "יצירת גיבוי (מצב סיכומי ביקורת)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "להשתמש בסיכומי ביקורת לאיתור שינויים." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "השהיית תהליך גיבוי" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "המשך תהליך גיבוי" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "עצירת תהליך הגיבוי" #: qt/app.py:520 msgid "Refresh backup list" msgstr "רענון רשימת הגיבויים" #: qt/app.py:524 msgid "Name backup" msgstr "מתן שם לגיבוי" #: qt/app.py:528 msgid "Remove backup" msgstr "הסרת גיבוי" #: qt/app.py:532 msgid "Open backup log" msgstr "פתיחת יומן גיבוי" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "הצגת יומן הגיבוי הנבחר." #: qt/app.py:536 msgid "Open last backup log" msgstr "פתיחת יומן הגיבוי האחרון" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "הצגת יומן הגיבוי האחרון." #: qt/app.py:540 msgid "Manage profiles…" msgstr "ניהול פרופילים…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "עריכת משוב משתמש" #: qt/app.py:548 msgid "Shutdown" msgstr "כיבוי" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "לכבות את המערכת אחרי ששמירת הגיבוי הסתיימה." #: qt/app.py:552 msgid "Setup language…" msgstr "הגדרות שפה…" #: qt/app.py:556 msgid "Exit" msgstr "יציאה" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "עמוד ה־man‏: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "הצגת עמוד man על Back In Time ‏(backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "עמוד man: קובץ הגדרת פרופילים" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "הצגת עמוד man על קובץ הגדרת פרופילים (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "פתיחת אתר Back In Time בדפדפן" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "יומן שינויים" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "פתיחת יומן השינויים (מקומי אם זמין או מקוון אם לא)" #: qt/app.py:589 msgid "FAQ" msgstr "שאלות ותשובות" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "פתיחת שאלות נפוצות (שו״ת) בדפדפן" #: qt/app.py:593 msgid "Ask a question" msgstr "פרסום שאלה" #: qt/app.py:597 msgid "Report a bug" msgstr "דיווח על תקלה" #: qt/app.py:600 msgid "Translation" msgstr "תרגום" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "הצגת ההודעה בנוגע להשתתפות בתרגום שוב." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "תעבורה מוצפנת (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "הצגת ההודעה על הסרת EncFS שוב." #: qt/app.py:615 msgid "About" msgstr "על אודות" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "שחזור" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "שחזור הקבצים או התיקיות הנבחרים ליעד המקורי." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "שחזור אל…" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "שחזור הקבצים או התיקיות הנבחרים ליעד חדש." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "שחזור התיקייה שמופיעה ואת כל התוכן שלה ליעד המקורי." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "שחזור התיקייה שמופיע ואת כל התוכן שלה ליעד חדש." #: qt/app.py:640 msgid "Up" msgstr "למעלה" #: qt/app.py:643 msgid "Show hidden files" msgstr "הצגת קבצים נסתרים" #: qt/app.py:646 msgid "Compare backups…" msgstr "השוואת גיבויים…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "מועמדת להוצאה לאור" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "הצגת ההודעה על המועמדת להוצאה לאור שוב." #: qt/app.py:716 msgid "Back In &Time" msgstr "&חזרה בזמן" #: qt/app.py:721 msgid "&Backup" msgstr "&גיבוי" #: qt/app.py:733 msgid "&Restore" msgstr "&שחזור" #: qt/app.py:739 msgid "&Help" msgstr "ע&זרה" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "סמלים בלבד" #: qt/app.py:827 msgid "Text only" msgstr "טקסט בלבד" #: qt/app.py:830 msgid "Text below icons" msgstr "טקסט מתחת לסמלים" #: qt/app.py:833 msgid "Text beside icon" msgstr "טקסט ליד הסמלים" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "התיקייה הזאת לא קיימת\n" "בגיבוי הנוכחי שנבחר." #: qt/app.py:1005 msgid "Add to Include" msgstr "הוספה להכללה" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "הוספה להחרגה" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "אם החלון הזה סגור, לא תהיה ל־Back In Time לכבות את המערכת שלך עם סיום " "הגיבוי." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "לסגור את החלון הזה בכל זאת?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "הסתיים, לא נדרש גיבוי" #: qt/app.py:1285 msgid "Working:" msgstr "בעבודה:" #: qt/app.py:1292 msgid "Working" msgstr "בעבודה" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "שגיאה" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "נשלחו:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "מהירות:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "זמן משוער לסיום:" #: qt/app.py:1490 msgid "Backup:" msgstr "גיבוי:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "שחזור {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "לשחזר את {path} אל…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "שלום\n" "השתמשת ב־Back In Time ב{language} מספר פעמים עד כה.\n" "מלאכת התרגום של הגרסה שהתקנת של Back In Time ל{language} הושלמה ב־{perc} אחוז. בלי קשר לרמת הידע הטכני שלך, אפשר לתרום למלאכת התרגום ובכך לתרום ל־Back In Time עצמה.\n" "נא לגשת אל {translation_platform_url} כדי לעזור. לעזרה ושאלות נוספות, נא לבקר ב־{back_in_time_project_website}.\n" "אנחנו מתנצלים על ההפרעה, וההודעה הזאת לא תופיע שוב. החלונית הזאת זמינה בכל עת דרך תפריט העזרה.\n" "צוות Back In Time לרשותכם" #: qt/app.py:1709 msgid "translation platform" msgstr "פלטפורמת תרגום" #: qt/app.py:1714 msgid "Website" msgstr "אתר" #: qt/app.py:1728 msgid "Your translation" msgstr "התרגום שלך" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "בפדיברס דרך מסטודון: {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "רשימת הדיוור {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "רשימת הדיוור {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} באתר המיזם." #: qt/app.py:1781 msgid "Open an issue" msgstr "לפתוח דיווח תקלה" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "לחלופין, אפשר להשתמש בכל ערוץ אחר לשיקולך." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "הגרסה הזאת של Back In Time היא מועמדת להוצאה לאור ומיועדת בעיקר לבדיקות יציבות ולהכנה למהדורה הרשמית הבאה.\n" "לא נאספים נתוני משתמש או מדדים. עם זאת, צוות Back In Time מאוד ישמח לדעת מה אופן השימוש במהדורה שמיועדת להוצאה לאור והאם שווה להמשיך לספק גרסאות טרום הוצאה לאור שכאלה.\n" "לכן, הצוות מבקש בצורה נעימה לקבל משוב קצר על האם בדקת את הגרסה הזאת, אפילו אם לא נתקלת בתקלות כלשהן. אפילו בדיקה זריזה שתרוץ במשך מספר דקות תעזור לנו מאוד.\n" "אלו האפשרויות הזמינות ליצירת קשר:\n" "{contact_list}\n" "בגרסה הזאת, ההודעה הזאת לא תופיע שוב אבל אפשר לגשת אליה בכל עת דרך תפריט העזרה.\n" "תודה על התמיכה ועל הסיוע במאמצים לשיפור Back In Time!\n" "צוות Back In Time לרשותך" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "רק {free} של מקום פנוי זמינים ביעד, שזה מתחת ליעד שהוגדר על סך {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "להמשיך עם הגיבוי?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "כל הקבצים החדשים יותר ב־{path} יוסרו. להמשיך?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "כל הקבצים החדשים ביותר בתיקייה המקומית יוסרו. להמשיך?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}אזהרה{BOLDEND}: מחיקת קבצים בשורש מערכת הקבצים יכולה לשבש את כל המערכת" " שלך." #: qt/app.py:2167 msgid "Backup name" msgstr "שם הגיבוי" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "להסיר את הגיבוי הזה?" msgstr[1] "להסיר את הגיבויים האלה?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "הגדרות השפה ייכנסו לתוקף רק לאחר הפעלת Back In Time מחדש." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "להשאיר גיבויים עם שמות." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "שאלה" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "ליצור עותקי גיבוי עם {suffix} כסיומת בטרם שכתוב או הסרה של רכיבים מקומיים." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "לפני השחזור, גרסאות חדשות יותר של קבצים ישנות את שמם עם תוספת {suffix}. אפשר" " להסיר את הקבצים האלה עם הפקודה הבאה:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "לשחזר רק קבצים שלא נמצאים או שהם חדשים יותר מאלו ביעד. באמצעות האפשרות " "„{rsync_example}”." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "הסרת רכיבים חדשים יותר בתיקייה המקורית." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "שחזור הקבצים או התיקיות הנבחרים ליעדם המקורי ולמחוק קבצים ותיקיות שאינם " "בגיבוי. חובה לנקוט במשנה זהירות כיוון שהפעולה הזאת תמחק קבצים ותיקיות " "שהוחרגו במהלך הכנת הגיבוי." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "לשחזר את הרכיב הזה לתיקייה החדשה?" msgstr[1] "לשחזר את הרכיבים האלה לתיקייה החדשה?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "לשחזר את הרכיב הזה?" msgstr[1] "לשחזר את הרכיבים האלה?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "קריאת משתמש: „{filename}”" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "סקריפט קריאת משתמש חייב לכלול שורת פתיח (shebang) בשורה הראשונה (למשל: " "{example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "הצגת/הסתרת קבצים ותיקיות מוסתרים (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "הגדרת שפה" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "תורגמו: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "ברירת מחדל המערכת" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "להשתמש בשפת מערכת ההפעלה." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "תצוגת יומן גיבוי" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "תצוגת היומן האחרון" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "פרופיל:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "גיבויים:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "סינון:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] שגיאה, [I] מידע, [C] שינוי" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "פענוח נתיבים" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "הכול" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "שינויים" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "שגיאות" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "פרטים" msgstr[1] "פרטים" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "כשלי העברה דרך rsync (ניסיוניים)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "ניהול פרופילים" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "עריכה" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "הוספה" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "הסרה" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&כללי" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "לכלול" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "לה&חריג" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "ה&סרה ושימור" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&אפשרויות" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "אפשרויות &מומחים" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "שחזור הגדרות" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "פרופיל חדש" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "שינוי שם לפרופיל" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "למחוק את הפרופיל „{name}”?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "השהיית תהליך גיבוי" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "החרגת קבצים" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "תיקיות גיבוי" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "לא ניתן להסיר תיקייה" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "הצגת תיקיות מוסתרות" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "עצירת תהליך הגיבוי" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "החרגת תיקיות" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "ברירת מחדל" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "תזמון" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "יום:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "יום בשבוע:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "שעה:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "שעות:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "אחרי השעה" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "דקות:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "להריץ את Back In Time עם חיבור הכונן (פעם אחת כל X ימים). תופיע בקשה לסיסמת " "העל שלך (sudo)." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "הרצת Back In Time באופן מחזורי. שימוש אם המחשב לא דולק קבוע." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "כל:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "הפעלת תיעוד של הודעות ניפוי שגיאות" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "כתיבת הודעות ברמת ניפוי שגיאות ליומן המערכת דרך „‎--debug”." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "אזהרה: להשתמש בזה באופן זמני לאבחון, כיוון שזה מייצר המון פלט." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "מושבת" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "בכל טעינה/הפעלה מחדש של מערכת" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "כל דקה" msgstr[1] "כל {n} דקות" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "כל שעה" msgstr[1] "כל {n} שעות" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "שעות מותאמות אישית" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "כל יום" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "במחזוריות (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "כאשר כונן מתחבר (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "כל שבוע" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "כל חודש" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "כל שנה" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "שעה/ות" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "יום/ימים" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "שבוע/ות" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "חודש/ים" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "שעות מותאמות אישית יכול להיות רק רשימת של שעות מופרדת בפסיקים (למשל: " "8,12,18,23) או ‎*/3 לגיבויים במחזורים של 3 שעות." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "" #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "" #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Privatni ključ za SSH" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Domaćin:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Korisnik:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" #: qt/manageprofiles/tab_exclude.py:85 #, fuzzy msgid "Exclude patterns, files or directories" msgstr "Iskljući sljedove, datoteke ili mape" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Isključi slijed" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Dodaj datoteku" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Dodaj mapu" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Isključi datoteku:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "" #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Isključi slijed" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Isključi slijed" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Isključi datoteku" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Isključi mapu" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Sačuvaj ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "" #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Gdje sačuvati snimke" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Novi profil" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Napredno" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Lozinka se ne podudara." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "" #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Stvori novu šifriranu mapu?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "Privatni ključ za SSH" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "" #: qt/manageprofiles/tab_include.py:48 #, fuzzy msgid "Include files and directories" msgstr "Ukljući mape i datoteke" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Uključi datoteku" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Uključi mapu" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Omogući obavijesti" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Onesposobi snimke tijekom rada na bateriji" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Stanje energije nije dostupno od sustava" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Nastavi ne grješkama (zadrži nepotpune snimke)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Razina Zapisa:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nijedno" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Nemoj uklanjati imenovane snimke." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Nemoj uklanjati imenovane snimke." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Godina" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Ukloni Snimku" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "Dan(a)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "Tjedan(a)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:389 #, fuzzy msgid "… the free space is less than" msgstr "Ako je slobodan prostor manji od:" #: qt/manageprofiles/tab_remove_retention.py:394 #, fuzzy msgid "… the free inodes are less than" msgstr "Ako je slobodan prostor manji od:" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Ukloni stare snimke" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Prečaci" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 #, fuzzy msgid "Backup directories" msgstr "Mape rezerve" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Prikaži Zadnji Zapis" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Radim…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Radim…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Prikaži skrivene datoteke" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Ukljući mape i datoteke" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Neuspješno stvaranje datoteke u sljedećoj mapi:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Isključi sustav kad snimanje završi." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Isključi računalo" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Isključi računalo" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "" #: qt/snapshotsdialog.py:70 #, fuzzy msgid "Command:" msgstr "Naredba" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametri:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "" #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Backup" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Odgoda sigurnosnog kopiranja za vrijeme punjenja" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Dubinska provjera (preciznije, ali sporije)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Idi Na" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opcije" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Neuspjelo uzimanje snimke {snapshot_id} !!!" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "" #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Korijen" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Danas" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Jučer" #: qt/timeline.py:87 msgid "This week" msgstr "Ovaj tjedan" #: qt/timeline.py:95 msgid "Last week" msgstr "Prošli tjedan" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "" backintime-1.6.1/common/po/hu.po000066400000000000000000002440201514264426600165230ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Úr Balázs , 2024, 2025, 2026. # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-08 06:18+0000\n" "Last-Translator: urbalazs \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "A projektben használt összes licenc megtalálható a(z) {dir_link} " "könyvtárban. Az SPDX metaadatok használatával történő fájlonkénti licenc- és" " szerzői jogi információk kinyeréséhez olvassa el a tájékoztatót: " "{readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Figyelmeztetés" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Fő profil" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Helyi (EncFS-sel titkosított)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS-sel titkosított)" #: common/config.py:237 msgid "Local" msgstr "Helyi" #: common/config.py:240 msgid "Local encrypted" msgstr "Helyi titkosított" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Titkosítás" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH személyes kulcs" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: „{name}”" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "A biztonsági mentés könyvtára nem érvényes." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Legalább egy könyvtárat ki kell választani a biztonsági mentéshez." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Könyvtár: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Ez a könyvtár nem szerepelhet a biztonsági mentésben, mivel magának a " "biztonsági mentési célnak a része." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Az „A legrégebbi biztonsági mentés eltávolítása, ha a szabad hely kevesebb " "mint” értékének ({val_one}) kisebbnek vagy egyenlőnek kell lennie a " "„Figyelmeztetés, ha a szabad lemezterület ez alá csökken” küszöbszintjével " "({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Állítsa be a beállításokat úgy, hogy a biztonsági mentés eltávolítási " "korlátja ne legyen magasabb a figyelmeztetési korlátnál." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Az udev ütemezése nem működik a(z) {mode} móddal" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Nem sikerült az új crontab írása." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "A cron nem fut, annak ellenére hogy a crontab parancs elérhető. A ütemezett " "biztonsági mentési feladatok nem fognak futni. Lehet, hogy a cron telepítve " "van, de nincs engedélyezve. Próbálja meg lefuttatni a „systemctl enable " "cron„ és „systemctl start cron” parancsokat, vagy kérjen segítséget a " "jelenleg használt GNU/Linux disztribúció támogatási csatornáin." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Nem sikerült elmenteni a beállításokat" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Nem sikerült betölteni a beállításokat" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "A(z) „{name}” profil már létezik." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Az utolsó profilt nem lehet eltávolítani." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Nem lehet csatolni a(z) „{command}” parancsot" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "A titkosított könyvtár beállítása nem található." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Létrehoz egy új titkosított könyvtárat?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Mégse" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Adja meg újra az EncFS jelszót a megerősítéshez." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Az EncFS jelszavak nem egyeznek." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Pillanatkép készítése" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Nem lehet előkészíteni a(z) „{command}” titkosított útvonalat" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "" "Nem lehet leválasztani a(z) {mountprocess} folyamatot a(z) {mountpoint} " "csatolási pontról." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "A(z) {command} nem található. Telepítse (például ezzel: „{installcommand}”)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "A(z) {mntpoint} csatolási pont nem üres." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Adja meg a(z) „{profile}” {mode} profil jelszavát:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Nem sikerült telepíteni az Udev-szabályt a(z) {profile_id} profilnál. A(z) " "„{dbus_interface}” DBus-szolgáltatás nem volt elérhető." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Nem található a(z) „{path}” UUID-ja" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "SIKERTELEN" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Jogosultságok helyreállítása" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Kész" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "A tartalmazási lista következő bejegyezéseinek nincs megfelelő fájlja vagy " "könyvtára a biztonsági mentés forrásában:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Biztonsági mentés elhalasztása akkumulátorról való működésnél" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Nem található a biztonsági mentés könyvtára." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Ha cserélhető meghajtón van, akkor helyezze be." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "{n} másodperc várakozás." msgstr[1] "{n} másodperc várakozás." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Nem sikerült létrehozni a(z) {snapshot_id} biztonsági mentést." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Legyen türelemmel. Véglegesítés…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Nem lehet létrehozni a könyvtárat." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Beállítófájl mentése…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Jogosultságok mentése…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Található egy befejezetlen {snapshot_id} biztonsági mentés, amely " "folytatható." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "A befejezetlen {snapshot_id} könyvtár eltávolítása a legutóbbi futtatásból" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Nem lehet eltávolítani a könyvtárat" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Biztonsági mentés létrehozása" #: common/snapshots.py:1517 msgid "Success" msgstr "Sikeres" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Részleges átvitel egy hiba miatt" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "Részleges átvitel az eltűnt forrásfájlok miatt (lásd: „man rsync”)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "Az „rsync” a(z) {exit_code} számú hibakóddal fejeződött be" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Nézze meg a „man rsync” kézikönyvet a további részletekért" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "A negatív rsync kilépési kódok szignálszámok, nézze meg a „kill -l” és a " "„man kill” parancsokat" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Semmi sem változott, nincs szükség új biztonsági mentésre" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Nem lehet átnevezni a(z) {new_path} útvonalat erre: {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Szabályok alkalmazása a régi biztonsági mentések eltávolításához" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Megtartási irányelv alkalmazása" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Kísérlet a legkisebb szabad hely megtartására" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Kísérlet legalább {perc} szabad inode megtartására" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Most" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Nem lehet csatolni: {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" "Az „ssh-agent” nem található. Győződjön meg arról, hogy telepítve van." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Nem sikerült feloldani az SSH személyes kulcsát. Hibás a jelszó vagy a " "jelszó nem érhető el a cron számára." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "A távoli útvonal létezik, de nem könyvtár." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "A távoli útvonal nem írható." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "A távoli útvonal nem futtatható." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Nem sikerült létrehozni a távoli útvonalat." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "A(z) {host} távoli kiszolgáló nem támogatja a(z) {command} parancsot" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "A parancsok ellenőrzése a(z) {host} kiszolgálón ismeretlen hibát adott " "vissza" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "" "A(z) {host} távoli kiszolgáló nem támogatja a rögzített hivatkozásokat" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "" "A(z) „{pubkey}” nyilvános SSH-kulcs másolása a(z) „{host}” távoli " "kiszolgálóra." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Adja meg „{user}” felhasználó jelszavát." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "A(z) {path} útvonal célfájlrendszere NTFS-re van formázva, amely nem " "kompatibilis a Unix-stílusú fájlrendszerekkel." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "A(z) {path} nem érvényes könyvtár." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "A következő könyvtár létrehozása nem sikerült:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Az írási hozzáférés korlátozott lehet." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "A(z) {path} útvonal célfájlrendszere FAT-tal van formázva, amely nem " "támogatja a rögzített hivatkozásokat. Használjon natív GNU/Linux " "fájlrendszert." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "A(z) {path} útvonal célfájlrendszere egy SMB csatolású megosztás. Győződjön " "meg arról, hogy a távoli SMB-kiszolgáló támogatja-e a szimbolikus " "hivatkozásokat vagy kapcsolja be a „{copyLinks}” lehetőséget az " "„{expertOptions}” alatt." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Hivatkozások másolása (szimbolikus hivatkozások megszüntetése)" #: common/tools.py:487 msgid "Expert Options" msgstr "Szakértői beállítások" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "A(z) {path} útvonal célfájlrendszere egy sshfs csatolású megosztás. Az sshfs" " nem támogatja a rögzített hivatkozásokat. Használja inkább az „SSH” módot." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "A fájl létrehozása ebben a könyvtárban nem sikerült:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "A Back In Time névjegye" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Szerzői jog:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Szerzők:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Fordítók:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Úr Balázs , 2024, 2025, 2026." #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "A fordítók névsora nem érhető el a jelenlegi nyelvhez." #: qt/aboutdlg.py:116 msgid "this link" msgstr "ezt a hivatkozást" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "Kövesse {thislink} az összes nyelv fordítói névsorának lekéréséhez." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Projekt webhelye" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Felhasználói kézikönyv" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Felhasználói kézikönyv megnyitása a böngészőben (helyileg, ha elérhető, " "egyébként az internetről)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Verzió{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Úgy tűnik, hogy a(z) {app_name} először lett elindítva, mert nem található " "beállítás hozzá." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Importál egy meglévő beállítást (egy biztonsági mentés helyéről vagy egy " "másik számítógépről)?" #: qt/app.py:395 msgid "Then press OK." msgstr "Ezután nyomja meg a Rendben gombot." #: qt/app.py:499 msgid "Create a backup" msgstr "Biztonsági mentés létrehozása" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "A módosítás ideje és a méret használata a fájlváltoztatások felismeréséhez." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Biztonsági mentés létrehozása (ellenőrzőösszeg mód)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Ellenőrzőösszegek használata a fájlváltoztatások felismeréséhez." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Biztonsági mentési folyamat szüneteltetése" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Biztonsági mentési folyamat folytatása" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Biztonsági mentési folyamat leállítása" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Biztonsági mentési lista frissítése" #: qt/app.py:524 msgid "Name backup" msgstr "Biztonsági mentés elnevezése" #: qt/app.py:528 msgid "Remove backup" msgstr "Biztonsági mentés eltávolítása" #: qt/app.py:532 msgid "Open backup log" msgstr "Biztonsági mentési napló megnyitása" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "A kiválasztott biztonsági mentés naplójának megtekintése." #: qt/app.py:536 msgid "Open last backup log" msgstr "Utolsó biztonság mentési napló megnyitása" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Az utolsó biztonsági mentés naplójának megtekintése." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Profilok kezelése…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Felhasználó-visszahívás szerkesztése" #: qt/app.py:548 msgid "Shutdown" msgstr "Leállítás" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "A rendszer leállítása a biztonsági mentés befejezése után." #: qt/app.py:552 msgid "Setup language…" msgstr "Nyelv beállítása…" #: qt/app.py:556 msgid "Exit" msgstr "Kilépés" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "kézikönyvoldal: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Megjeleníti a Back In Time (backintime) kézikönyvoldalát" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "kézikönyvoldal: Profilok beállítófájlja" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Megjeleníti a profilok beállítófájljával kapcsolatos kézikönyvoldalt " "(backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "A Back In Time webhelyének megnyitása a böngészőben" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Változásnapló" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Változásnapló megnyitása (helyileg, ha elérhető, egyébként az internetről)" #: qt/app.py:589 msgid "FAQ" msgstr "GYIK" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Gyakran ismételt kérdések (GYIK) megnyitása a böngészőben" #: qt/app.py:593 msgid "Ask a question" msgstr "Kérdés feltevése" #: qt/app.py:597 msgid "Report a bug" msgstr "Hiba jelentése" #: qt/app.py:600 msgid "Translation" msgstr "Fordítás" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "" "Ismét megjeleníti a fordításban való részvétellel kapcsolatos üzenetet." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Titkosítási átmenet (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Ismét megjeleníti az EncFS eltávolításával kapcsolatos üzenetet." #: qt/app.py:615 msgid "About" msgstr "Névjegy" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Helyreállítás" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "A kijelölt fájlok vagy könyvtárak helyreállítása az eredeti helyre." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Helyreállítás ide…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "A kijelölt fájlok vagy könyvtárak helyreállítása új helyre." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "A jelenleg megjelenített könyvtár és annak teljes tartalmának helyreállítása" " az eredeti helyre." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "A jelenleg megjelenített könyvtár és annak teljes tartalmának helyreállítása" " új helyre." #: qt/app.py:640 msgid "Up" msgstr "Fel" #: qt/app.py:643 msgid "Show hidden files" msgstr "Rejtett fájlok megjelenítése" #: qt/app.py:646 msgid "Compare backups…" msgstr "Biztonsági mentések összehasonlítása…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Kiadásra jelölt" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Ismét megjeleníti az ezzel a kiadásra jelölttel kapcsolatos üzenetet." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Biztonsági mentés" #: qt/app.py:733 msgid "&Restore" msgstr "&Helyreállítás" #: qt/app.py:739 msgid "&Help" msgstr "&Súgó" #: qt/app.py:790 msgid "Systray Icon" msgstr "Rendszertálca ikon" #: qt/app.py:796 msgid "Automatic" msgstr "Automatikus" #: qt/app.py:800 msgid "Light icon" msgstr "Világos ikon" #: qt/app.py:801 msgid "Dark icon" msgstr "Sötét ikon" #: qt/app.py:824 msgid "Icons only" msgstr "Csak ikonok" #: qt/app.py:827 msgid "Text only" msgstr "Csak szöveg" #: qt/app.py:830 msgid "Text below icons" msgstr "Szöveg az ikonok alatt" #: qt/app.py:833 msgid "Text beside icon" msgstr "Szöveg az ikon mellett" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Ez a könyvtár nem létezik a jelenleg\n" "kiválasztott biztonsági mentésben." #: qt/app.py:1005 msgid "Add to Include" msgstr "Hozzáadás a felvettekhez" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Hozzáadás a kizártakhoz" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Ha ezt az ablak bezárásra kerül, akkor a Back In Time nem lesz képes " "leállítani a rendszert a biztonsági mentés befejezése után." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Mindenképp bezárja az ablakot?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Kész, nincs szükség biztonsági mentésre" #: qt/app.py:1285 msgid "Working:" msgstr "Munkavégzés:" #: qt/app.py:1292 msgid "Working" msgstr "Munkavégzés" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Hiba" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Elküldve:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Sebesség:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Becsült hátralévő idő:" #: qt/app.py:1490 msgid "Backup:" msgstr "Biztonsági mentés:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "{path} helyreállítása" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "{path} helyreállítása ide…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Üdvözöljük!\n" "Ön már többször használta a Back In Time programot {language} nyelven.\n" "A Back In Time telepített verziójának {language} nyelvre történő fordítása {perc} készültségű. Függetlenül attól, hogy milyen szintű műszaki ismeretekkel rendelkezik, hozzájárulhat a fordításhoz, és így magához a Back In Time-hoz is.\n" "Látogasson el a {translation_platform_url} oldalra, ha szeretne közreműködni. A további segítségért és kérdésekért látogasson el a {back_in_time_project_website} weboldalra.\n" "Elnézést kérünk a zavarásért. Ez az üzenet nem fog többé megjelenni. Ez a párbeszédablak később is bármikor elérhető a súgó menüben.\n" "A Back In Time csapata" #: qt/app.py:1709 msgid "translation platform" msgstr "fordítási platform" #: qt/app.py:1714 msgid "Website" msgstr "Webhely" #: qt/app.py:1728 msgid "Your translation" msgstr "Az Ön fordítása" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "A mastodoni födiverzumban: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "E-mail küldése: {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Levelezőlista: {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} a projekt webhelyén." #: qt/app.py:1781 msgid "Open an issue" msgstr "Nyisson hibajegyet" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" "Alternatívaként egy másik, Ön által választott csatornát is használhat." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "A Back In Time ezen verziója kiadásra jelölt, és elsősorban a következő hivatalos kiadásra való felkészülés során végzett stabilitástesztekre szolgál.\n" "Nem gyűjt felhasználói adatokat vagy telemetriát. A Back In Time csapatát azonban nagyon érdekli, hogy a kiadásra jelölt verzió használatban van-e, és érdemes-e folytatni az ilyen kiadás előtti verziók biztosítását.\n" "Ezért a csapat rövid visszajelzést kér arról, hogy tesztelte-e ezt a verziót, még akkor is, ha nem találkozott semmilyen problémával. Már egy gyors, néhány perces próbahasználat is sokat segítene nekünk.\n" "A következő kapcsolatfelvételi lehetőségek állnak rendelkezésre:\n" "{contact_list}\n" "Ebben a verzióban ez az üzenet nem jelenik meg újra, de bármikor elérhető a súgó menüből.\n" "Köszönjük a támogatását és azt, hogy segít nekünk a Back In Time fejlesztésében!\n" "Az Ön Back In Time csapata" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Csak {free} szabad terület érhető el a célon, amely a beállított {threshold}" " küszöbszint alatt van." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Folytatja a biztonsági mentést?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" "A(z) {path} útvonalon lévő összes újabb fájl el lesz távolítva. Folytatja?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Az eredeti könyvtárban lévő összes újabb fájl el lesz távolítva. Folytatja?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Figyelmeztetés:{BOLDEND} a fájlrendszer gyökerében lévő fájlok törlése" " tönkreteheti az egész rendszert." #: qt/app.py:2167 msgid "Backup name" msgstr "Biztonsági mentés neve" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Eltávolítja ezt a biztonsági mentést?" msgstr[1] "Eltávolítja ezeket a biztonsági mentéseket?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "A nyelvi beállítások csak a Back In Time újraindítása után lépnek érvénybe." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Verziózott biztonsági mentések (rendszergazda)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Felhasználóbarát grafikus felület a verziózott biztonsági mentésekhez, ami " "csökkenti a lemezhasználatot (rendszergazdai mód)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Verziózott biztonsági mentések" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Felhasználóbarát grafikus felület a verziózott biztonsági mentésekhez, ami " "csökkenti a lemezhasználatot" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Kérdés" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Biztonsági mentés másolatok létrehozása {suffix} végződéssel a helyi elemek " "felülírása vagy eltávolítása előtt." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "A helyreállítás előtt a fájlok újabb verziói átnevezésre kerülnek a " "hozzáfűzött {suffix} értékkel. Ezek a fájlok a következő paranccsal " "távolíthatók el:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Csak azon elemek helyreállítása, amelyek nem léteznek, vagy újabbak a " "célhelyen lévőknél. Az „{rsync_example}” kapcsoló használata." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Újabb elemek eltávolítása az eredeti könyvtárból." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "A kijelölt fájlok vagy könyvtárak helyreállítása az eredeti célhelyre, " "valamint a biztonsági mentésben nem szereplő fájlok vagy könyvtárak törlése." " Legyen rendkívül óvatos, mert ez törölni fogja azokat a fájlokat és " "könyvtárakat, amelyek a biztonsági mentés létrehozásakor ki voltak zárva." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Valóban helyreállítja ezt az elemet az új könyvtárba?" msgstr[1] "Valóban helyreállítja ezeket az elemeket az új könyvtárba?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Valóban helyreállítja ezt az elemet?" msgstr[1] "Valóban helyreállítja ezeket az elemeket?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Felhasználó-visszahívás: „{filename}”" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "A felhasználó-visszahívási parancsfájlnak parancsértelmezőt megadó sort kell" " tartalmaznia az első sorban (például {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Rejtett fájlok és könyvtárak megjelenítése vagy elrejtése (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Nyelv beállítása" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Lefordítva: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Rendszer alapértelmezettje" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Az operációs rendszer nyelvének használata." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Biztonsági mentési napló nézet" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Utolsó napló megtekintése" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Biztonsági mentések:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Szűrő:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] hiba, [I] információ, [C] változtatás" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "útvonalak visszafejtése" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Összes" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Változtatások" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Hibák" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Információk" msgstr[1] "Információk" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync átviteli hibák (kísérleti)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Profilok kezelése" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Szerkesztés" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Hozzáadás" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Eltávolítás" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "Á<alános" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Felvétel" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Kizárás" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Eltávolítás és megtartás" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Beállítások" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "S&zakértői beállítások" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Beállítások helyreállítása" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Új profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Profil átnevezése" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Törli a(z) „{name}” profilt?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Szimbolikus hivatkozások másolása fájlokként" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Szimbolikus hivatkozások valódi fájlokként vagy könyvtárakként való másolása" " a biztonsági mentésbe. Válassza ki, hogy az összes hivatkozást vagy csak a " "forráson kívülre mutatókat kell másolni." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Ez a beállítás növelheti a biztonsági mentés méretét." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Alapértelmezetten le van tiltva." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Az összes szimbolikus hivatkozás azokkal a valódi fájlokkal vagy " "könyvtárakkal kerül helyettesítésre, amelyekre mutatnak. Ez növeli a " "biztonsági mentés méretét, és ugyanazokat a fájlokat többször is tárolhatja." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Az „rsync --copy-links” kapcsolót használja." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Csak külső" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Csak a biztonsági mentés forrásán kívülre mutató hivatkozások lesznek " "fájlokként másolva. Ez növeli a biztonsági mentés méretét, és ugyanazokat a " "fájlokat többször is tárolhatja." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Az „rsync --copy-unsafe-links” kapcsolót használja." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Szerkesztő és irodai programcsomag ideiglenes fájljai" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacs biztonsági mentési fájlok" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs automatikusan mentett fájljai" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Vim cserehelyfájlok" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Office ideiglenes fájljai" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice és egyéb OpenDocument-szerkesztők zárolási fájljai" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Bélyegképek és ideiglenes képek" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "Bélyegkép-gyorsítótár GNU/Linux és egyéb Unix-szerű operációs rendszereken" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Bélyegkép-adatbázis Windows rendszeren" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Metaadatkönyvtár MacOS rendszeren" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Alkalmazásspecifikus zárolások" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discord-alkalmazás zárolási fájlja" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord-munkamenet zárolási fájlja" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Mozilla Firefox és Thunderbird zárolási fájlja" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Gyorsítótárak és ideiglenes könyvtárak" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "A felhasználó alkalmazás-gyorsítótára" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "A rendszer ideiglenes könyvtára" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Csomaggyorsítótár Debian(-alapú) GNU/Linux disztribúcióknál" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Flatpak alkalmazás- és futtatókörnyezet-tárolók" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "A rendszer futtatókörnyezet-könyvtárai" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Rendszermag- és folyamatinformációk" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Eszköz- és egyéb hardverinformációk (sysfs csatoló)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Eszközcsomópontok" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Futtatókörnyezet rendszerfájljai" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Egyéb nem tartós" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Jelenleg csatolt fájlrendszerek listája" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "A rendszer cserehelyfájlja (virtuális memória)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "GNOME virtuális fájlrendszer csatolási pontja" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Helyreállított fájlrendszerobjektumok" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Egyebek" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Metaadatkönyvtár Microsoft Windows rendszeren" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "A felhasználó kukája" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "A rendszer biztonsági mentési fájljai" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Javaslatok kizárása" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "A gyakran használt elemek kiválasztása a biztonsági mentés kizárásaihoz való" " hozzáadáshoz." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Alapértelmezett" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Visszaállítás az előre meghatározott kiválasztásra" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Ütemezés" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Nap:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Hét napja:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Idő:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Óra:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "óra után" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Perc:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "A Back In Time futtatása, amint a meghajtó csatlakoztatásra kerül (X naponta" " csak egyszer). Meg fog jelenni a sudo jelszó kérése." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "A Back In Time futtatása ismételten. Ez akkor hasznos, ha a számítógép nincs" " rendszeresen bekapcsolva." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Minden:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Hibakeresési üzenetek naplózásának engedélyezése" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Hibakeresés szintű üzeneteket ír a rendszernaplóba a „--debug” kapcsolón " "keresztül." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Vigyázat: ezt csak átmenetileg használja diagnosztikára, mivel nagy " "mennyiségű kimenetet állít elő." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Letiltva" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Minden indításkor vagy újraindításkor" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Percenként" msgstr[1] "{n} percenként" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Óránként" msgstr[1] "{n} óránként" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Egyéni órák" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Naponta" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Ismételten (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Ha meghajtó kerül csatlakoztatásra (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Hetente" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Havonta" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Évente" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Óra" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Nap" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Hét" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Hónap" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Az egyéni órák csak az órák vesszővel elválasztott listája lehet (például " "8,12,18,23) vagy */3 a háromóránkénti rendszeres biztonsági mentésekhez." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Pilih berkas kunci privat yang sudah ada dari tempat lain." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Buat kunci SSH baru tanpa kata sandi." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Path lengkap: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Kunci privat:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Gunakan konfigurasi SSH sistem" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Membiarkan berkas kunci tidak dipilih. Koneksi SSH akan bergantung pada " "konfigurasi klien yang ada di sistem (misalnya, ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proksi SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Host:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Pengguna:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Menyambung ke host target melalui proksi ini (juga dikenal sebagai jump " "host). Lihat \"-J\" dalam dokumentasi perintah \"ssh\" atau \"ProxyJump\" " "dalam halaman man \"ssh_config\" untuk rinciannya." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Info{ENDBOLD}: Dalam mode 'SSH terenkripsi', hanya asterisk tunggal " "atau ganda yang berfungsi (mis. {example2}). Tipe wildcard dan pola lain " "akan diabaikan (mis. {example1}). Nama berkas itu tidak dapat ditebak dalam " "mode ini karena enkripsi oleh EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Kecualikan pola, berkas, atau direktori" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Tambahkan pola" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Tambahkan berkas" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Tambahkan direktori" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Saran" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Pilih dari butir yang umum digunakan untuk ditambahkan ke daftar " "pengecualian." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Abaikan berkas yang lebih dari:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Abaikan berkas yang lebih dari {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Dengan menonaktifkan 'Mode rsync penuh', pengaturan ini hanya memengaruhi " "berkas yang baru dibuat, karena rsync memperlakukannya sebagai opsi transfer" " dan bukan aturan pengecualian. Akibatnya, berkas besar yang telah " "dicadangkan akan tetap ada dalam cadangan meskipun dimodifikasi." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Abaikan pola" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Masukkan pola pengecualian:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Untuk bantuan, lihat halaman manual rsync bagian {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Buka halaman manual rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Kecualikan berkas" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Kecualikan direktori" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Dinonaktifkan karena pola ini tidak berfungsi dalam mode 'SSH terenkripsi'." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Opsi-opsi ini untuk konfigurasi lanjutan. Ubah hanya jika Anda benar-benar " "memahami dampaknya." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Jalankan 'rsync' dengan '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "sebagai cron job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "pada host jarak jauh" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "saat melakukan pencadangan manual" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Mohon pasang 'nocache' untuk mengaktifkan opsi ini." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "pada mesin lokal" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Arahkan ulang stdout ke /dev/null dalam cronjobs." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron akan secara otomatis mengirim suatu surel dengan keluaran cronjob yang " "dilampirkan bila suatu MTA terpasang." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Arahkan ulang stderr ke /dev/null dalam cronjobs." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron akan secara otomatis mengirim suatu email dengan kesalahan cronjob yang" " dilampirkan bila suatu MTA terpasang." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/detik" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Batasi penggunaan bandwidth rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Pertahankan ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Pertahankan atribut tambahan (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Batasi ke satu sistem berkas" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Opsi harus diapit tanda kutip mis.: {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Tempelkan opsi tambahan ke rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefiks yang dijalankan sebelum setiap perintah pada host jarak jauh." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variabel perlu di-escape dengan \\$FOO. Ini tidak menyentuh rsync. Jadi " "untuk menambah awalan bagi rsync gunakan \"{example_value}\" dengan " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "baku" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Tambahkan prefiks ke perintah-perintah SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Periksa apakah host jarak jauh sedang daring" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Peringatan: jika dimatikan dan host jarak jauh tidak tersedia, ini dapat " "menyebabkan kesalahan yang aneh." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" "Periksa apakah host jarak jauh mendukung semua perintah yang diperlukan." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Peringatan: jika dimatikan dan host jarak jauh tidak mendukung semua " "perintah yang dibutuhkan, ini dapat menyebabkan beberapa kesalahan aneh." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(baku: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "dinonaktifkan" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "difungsikan" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Mode:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Di mana menyimpan cadangan" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Pengaturan SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Path:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Berkas kunci:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Kata Sandi" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Simpan Kata Sandi ke Ring Kunci" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Singgahkan Kata Sandi untuk Cron (Masalah keamanan: root dapat membaca kata " "sandi)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Tingkat Lanjut" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Path cadangan lengkap:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Penjadwalan dinonaktifkan karena tidak ditemukan instalasi cron. Silakan " "pasang cron untuk mengaktifkan pencadangan terjadwal." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Path tujuan pencadangan tidak boleh kosong." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Kata sandi enkripsi tidak boleh kosong." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Terjadi kesalahan saat mencoba masuk ke host jarak jauh. Pesan kesalahan " "berikut dikembalikan:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Untuk mengaktifkan login tanpa kata sandi, kunci SSH publik dapat disalin ke" " host jarak jauh." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Lanjutkan dengan menyalin kunci SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Kunci SSH publik tidak dapat disalin. Hal ini mungkin disebabkan oleh " "masalah koneksi atau izin." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Keaslian host \"{host}\" tidak dapat diyakinkan." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Sidik jari kunci {keytype} adalah:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "Silakan verifikasi sidik jari ini. Tambahkan ke berkas \"known_hosts\"?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Benar-benar mengubah direktori cadangan?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Tujuan pencadangan yang dipilih tidak kosong." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Itu harus kosong untuk menggunakan enkripsi." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Berkas tidak valid: Bukan kunci SSH privat" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Berkas yang dipilih ({path}) adalah kunci SSH publik. Silakan pilih berkas " "kunci privat yang sesuai sebagai pengganti (tanpa \".pub\")." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Berkas {path} sudah ada. Tidak dapat membuat kunci SSH baru dengan nama " "tersebut." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Gagal membuat kunci SSH baru dalam {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Sertakan berkas dan direktori" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" adalah symlink. Target yang ditaut tidak akan dicadangkan sampai " "target tersebut juga disertakan." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Sertakan target symlink sebagai gantinya?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Sertakan berkas" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Sertakan direktori" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Fungsikan pemberitahuan" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Nonaktifkan pencadangan saat menggunakan baterai" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Status daya tidak tersedia dari sistem" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Jalankan hanya satu pencadangan dalam satu waktu" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Pencadangan lainnya akan diblokir hingga pencadangan saat ini selesai. Ini " "adalah pengaturan global, yang berarti akan memengaruhi semua profil " "pengguna ini. Namun, pengaturan ini juga harus diaktifkan untuk semua " "pengguna lain." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Backup menggantikan berkas-berkas saat pemulihan" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "" "Lanjutkan meskipun terjadi kesalahan (simpan cadangan yang belum lengkap)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Gunakan checksum untuk mendeteksi perubahan" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Buat cadangan baru, baik ada perubahan atau tidak." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Beri peringatan jika ruang disk kosong kurang dari" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Menampilkan peringatan ketika ruang kosong pada disk tujuan pencadangan " "kurang dari nilai yang ditentukan." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Jika kebijakan Hapus & Retensi diaktifkan dan cadangan lama dihapus " "berdasarkan ruang kosong yang tersedia, nilai ini tidak boleh lebih rendah " "dari nilai yang ditetapkan dalam kebijakan tersebut." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Level Log:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nihil" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "manual pengguna" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Aturan-aturan berikut diproses dari atas ke bawah. Aturan-aturan selanjutnya" " akan menggantikan aturan-aturan sebelumnya. Lihat {manual_link} untuk " "detail dan contohnya." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Buka manual pengguna dalam peramban." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Simpan cadangan terbaru." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Cadangan data terbaru selalu disimpan dalam segala keadaan." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Perilaku itu tidak bisa diubah." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Simpan cadangan yang dinamai." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Cadangan yang telah diberi nama, selain stempel waktu biasa, akan disimpan " "dalam semua keadaan dan tidak akan dihapus." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Tahun" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Hapus cadangan yang lebih lama dari" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Hari penuh. Hari kini diabaikan." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Minggu kalender dengan Senin sebagai hari pertama. Minggu kini diabaikan." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Periode 12 bulan. Bulan kini diabaikan." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Kebijakan retensi" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Jalankan di latar belakang pada host jarak jauh." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Kebijakan retensi akan dieksekusi langsung pada mesin jarak jauh, bukan " "secara lokal. Perintah \"bash\", \"screen\", dan \"flock\" harus dipasang " "dan tersedia pada mesin jarak jauh tersebut." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" "Jika dipilih, Back In Time akan terlebih dahulu menguji mesin jarak jauh." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Hari-hari dihitung mulai dari hari ini." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Simpan semua cadangan untuk yang terakhir" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "hari terakhir." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Simpan cadangan terakhir setiap hari untuk yang terakhir" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Minggu-minggu dihitung mulai dari minggu kini yang sedang berjalan. Suatu " "minggu mulai pada hari Senin." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Simpan cadangan terakhir setiap minggu untuk yang terakhir" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "minggu terakhir." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Bulan-bulan dihitung sebagai bulan kalender mulai dari bulan kini." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Simpan cadangan terakhir setiap bulan untuk yang terakhir" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "bulan terakhir." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Tahun-tahun dihitung sebagai tahun kalender mulai dari tahun kini." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Simpan cadangan terakhir setiap tahun untuk" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "semua tahun." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "... ruang kosong kurang dari" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "... inode bebas kurang dari" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Hapus cadangan terlama jika …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Pintasan" #: qt/placeswidget.py:63 msgid "Places" msgstr "Tempat" #: qt/placeswidget.py:64 msgid "File System" msgstr "Sistem Berkas" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Cadangkan direktori" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: {profile_name} (oleh pengguna \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Lihat Catatan Log Terakhir" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Mulai {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Sedang Bekerja…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "halaman man: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Impor konfigurasi" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Impor" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Mencari…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Pilih direktori cadangan tempat asal berkas konfigurasi mesti diimpor. Path-" "nya mungkin seperti ini: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Bila direktori terletak pada drive eksternal atau jarak jauh, itu mesti " "dikait secara manual sebelumnya." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Pindai lagi" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Tampilkan direktori tersembunyi" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Tampilkan/sembunyikan direktori tersembunyi (Ctrl+H)" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Pembuatan berkas gagal di direktori ini:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Pencarian selesai." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Tampilkan log lengkap" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Hitung Mundur ke Mematikan" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Proses pencadangan telah selesai." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Batalkan Mematikan" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Matikan Sekarang" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Sistem akan dimatikan dalam {n} detik." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opsi tentang membandingkan cadangan" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Perintah:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parameter:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Gunakan %1 dan %2 untuk parameter path" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Harap atur suatu perintah diff atau tekan Batal." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Perintah \"{cmd}\" tidak bisa ditemukan pada sistem ini. Harap coba yang " "lain atau tekan Batal." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Tidak ada parameter yang diatur untuk perintah diff. Memakai nilai baku " "\"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Cadangan" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Hanya cadangan yang berbeda" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Cantumkan hanya cadangan yang sama dengan:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Pemeriksaan mendalam (lebih akurat, tetapi lambat)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Hapus" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Pilih Semua" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Bandingkan" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Pergi Ke" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opsi" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Tidak mungkin membandingkan cadangan dengan dirinya sendiri, karena " "perbandingan tersebut akan redundan." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Benar-benar menghapus {file_or_dir} di cadangan {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Benar-benar menghapus {file_or_dir} di {count} cadangan?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "PERINGATAN: Ini tidak dapat dicabut." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Kecualikan {path} dari pencadangan di masa mendatang?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Mode root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time saat ini berjalan dengan hak akses root (akses sistem penuh)" #: qt/timeline.py:69 msgid "Today" msgstr "Hari ini" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Kemarin" #: qt/timeline.py:87 msgid "This week" msgstr "Minggu ini" #: qt/timeline.py:95 msgid "Last week" msgstr "Minggu lalu" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Ini BUKAN cadangan, melainkan tampilan langsung dari berkas lokal." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Pemeriksaan terakhir {time}" backintime-1.6.1/common/po/is.po000066400000000000000000002025011514264426600165200ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-01-03 03:42+0000\n" "Last-Translator: sveinki \n" "Language-Team: Icelandic \n" "Language: is\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.9.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Aðvörun" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Aðalsnið" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Staðvært (EncFS-dulritað)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS-dulritað)" #: common/config.py:237 msgid "Local" msgstr "Staðvært" #: common/config.py:240 msgid "Local encrypted" msgstr "Staðvært dulritað" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Dulritun" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH-einkalykill" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Snið: \"{name}\"" #: common/config.py:301 #, fuzzy msgid "Backup directory is not valid." msgstr "Mappa fyrir skyndiafrit er ekki gild." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Að minnsta kosti ein mappa verður að vera undir öryggisafrit." #: common/config.py:331 common/config.py:346 #, fuzzy, python-brace-format msgid "Directory: {path}" msgstr "Endurheimta {path}" #: common/config.py:332 common/config.py:347 #, fuzzy msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "Mappan getur ekki verið innifalin í öryggisafritinu." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Áætlað udev virkar ekki með hamnum {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Mistókst að skrifa nýtt crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" #: common/configfile.py:101 msgid "Failed to save config" msgstr "Mistókst að vista stillingaskrá" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Mistókst að hlaða inn stillingaskrá" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Sniðið \"{name}\" er þegar til staðar." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Ekki er hægt að fjarlægja síðasta sniðið." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Get ekki tengt '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Grunnstillingar fyrir dulritaða möppu fundust ekki." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Búa til nýja dulritaða möppu?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Hætta við" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "Settu inn lykilorð fyrir \"{user}\"." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "Lykilorðin samsvara ekki." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Taka skyndiafrit" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Get ekki tengt '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Get ekki aftengt {mountprocess} úr {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} fannst ekki. Endilega settu það upp (t.d. með " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Tengipunktur {mntpoint} er ekki laus." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Settu inn lykilorð fyrir {mode}-notkunarsniðið \"{profile}\":" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Gat ekki installað Udev reglu fyrir prófíl {profile_id}. DBus þjónusta " "'{dbus_interface}' var ekki í boði" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Gat ekki fundið UUID fyrir {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "MISTÓKST" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Endurheimta heimildir" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Búið" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Fresta afritun þegar rafhlöður eru í notkun" #: common/snapshots.py:931 qt/app.py:393 #, fuzzy msgid "Can't find backup directory." msgstr "Finn ekki möppu fyrir skyndiafrit." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "" "Ef hún er á útskiptanlegu drifi, skaltu tengja það og ýta síðan á 'Í lagi'." #: common/snapshots.py:938 #, fuzzy, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Bið %s sekúndu." msgstr[1] "Bið %s sekúndur." #: common/snapshots.py:1005 #, fuzzy, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Mistókst að taka skyndiafritið {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Sýndu þolinmæði. Er að klára.…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Get ekki búið til möppu." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Vista stillingaskrá…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Vista aðgangsheimildir…" #: common/snapshots.py:1377 #, fuzzy, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Fann leifar af skyndiafritinu {snapshot_id} sem hægt er að halda áfram með." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Fjarlægi leifar af möppunni {snapshot_id} frá síðustu keyrslu" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Get ekki fjarlægt möppu" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "Tókst" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Einungis hluti skráaflutnings vegna villu" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Einungis hluti skráaflutnings vegna horfinna upprunaskráa (skoðaðu 'man " "rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' hætti með stöðvunarkóðanum {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Skoðaðu 'man rsync' til að sjá frekari upplýsingar" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" #: common/snapshots.py:1566 #, fuzzy msgid "Nothing changed, no new backup necessary" msgstr "Engar breytingar, engin þörf fyrir nýtt skyndiafrit" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Gat ekki endurnefnt {new_path} sem {path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Fjarlægja gömul skyndiafrit" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Reyna að halda í lágmarksmagn af lausu plássi" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Reyna að halda a.m.k. {perc} af lausum i-hnútum (inodes)" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Núna" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Get ekki tengt {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent fannst ekki. Gakktu úr skugga um að það sé uppsett." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Tókst ekki að aflæsa ssh-einkalykli. Rangt lykilorð eða að lykilorð er ekki " "tiltækt fyrir cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Fjartengd slóð er til, en er ekki mappa." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Fjartengd slóð er ekki skrifanleg." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Fjartengd slóð er ekki keyranleg." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Tókst ekki að útbúa fjartengda slóð." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Fjartengda vélin {host} styður ekki {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Fjartengda vélin {host} styður ekki harðtengi (hardlinks)" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Afritaðu ssh-dreifilykil \"{pubkey}\" yfir á fjartengdu vélina \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Settu inn lykilorð fyrir \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Markskráakerfi fyrir {path} er í NTFS-sniði, sem þekkt er fyrir ósamhæfni " "við Unix-ættuð skráakerfi." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} er ekki gild mappa." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Gerð eftirfarandi möppu mistókst:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Skrifaðgangur gæti verið takmarkaður." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Markskráakerfi fyrir {path} er á FAT-sniði sem virkar ekki með hörðum-" "tenglum. Notaðu frekar upprunalegt GNU/Linux skráakerfi." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Markskráakerfi fyrir {path} er SMB-tengd sameign. Gakktu úr skugga um að " "fjartengdi SMB-þjónninn styðji tákntengi (symlink) eða virkjaðu {copyLinks} " "í {expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Afrita tengla (afbyggja tákntengi - dereference symbolic links)" #: common/tools.py:487 msgid "Expert Options" msgstr "Ítarlegri valkostir" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Markskráakerfi fyrir {path} er í sshfs-tengd sameign. SSHFS styður ekki " "harða-tengla. Notaðu frekar 'SSH'." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Mistókst að útbúa skrá í þessari möppu:" #: qt/aboutdlg.py:51 #, fuzzy msgid "About Back In Time" msgstr "Back In &Time öryggisafritun" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 #, fuzzy msgid "Authors:" msgstr "Höfundar" #: qt/aboutdlg.py:97 #, fuzzy msgid "Translators:" msgstr "Þýðingar" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Það lítur út fyrir að {app_name} sé að keyra í fyrsta skipti þar sem engar " "grunnstillingar fundust." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Flytja inn fyrirliggjandi grunnstillingar (úr markmöppu öryggisafritunar eða" " annarri tölvu)?" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Nota breytingartíma og stærð til að skynja breytingar á skrám." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "Taka skyndiafrit (í gátsummuham)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Nota gátsummu til að skynja breytingar á skrám." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "Gera hlé á vinnslu skyndiafrits" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "Halda áfram með vinnslu skyndiafrits" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "Stöðva vinnslu skyndiafrits" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "Endurlesa lista yfir skyndiafrit" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "Fjarlægja skyndiafrit" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "Skoða síðustu atvikaskrá" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Að minnsta kosti ein mappa verður að vera undir öryggisafrit." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "Skoða síðustu atvikaskrá" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "Sýsla með notkunarsnið…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "" #: qt/app.py:548 msgid "Shutdown" msgstr "Slökkva" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "Slökkva á kerfi þegar skyndiafritun lýkur." #: qt/app.py:552 msgid "Setup language…" msgstr "Setja upp tungumál…" #: qt/app.py:556 msgid "Exit" msgstr "Hætta" #: qt/app.py:566 #, fuzzy msgid "man page: Back In Time" msgstr "Back In &Time öryggisafritun" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "" #: qt/app.py:571 #, fuzzy msgid "man page: Profiles config file" msgstr "Stillingaskrá notkunarsniða" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Breytingasaga" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ / Algengar spurningar" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "" #: qt/app.py:593 msgid "Ask a question" msgstr "Spyrja spurninga" #: qt/app.py:597 msgid "Report a bug" msgstr "Tilkynna um villu" #: qt/app.py:600 msgid "Translation" msgstr "Þýðingar" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Birtir aftur skilaboðin um þátttöku í þýðingum." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Encryption Transition (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Birtir aftur skilaboðin um fjarlægingu EncFS." #: qt/app.py:615 msgid "About" msgstr "Um forritið" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Endurheimta" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "Endurheimta valdar skrár eða möppur á upprunalega staðsetningu." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Endurheimta í …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "Endurheimta valdar skrár eða möppur á nýja staðsetningu." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Endurheimta sýnda möppu og allt innihald hennar á upprunalega staðsetningu." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "Endurheimta sýnda möppu og allt innihald hennar á nýja staðsetningu." #: qt/app.py:640 msgid "Up" msgstr "Upp" #: qt/app.py:643 msgid "Show hidden files" msgstr "Sýna faldar skrár" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "Bera saman skyndiafrit…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Útgáfukandídat" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Birtir aftur skilaboðin um þennan útgáfukandídat." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time öryggisafritun" #: qt/app.py:721 msgid "&Backup" msgstr "&Öryggisafrit" #: qt/app.py:733 msgid "&Restore" msgstr "Endu&rheimta" #: qt/app.py:739 msgid "&Help" msgstr "&Hjálp" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "" #: qt/app.py:827 msgid "Text only" msgstr "" #: qt/app.py:830 msgid "Text below icons" msgstr "" #: qt/app.py:833 msgid "Text beside icon" msgstr "" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Þessi mappa er ekki til\n" "í valda skyndiafritinu." #: qt/app.py:1005 msgid "Add to Include" msgstr "Bæta við meðfylgjandi" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Bæta við útilokun" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Ef þú lokar þessum glugga, mun Back In Time ekki geta slökkt á kerfinu þegar" " skyndiafritun lýkur." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Búið, engin öryggisafritun nauðsynleg" #: qt/app.py:1285 msgid "Working:" msgstr "Að vinna:" #: qt/app.py:1292 msgid "Working" msgstr "Að vinna" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Villa" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Sent:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Hraði:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Áætluð lok:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "&Öryggisafrit" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Endurheimta {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Endurheimta {path} í …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hæ\n" "Þú hefur núna notað Back In Time með {language}-viðmótinu nokkrum sinnum.\n" "Þýðingarnar á uppsettu útgáfunni á Back In Time fyrir {language} eru {perc} kláraðar. Sama á hvaða stigi þú ert varðandi tækniþekkingu, þá geturðu alveg lagt af mörkum við þýðingarnar og þannig einnig til Back In Time.\n" "Þú ættir að skoða {translation_platform_url} ef þig langar til að vera með. Til að fá frekari aðstoð og svör við spurningum ættirðu að heimsækja {back_in_time_project_website}.\n" "Við biðjums velvirðingar á trufluninni, þessi skilaboð munu ekki birtast aftur. Hægt er að skoða þessi skilaboð aftur hvenær sem er úr hjálparvalmyndinni.\n" "Back In Time teymið" #: qt/app.py:1709 msgid "translation platform" msgstr "þýðingakerfið" #: qt/app.py:1714 msgid "Website" msgstr "Vefsvæði" #: qt/app.py:1728 msgid "Your translation" msgstr "Þýðing þín" #: qt/app.py:1765 #, fuzzy, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Senda tölvupóst til {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Póstlisti {link_and_label}" #: qt/app.py:1774 #, fuzzy, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Póstlisti {link_and_label}" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} á vefsvæði verkefnisins." #: qt/app.py:1781 msgid "Open an issue" msgstr "Opna verkbeiðni" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" "Einnig gætirðu sent inn spurningar á aðra samskiptaleið sem þér líkar." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Aðvörun{BOLDEND}: Eyðing skráa á rót skráarkerfis gæti skemmt " "varanlega allt kerfið þitt." #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "&Öryggisafrit" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" msgstr[1] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Breytingar á tungumálastillingum munu öðlast gildi þegar þú skráir þig næst " "inn." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "Geyma nefnd skyndiafrit." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Spurning" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Fjarlægja nýjar skrár í upprunalegri möppu." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Ertu viss um að þú viljir endurheimta þetta atriði í nýju möppuna?" msgstr[1] "Ertu viss um að þú viljir endurheimta þessi atriði í nýju möppuna?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Ertu viss um að þú viljir endurheimta þetta atriði ?" msgstr[1] "Ertu viss um að þú viljir endurheimta þessi atriði?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Hafa með skrár og möppur" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Setja upp tungumál" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Þýtt: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Sjálfgefið í kerfinu" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "Nota tungumál stýrikerfis." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "Síðasta virka sýn atvikaskráningar" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Síðasta virka sýn atvikaskráningar" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Notkunarsnið:" #: qt/logviewdialog.py:86 #, fuzzy msgid "Backups:" msgstr "&Öryggisafrit" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Sía:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Villa, [I] Upplýsingar, [C] Breyta" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "afkóða slóðir" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Allt" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Breytingar" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Villur" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Upplýsingar" msgstr[1] "Upplýsingar" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Sýsla með notkunarsnið" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Breyta" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Bæta við" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Fjarlægja" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Almennt" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "Ta&ka með" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Undanskilja" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "Valk&ostir" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Ítarlegri &valkostir" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Endurheimta stillingaskrá" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Nýtt snið" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Endurnefna snið" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Ertu viss um að þú viljir eyða sniðinu \"{name}\" ?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Gera hlé á vinnslu skyndiafrits" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Undanskilja skrá" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Öryggisafritunarmöppur" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Get ekki fjarlægt möppu" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Sýna faldar skrár" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Stöðva vinnslu skyndiafrits" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Undanskilja möppu" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "sjálfgefið" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Vinnuáætlun" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dagur:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Vikudagur:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Tími:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Klukkustundir:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Hverjar:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Virkja atvikaskráningu villuleitarskilaboða" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Óvirkt" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Við hverja ræsingu/endurræsingu" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Á {n} mínútu fresti" msgstr[1] "Á {n} mínútna fresti" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Á klukkustundar fresti" msgstr[1] "Á {n} klukkustunda fresti" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Sérsniðnar klukkustundir" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Hvern dag" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Endurtekið (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Þegar drif er tengt (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Vikulega" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Mánaðarlega" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Árlega" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "klukkustund(ir)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "dag(a)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "viku(r)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "mánuð(ir)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Seleziona un file di chiave privata esistente da qualche altra parte." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Crea una nuova chiave SSH senza frase segreta." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Percorso completo: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Chiave privata:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Usa la configurazione SSH di sistema" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Lascia il file chiave non selezionato. Le connessioni SSH si baseranno sulla" " configurazione client di sistema esistente (ad es., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proxy SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Host:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Porta:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Utente:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Connetti all'host destinazione attraverso questo proxy (conosciuto anche " "come jump host). Per i dettagli, consulta \"-J\" nella documentazione del " "comando \"ssh\" o \"ProxyJump\" nella pagina del manuale." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Info{ENDBOLD}: nella modalità 'SSH cifrato' funzionano solo gli " "asterischi singoli e doppi (es. {example2}). Gli altri tipi di caratteri " "jolly e pattern saranno ignorati (es. {example1}). In questa modalità i nomi" " di file non sono prevedibili a causa della cifratura di EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Escludi pattern, file o cartelle" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Aggiungi pattern" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Aggiungi file" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Aggiungi cartelle" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Suggerimenti" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Seleziona tra gli elementi comunemente utilizzati da aggiungere all'elenco " "delle esclusioni." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Escludi file più grandi di:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Escludi file più grandi del valore in {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Con la 'Modalità rsync completo' è disabilitata, questa impostazione avrà " "effetto solo sui nuovi file, perché rsync la tratta come un'opzione di " "trasferimento, non come una regola di esclusione. Per questo motivo i file " "già sottoposti a backup in precedenza rimarranno nei backup anche se sono " "stati modificati." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Pattern di esclusione" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Digita un pattern di esclusione:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Per aiuto, vedi la sezione {link} della pagina di manuale di rsync." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Aprire la pagina di manuale per rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Escludi file" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Escludi cartelle" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Disabilitato perché questo pattern non è funzionante in modalità 'SSH " "cifrato'." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Queste opzioni sono pensate per le configurazioni avanzate. Modificale solo " "sei pienamente consapevole delle loro implicazioni." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Esegui 'rsync' con '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "come cron job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "sull'host remoto" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "quando si crea un backup manuale" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Installa 'nocache' per abilitare questa opzione." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "sulla macchina locale" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Redirigi stdout verso /dev/null nei cronjob." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron invierà automaticamente una email con allegato il registro dei cronjob " "se un MTA è installato." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Redirigi stderr verso /dev/null nei cronjob." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron invierà automaticamente una email con allegato il registro errori dei " "cronjob se un MTA è installato." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Limita la banda utilizzata da rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Preserva ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Preserva attributi estesi (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Limita a un file system" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Le opzioni devono essere racchiuse tra virgolette, es. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Passa opzioni aggiuntive a rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefisso da eseguire prima di ciascun comando sull'host remoto." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Le variabili necessitano di escaping con \\$FOO. Questo non riguarda rsync. " "Quindi per aggiungere un prefisso per rsync usa \"{example_value}\" con " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "default" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Aggiungi prefisso ai comandi SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Controlla se l'host remoto è online" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Attenzione: se disabilitato e l'host remoto non è disponibile, questo " "potrebbe portare ad alcuni errori strani." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Controlla se l'host remoto supporta tutti i comandi necessari." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Attenzione: se disabilitato e l'host remoto non supporta tutti i comandi " "necessari, questo potrebbe portare ad alcuni strani errori." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(predefinito: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "disabilitato" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "abilitato" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modalità:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Dove salvare i backup" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Impostazioni di SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Percorso:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "File della chiave:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Password" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Salva la password nel gestore delle password" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Salva la password per Cron (problema di sicurezza: l'utente root può leggere" " la password)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avanzate" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Percorso completo per i backup:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "La pianificazione è stata disabilitata perchè cron non risulta installato. " "Installare cron per abilitare i backup pianificati." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Il percorso di destinazione del backup non può essere vuoto." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "La password di cifratura non può essere vuota." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Si è verificato un errore durante il tentativo di accesso all'host remoto. È" " stato restituito il seguente messaggio di errore:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Per abilitare il login senza password, la chiave pubblica SSH può essere " "copiata nell'host remoto." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Vuoi procedere con la copia della chiave SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Impossibile copiare la chiave SSH pubblica. Potrebbe essere dovuto a un " "problema di connessione o di permessi." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "L'autenticità dell'host \"{host}\" non può essere stabilita." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "L'impronta digitale della chiave {keytype} è:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Verifica questa impronta digitale. Vuoi aggiungerla al file 'known_hosts'?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Vuoi cambiare la cartella del backup?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "La destinazione selezionata per il backup non è vuota." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Per utilizzare la cifratura deve essere vuoto." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "File non valido: non è una chiave privata SSH" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Il file selezionato ({path}) è una chiave pubblica SSH. Scegli il file della" " chiave privata corrispondente (senza estensione \".pub\")." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Il file {path} esiste già. Impossibile creare una nuova chiave SSH con tale " "nome." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Impossibile creare una nuova chiave SSH in {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Includi file e cartelle" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" è un collegamento simbolico. La destinazione del collegamento non" " sarà copiata nel backup se non inclusa esplicitamente." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Vuoi includere invece la destinazione del collegamento simbolico?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Includi file" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Includi cartelle" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Abilita le notifiche" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Disabilita i backup quando usi la batteria" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Impossibile stabilire la modalità di alimentazione" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Esegui solo un backup alla volta" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Gli altri backup saranno bloccati finché il backup attuale non sarà " "completato. Questa è un'opzione globale, pertanto avrà effetto su tutti i " "profili di questo utente. Tuttavia, devi attivare quest'opzione anche per " "gli altri utenti." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Backup dei file sostituiti durante il ripristino" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Continua in caso di errore (mantieni backup incompleti)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Usa il checksum per rilevare i cambiamenti" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Crea un nuovo backup in presenza di modifiche o meno." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Avvisa se lo spazio libero sul disco scende sotto" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Mostra un avviso quando lo spazio libero sul disco di destinazione del " "backup è inferiore al valore specificato." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Se la politica di rimozione e conservazione è abilitata e i vecchi backup " "vengono rimossi in base allo spazio libero disponibile, questo valore non " "può essere inferiore al valore impostato nella politica." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Livello di log:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nessuno" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "manuale utente" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Le regole seguenti sono elaborate dall'alto in basso. Le regole successive " "scavalcano le regole precedenti. Vedi il {manual_link} per dettagli ed " "esempi." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Apri il manuale utente nel browser." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Mantieni il backup più recente." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Il backup più recente è mantenuto in ogni caso." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Il comportamento non può essere modificato." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Mantieni i backup con un nome." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "I backup che, in aggiunta alla consueta marca temporale, hanno ricevuto un " "nome saranno mantenuti in ogni caso e non saranno rimossi." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Anno(i)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Rimuovi i backup più vecchi di" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Giorni interi. Il giorno attuale è ignorato." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Settimane di calendario con lunedì come primo giorno. La settimana attuale è" " ignorata." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Periodi di 12 mesi. Il mese attuale è ignorato." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Politica di conservazione" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Esegui in sottofondo sull'host remoto." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "La procedura di rimozione sarà eseguita direttamente nella macchina remota, " "non localmente. I comandi \"bash\", \"screen\" e \"flock\" devono essere " "installati e disponibili sulla macchina remota." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" "Se selezionato, Back In Time effettuerà innanzi tutto un test della macchina" " remota." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "I giorni sono contati a partire da oggi." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Mantieni tutti i backup degli ultimi" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "giorno/i." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Mantieni l'ultimo backup per ogni giorno per gli ultimi" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Le settimane sono contate a partire dalla settimana attuale in corso. Una " "settimana inizia il lunedì." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Mantieni l'ultimo backup per ogni settimana per le ultime" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "settimana/e." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "I mesi sono contati come mesi di calendario a partire dal mese attuale." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Mantieni l'ultimo backup per ogni mese per gli ultimi" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "mese/i." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" "Gli anni sono contati come anni di calendario a partire dall'anno attuale." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Mantieni l'ultimo backup per ogni anno per" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "tutti gli anni." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… lo spazio libero è inferiore a" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… gli inode liberi sono inferiori a" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Rimuovi i vecchi backup se…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Per eseguire Back In Time come root è richiesta l'autenticazione." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Per modificare le pianificazioni di backup attivate dalle connessioni a " "dispositivi di archiviazione esterni è richiesta l'autenticazione." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Collegamenti" #: qt/placeswidget.py:63 msgid "Places" msgstr "Risorse" #: qt/placeswidget.py:64 msgid "File System" msgstr "File System" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Cartelle di backup" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profilo: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profilo: {profile_name} (dall'utente \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Visualizza ultimo log" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Avvia {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Lavoro in corso…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "pagina del manuale: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importa configurazione" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Nessuna cartella selezionata" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importa" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Ricerca…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Seleziona la cartella dei backup da cui importare la configurazione. Il " "percorso potrebbe somigliare a: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Se la cartella si trova su un disco esterno o remoto, deve essere prima " "montato manualmente." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Analizza nuovamente" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Mostra le cartelle nascoste" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Mostra/nascondi le cartelle nascoste (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Nessun configurazione trovata in questa cartella" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Ricerca completata." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Mostra il registro completo" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Conto alla rovescia per lo spegnimento" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Il backup è terminato." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Annulla lo spegnimento" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Spegni subito" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Il sistema si spegnerà tra {n} secondo." msgstr[1] "Il sistema si spegnerà tra {n} secondi." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opzioni relative al confronto tra backup" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Comando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametri:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Usa %1 e %2 come parametri del percorso" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Si prega di impostare un comando diff o premere Annulla." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Il comando \"{cmd}\" non è stato trovato nel sistema. Si prega di provarne " "un altro o premere Annulla." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Nessun parametro impostato per il comando diff. Uso il valore predefinito " "\"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Backup" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Solo backup diversi" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Mostra solo i backup uguali a:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Controllo approfondito (più accurato ma più lento)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Elimina" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Seleziona tutte" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Confronta" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Vai a" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opzioni" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Impossibile confrontare un backup con se stesso, poiché il confronto sarebbe" " ridondante." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Vuoi davvero eliminare {file_or_dir} nel backup {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Vuoi davvero eliminare {file_or_dir} in {count} backup?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "ATTENZIONE: Questa operazione è irreversibile." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Vuoi escludere {path} dai backup futuri?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Modalità Root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time è attualmente in esecuzione con i privilegi di root (accesso " "completo al sistema)" #: qt/timeline.py:69 msgid "Today" msgstr "Oggi" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Ieri" #: qt/timeline.py:87 msgid "This week" msgstr "Questa settimana" #: qt/timeline.py:95 msgid "Last week" msgstr "Scorsa settimana" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Questo NON è un backup, bensì una vista attuale dei tuoi file locali." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Ultimo controllo {time}" backintime-1.6.1/common/po/ja.po000066400000000000000000002471651514264426600165160ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © AmaseCocoa (甘瀬ここあ) # SPDX-FileCopyrightText: © Ayako # SPDX-FileCopyrightText: © Sadaharu Wakisaka # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-05 17:33+0000\n" "Last-Translator: buhtz \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "このプロジェクトで使われる全てのライセンスは {dir_link} " "ディレクトリにあります。ファイル単位のライセンス及び著作権をSPDXメタデータから取得するには、{readme_link} を参照してください。" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "警告" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "メインプロファイル" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "ローカル (EncFS暗号化)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS暗号化)" #: common/config.py:237 msgid "Local" msgstr "ローカル" #: common/config.py:240 msgid "Local encrypted" msgstr "ローカル暗号化" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "暗号" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH 秘密鍵" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "プロファイル: 「{name}」" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "バックアップフォルダが無効です。" #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "最低でも一個のディレクトリをバックアップのために指定してください。" #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "ディレクトリ: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "このディレクトリはバックアップ先の一部であるため、バックアップに含めることはできません。" #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "「空き容量が以下になった場合に最古のバックアップを削除する」の値 ({val_one}) は、「空きディスク容量が以下になった場合に警告する」のしきい値" " ({val_two}) 以下でなければなりません。" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "バックアップ削除制限が警告制限を超えないよう設定を調整してください。" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "{mode} モード では、udev スケジュールは使用できません" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "新しい crontab の書き込みに失敗しました。" #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "crontab コマンドは利用可能ですが Cron は稼働していません。予定されたバックアップ job は実行されないでしょう。 Cron " "はインストールされているようですが、サービスとして起動されてない可能性があります。 2つのコマンド 'systemctl enable cron' と " "'systemctl start cron' を実行してみてください、もしくは使用している GNU/Linux " "ディストリビューションのサポートに相談するのもよいでしょう。" #: common/configfile.py:101 msgid "Failed to save config" msgstr "設定を保存できませんでした" #: common/configfile.py:137 msgid "Failed to load config" msgstr "設定を読み込めませんでした" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "プロファイル 「{name}」 はすでに存在しています。" #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "最後に残ったプロファイルを削除することはできません。" #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "「{command}」 をマウントできません" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "フォルダの暗号化に関する設定がみつかりません。" #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "新しい暗号化されたフォルダを作成しますか?" #: common/encfstools.py:204 msgid "Cancel" msgstr "取消" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "EncFSのパスワードを再入力してください。" #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFSのパスワードが一致しません。" #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "スナップショット取得" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "暗号化されたパス「{command}」の初期化に失敗しました" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "{mountprocess} を {mountpoint} からアンマウントできません。" #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "{command} は見つかりません。例を参考にインストールしてください。例 「{installcommand}」" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "マウントポイント {mntpoint} が空ではありません。" #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "{mode}プロファイル 「{profile}」 のパスワードを入力してください:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "プロファイル {profile_id} のUdevルールをインストールできませんでした。 DBusサービス '{dbus_interface}' " "が有効ではありません。" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "{path} には該当の UUID がありませんでした" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "失敗" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "パーミッションを復元" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "完了" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "以下のインクルードリストのエントリには、バックアップソースに対応するファイルまたはディレクトリが存在しません:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "バッテリー動作のときは延期する" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "バックアップフォルダが見つかりません。" #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "もしリムーバブルドライブ上にあるのなら、それを接続してください。" #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "{n} 秒待機中。" #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "バックアップ {snapshot_id} の作成に失敗しました。" #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "最終処理を行っています、少々お持ちください…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "フォルダを作成できません。" #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "設定ファイルの保存…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "パーミッションを保存…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "以前に作成した継続使用できるバックアップ {snapshot_id} がありました。" #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "前回の作業で作成した不完全な {snapshot_id} フォルダを削除しています" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "フォルダを削除できません" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "バックアップを作成中" #: common/snapshots.py:1517 msgid "Success" msgstr "成功" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "エラーによる部分的な転送" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "ソースファイルの消失による部分的な転送 (man rsync を参照)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' は終了コード {exit_code} で終了しました" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "詳細は'man rsync'を参照" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "ネガティブの rsync 終了コードはシグナル番号です、'kill -l' および 'man kill' を参照してください" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "変更箇所がないので新しいバックアップは必要ありません" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "{path} を {new_path} に変更できません。" #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "古いバックアップを削除するためのルールの適用" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "保持ポリシーの適用" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "最小限のフリースペースの確保を試みる" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "最低限でも{perc}分のフリーなinodeを確保中です" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "現在" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "{sshfs} をマウントできません" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agentが見つかりません。インストールされているか確認してください。" #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "ssh の秘密鍵を解除できませんでした。パスワードが間違っているか、cron で使用できないパスワードです。" #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "リモートパスは存在するが、ディレクトリではない。" #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "リモートパスは書き込みできません。" #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "リモートパスは実行可能ではありません。" #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "フォルダを作成できません。" #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "リモートホスト {host} は {command} をサポートしていない" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "ホスト {host} でのコマンド確認中に不明なエラーが発生しました" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "リモートホスト {host} がハードリンクをサポートしていません" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "公開鍵 「{pubkey}」 をリモートホスト 「{host}」 にコピーしてください。" #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "ユーザ 「{user}」のパスワードを入力してください。" #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "{path} の保存先ファイルシステムは NTFS でフォーマットされていて、これはUnix-" "styleのファイルシステムと非互換であることが知られています。" #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} は有効なディレクトリではありません。" #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "以下のディレクトリの作成に失敗しました:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "書き込み権限が限定されているようです。" #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "{path} の保存先ファイルシステムは、ハードリンクをサポートしない FAT でフォーマットされています。ネイティブの GNU/Linux " "ファイルシステムを使用してください。" #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "{path} の保存先ファイルシステム は SMB マウントされた共有です。 " "リモートSMBサーバーがシンボリックリンクをサポートしているか確認してください、または {expertOptions} で {copyLinks} " "を有効化してください。" #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "リンクをコピーする(シンボリックリンクの参照解除)" #: common/tools.py:487 msgid "Expert Options" msgstr "上級者向けオプション" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "{path} の保存先ファイルシステムは sshfs の共有マウントです。 sshfs はハードリンクをサポートしていません 。代わりにモード " "「SSH」 を使用してください。" #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "以下のディレクトリへのファイル作成が失敗しました:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Back In Time について" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "著作権:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "開発者:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "翻訳:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "AmaseCocoa (甘瀬ここあ) \n" "Ayako\n" "Sadaharu Wakisaka " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "この言語の翻訳者一覧はありません。" #: qt/aboutdlg.py:116 msgid "this link" msgstr "このリンク" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "全言語の翻訳者一覧は {thislink} にあります。" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "開発元サイト" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "ユーザーマニュアル" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "ユーザーマニュアルをブラウザで開く(ローカルファイルがある場合はローカルファイル、ない場合はオンライン)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}バージョン{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "{app_name} は設定が見つからないため、初めて実行されているようです。" #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "既存の設定をバックアップ場所または別のコンピューターからインポートしますか?" #: qt/app.py:395 msgid "Then press OK." msgstr "次に「OK」を押してください。" #: qt/app.py:499 msgid "Create a backup" msgstr "バックアップを作成" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "ファイルの変更検出には、変更時間とサイズを使用します。" #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "バックアップを作成(チェックサムモード)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "変更の検出にチェックサムを使用する。" #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "バックアップの作成を一時停止する" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "バックアップの作成を再開する" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "バックアップの作成を停止する" #: qt/app.py:520 msgid "Refresh backup list" msgstr "バックアップのリストを更新" #: qt/app.py:524 msgid "Name backup" msgstr "バックアップに名前をつける" #: qt/app.py:528 msgid "Remove backup" msgstr "バックアップの削除" #: qt/app.py:532 msgid "Open backup log" msgstr "バックアップログを開く" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "選択したバックアップのログを表示します。" #: qt/app.py:536 msgid "Open last backup log" msgstr "最後のバックアップログを開く" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "最新のバックアップのログを表示する。" #: qt/app.py:540 msgid "Manage profiles…" msgstr "プロファイルの管理…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "ユーザーコールバックの編集" #: qt/app.py:548 msgid "Shutdown" msgstr "電源を切る" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "バックアップの作成終了後に電源を切る。" #: qt/app.py:552 msgid "Setup language…" msgstr "言語設定…" #: qt/app.py:556 msgid "Exit" msgstr "終了" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man ページ: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Back In Time (backintime)の man ページを表示する" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man ページ: 設定ファイルのプロファイル" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "設定ファイル (backintime-config) のプロファイルに関する man ページを表示する" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Back In Time の開発サイトをブラウザで開く" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "変更履歴" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "変更履歴を開く(ローカルで利用可能な場合はローカルから、そうでない場合はウェブから)" #: qt/app.py:589 msgid "FAQ" msgstr "よくある質問" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "よくある質問 (FAQ) をブラウザで開く" #: qt/app.py:593 msgid "Ask a question" msgstr "質問する" #: qt/app.py:597 msgid "Report a bug" msgstr "バグを報告する" #: qt/app.py:600 msgid "Translation" msgstr "翻訳" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "翻訳への参加に関するメッセージを再度表示。" #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "暗号化の移行 (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "EncFS 削除に関するメッセージを再度表示。" #: qt/app.py:615 msgid "About" msgstr "バージョン情報" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "復元" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "選択したファイルまたはディレクトリを元の場所に復元します。" #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "復元…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "選択したファイルまたはディレクトリを新しい場所に復元します。" #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "現在表示されているディレクトリとそのすべての内容を元の場所に復元します。" #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "現在表示されているディレクトリとその全内容を新しい場所に復元します。" #: qt/app.py:640 msgid "Up" msgstr "上のフォルダへ" #: qt/app.py:643 msgid "Show hidden files" msgstr "不可視ファイルを表示" #: qt/app.py:646 msgid "Compare backups…" msgstr "バックアップを比較…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "リリース候補版" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "リリース候補版についてのメッセージを再度表示。" #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "バックアップ(&B)" #: qt/app.py:733 msgid "&Restore" msgstr "復元(&R)" #: qt/app.py:739 msgid "&Help" msgstr "ヘルプ(&H)" #: qt/app.py:790 msgid "Systray Icon" msgstr "システムトレイアイコン" #: qt/app.py:796 msgid "Automatic" msgstr "自動" #: qt/app.py:800 msgid "Light icon" msgstr "ライトアイコン" #: qt/app.py:801 msgid "Dark icon" msgstr "ダークアイコン" #: qt/app.py:824 msgid "Icons only" msgstr "アイコンのみ" #: qt/app.py:827 msgid "Text only" msgstr "テキストのみ" #: qt/app.py:830 msgid "Text below icons" msgstr "テキストをアイコンの下に" #: qt/app.py:833 msgid "Text beside icon" msgstr "テキストをアイコンの横に" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "現在選択されているバックアップには\n" "このフォルダはありません。" #: qt/app.py:1005 msgid "Add to Include" msgstr "含むフォルダを指定" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "除外するフォルダを指定" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "このウインドウを閉じると Back In Time はバックアップの作成終了時に電源を切ることができなくなります。" #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "本当に閉じますか?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "完了、バックアップの必要はありませんでした" #: qt/app.py:1285 msgid "Working:" msgstr "作業中:" #: qt/app.py:1292 msgid "Working" msgstr "作業中" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "エラー" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "送信:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "速度:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "完了予想時間:" #: qt/app.py:1490 msgid "Backup:" msgstr "バックアップ:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "{path} を復元" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "{path} を復元…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "こんにちは\n" "これまでに Back In Time {language} 版をご利用いただいた皆様へ。\n" "インストールいただいた Back In Time {language} 版のバージョンでは、{perc} まで翻訳が完了しています。技術的な知見の有無に関わらず、翻訳にご協力いただくことで Back In Time に貢献いただくことが可能です。\n" "ご協力いただける場合は {translation_platform_url} をご覧ください。その他のヘルプやご質問は {back_in_time_project_website} をご覧ください。\n" "突然のメッセージを失礼致しました。このメッセージは今後表示されませんが、ヘルプメニューからいつでもご覧いただけます。\n" "Back In Time チーム一同" #: qt/app.py:1709 msgid "translation platform" msgstr "翻訳プラットフォーム" #: qt/app.py:1714 msgid "Website" msgstr "ウェブサイト" #: qt/app.py:1728 msgid "Your translation" msgstr "翻訳へのご協力のお願い" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Mastodon にある Fediverse で: {link_and_label}。" #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "{link_and_label}宛のメール。" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "メーリングリスト {link_and_label}。" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "開発サイトに {link_and_label}。" #: qt/app.py:1781 msgid "Open an issue" msgstr "議題を伝える" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "その他に、好みのチャンネルを選択することもできます。" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "このバーションの Back In Time は公開予定版で次の公式リリースに向けて安定性のテストに使用されます。\n" "個人情報等のユーザーデータは送信されません、しかしながら、 Back In Time チームは公開予定版が使用されているかどうかや、このようなプレリリース版を提供することに意味があるのかどうか知りたいと思っています。\n" "それ故に、もし何も問題なくてもフィードバックをくださることをお願いしたいのです。 たった数分間のテストランでも十分に有益な情報となり得ます。\n" "以下は送信要領です:\n" "{contact_list}\n" "このバージョンではメッセージは再度表示されません、が、ヘルプメニューからいつでもアクセスできます。\n" "Back In Time をご愛用いただき、多大なる支援を頂いて誠に感謝申し上げます。\n" "Back In Time チーム一同" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "宛先には {free} の空き領域しかなく、これは設定されたしきい値 {threshold} を下回っています。" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "バックアップを続行しますか?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "{path} にあるより新しいファイルは削除されます。続行しますか?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "元のディレクトリにあるより新しいファイルは削除されます。続行しますか?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "{BOLD}警告{BOLDEND}: ファイルシステムルートのファイルを削除すると、システム全体が壊れる可能性があります。" #: qt/app.py:2167 msgid "Backup name" msgstr "バックアップ名" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "このバックアップを削除しますか?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "言語設定は、Back In Time を再起動した後に有効になります。" #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "バージョン管理されたバックアップ (ルート)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "バージョン管理されたバックアップのためのユーザーフレンドリーなGUI(ディスク使用量を削減)(rootモード)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "バージョン管理されたバックアップ" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "バージョン管理されたバックアップのための使いやすいGUIで、ディスク使用量を削減します" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "質問" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "ローカル要素を上書きまたは削除する前に、末尾に {suffix} を付加したバックアップコピーを作成します。" #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "復元をする際に、より新しいファイルがある場合は拡張子 {suffix} がファイル名に付与されます。もし不要の場合は次のコマンドで削除してください :" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "存在しない要素、または宛先にある要素よりも新しい要素のみを復元します。「{rsync_example}」オプションを使用します。" #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "元のフォルダ内の新しいファイルを削除する。" #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "選択したファイルやフォルダを元の保存先に復元して、バックアップに含まれないファイルやフォルダを削除します。これによってバックアップ作成時に除外されたファイルやフォルダが" " 削除されるので、十分注意してください。" #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "本当にこれらを新しいディレクトリに復元しますか?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "本当にファイルを復元しますか?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "ユーザーコールバック: 「{filename}」" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "ユーザーコールバックスクリプトは、最初の行にシェーバンを含める必要があります(例:{example})。" #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "隠しファイルと隠しディレクトリを表示/非表示にする (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "言語設定" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "翻訳済み: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "標準設定" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "オペレーティングシステムの言語を使用する。" #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "バックアップログを表示" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "最終ログを表示" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "プロファイル:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "バックアップ:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "フィルタ:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] エラー、 [I] インフォメーション、 [C] 変更点" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "復号先" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "全て" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "変更点" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "エラー" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "情報" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync 転送の失敗 (実験的)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "プロファイルの管理" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "編集" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "追加" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "削除" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "一般(&G)" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "追加リスト(&I)" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "除外リスト(&E)" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "削除と保持の条件(&R)" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "オプション(&O)" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "上級者向けオプション(&X)" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "設定の復元" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "新規プロファイル" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "プロファイルをリネーム" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "プロファイル \"{name}\" を削除しますか?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "シンボリックリンクをファイルとしてコピーする" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "シンボリックリンクを実際のファイルまたはディレクトリとしてバックアップにコピーします。すべてのリンクをコピーするか、ソース外を指すリンクのみをコピーするかを選択します。" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "このオプションはバックアップサイズを増加させる可能性があります。" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "デフォルトで無効化されています。" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "すべてのシンボリックリンクは、それらが指す実際のファイルまたはディレクトリに置き換えられます。これによりバックアップサイズが増加し、同じファイルが複数回保存される可能性があります。" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "`rsync --copy-links` を使用します。" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "外部のみ" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "バックアップソース外を指すリンクのみがファイルとしてコピーされます。これによりバックアップサイズが増加し、同じファイルが複数回保存される可能性があります。" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "`rsync --copy-unsafe-links` を使用します。" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "エディタおよびオフィスの一時ファイル" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacsのバックアップファイル" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacsの自動保存ファイル" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Vimのスワップファイル" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Officeの一時ファイル" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice およびその他の OpenDocument エディタはファイルをロックします" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "サムネイルと一時的な画像" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "GNU/Linuxおよびその他のUnix系OSにおけるサムネイルキャッシュ" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Windows上のサムネイルデータベース" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "MacOS上のメタデータディレクトリ" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "アプリケーション固有のロック" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discordアプリケーションロックファイル" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord セッションロックファイル" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Mozilla Firefox および Thunderbird のロックファイル" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "キャッシュと一時ディレクトリ" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "ユーザーアプリケーションキャッシュ" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "システム一時ディレクトリ" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "DebianベースのGNU/Linuxディストリビューション向けパッケージキャッシュ" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Flatpakアプリおよびランタイムリポジトリ" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "システム実行時ディレクトリ" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "カーネルとプロセス情報" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "デバイスおよびその他のハードウェア情報(sysfsインターフェース)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "デバイスノード" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "ランタイムシステムファイル" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "その他の非永続的" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "現在マウントされているファイルシステムのリスト" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "システムスワップファイル(仮想メモリ)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "GNOME仮想ファイルシステムのマウントポイント" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "回復されたファイルシステムオブジェクト" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "その他" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Microsoft Windows 上のメタデータ ディレクトリ" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "ユーザーごみ箱" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "システムバックアップファイル" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "提案を除外する" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "バックアップ除外項目に追加する、よく使用するアイテムを選択してください。" #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "デフォルト" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "事前定義された選択にリセット" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "スケジュール" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "日:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "曜日:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "時間:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "時間:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "毎正時後" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "分:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "ドライブが接続されたら Back In Time を実行 (ただし X日に一回)。 sudo のパスワードプロンプトが表示されるでしょう。" #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "Back In Time を繰り返し実行する。コンピュータを定期的に起動していない場合に便利です。" #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "毎:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "デバッグメッセージのログを有効化" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "デバッグレベルメッセージを 「--debug」 経由でシステムログに書き込む。" #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "注意: これは非常に大量の出力を発生させるので、臨時の診断に使用してください。" #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "無効" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "起動/再起動毎に" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "毎{n}分ごと" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "毎{n}時間ごと" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "カスタム時間" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "毎日" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "繰り返し (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "ドライブが接続されたとき(udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "毎週" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "毎月" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "毎年" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "時間" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "日" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "週" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "カ月" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "カスタム時間には、カンマ区切りの時間リスト(例:8,12,18,23)または */3 3時間ごとの定期バックアップのみを指定できます。" #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "" #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "" #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "პირადი გასაღები:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH პროქსი" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "ჰოსტი:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "პორტი:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "მომხმარებელი:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "ფაილების დამატება" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "საქაღალდეების დამატება" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "მინიშნებები" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "" #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "ფაილების გამორიცხვა" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "საქაღალდეების გამორიცხვა" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "" #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "ნაგულისხმევი" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "" #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "გამორთულია" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "ჩართულია" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "რეჟიმი:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH-ის მორგება" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "ბილიკი:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "გასაღების ფაილი:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "პაროლი" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "დამატებით" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "" #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "" #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "ფაილების ჩასმა" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "საქაღალდეების ჩასმა" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "გაფრთხილებების ჩართვა" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "ჟურნალის დონე:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "არცერთი" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "მალსახმობები" #: qt/placeswidget.py:63 msgid "Places" msgstr "ადგილები" #: qt/placeswidget.py:64 msgid "File System" msgstr "ფაილური სისტემა" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "მუშავდება…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "კონფიგურაციის შემოტანა" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "შემოტანა" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "ძებნა…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "ძებნა დასრულდა." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "" #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "ბრძანება:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "პარამეტრები:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "" #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "მარქაფები" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "წაშლა" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "ყველას მონიშვნა" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "შედარება" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "გადასვლა" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "მორგება" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "" #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "" #: qt/statusbar.py:85 msgid "Root mode" msgstr "" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "დღეს" #: qt/timeline.py:77 msgid "Yesterday" msgstr "გუშინ" #: qt/timeline.py:87 msgid "This week" msgstr "ეს კვირა" #: qt/timeline.py:95 msgid "Last week" msgstr "წინა კვირაში" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "" backintime-1.6.1/common/po/ko.po000066400000000000000000002224661514264426600165320ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-03-10 15:41+0000\n" "Last-Translator: darkcircle \n" "Language-Team: Korean \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.10.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "경고" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "메인 프로파일" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "로컬 (EncFS 암호화)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS 암호화)" #: common/config.py:237 msgid "Local" msgstr "로컬" #: common/config.py:240 msgid "Local encrypted" msgstr "로컬 암호화" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "암호화" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH 개인 키" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "프로필: \"{name}\"" #: common/config.py:301 #, fuzzy msgid "Backup directory is not valid." msgstr "스냅샷 폴더가 올바르지 않습니다." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "백업을 위해서는 적어도 하나의 디렉토리가 선택되어야 합니다." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "디렉터리: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "이 디렉터리는 백업 저장소 자체의 일부이므로 백업 대상에 넣어둘 수 없습니다." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "udev 일정이 {mode} 모드로 동작하지 않습니다" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "새로운 크론탭 작성에 실패했습니다." #: common/config.py:1577 #, fuzzy msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "크론탭(crontab) 명령어가 가능하지만 크론(Cron)이 작동하지 않습니다. 스케쥴 백업이 작동하지 않을 것입니다. 크론(Cron)이" " 설치 되어있을 수도 있지만 활성화가 안되어있을 수 도 있습니다. 다음 명령어 \"systemctl enable cron\"를 시도하거나" " 당신의 GNU/Linux 배포판에 도움을 요청해보세요." #: common/configfile.py:101 msgid "Failed to save config" msgstr "설정 저장에 실패했습니다" #: common/configfile.py:137 msgid "Failed to load config" msgstr "설정 불러오기에 실패했습니다" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "\"{name}\" 프로필이 이미 있습니다." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "마지막 프로필은 제거할 수 없습니다." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "'{command}' 명령을 마운트할 수 없습니다" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "암호화 디렉터리 설정을 찾을 수 없습니다." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "새 암호화 폴더를 만드시겠습니까?" #: common/encfstools.py:204 msgid "Cancel" msgstr "취소" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "\"{user}\" 암호를 입력하십시오." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "암호가 일치하지 않습니다." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "스냅샷 생성하기" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "'{command}' 명령을 마운트할 수 없습니다" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "{mountpoint}(에)서 {mountprocess}을(를) 마운트 해제할 수 없습니다." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "{command}을(를) 찾을 수 없습니다. {installcommand} 명령으로 설치하십시오" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "{mntpoint} 마운트 지점이 비어 있지 않습니다." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "\"{profile}\" {mode} 프로파일의 암호를 입력하십시오:" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "{profile_id} 프로필에 Udev 규칙을 설치할 수 없습니다. DBus 서비스 '{dbus_interface}'을(를) 사용할 수" " 없습니다" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "{path}의 UUID를 찾을 수 없습니다" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "실패" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "권한 복원" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "완료" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "배터리를 사용하는 동안 백업 연기" #: common/snapshots.py:931 qt/app.py:393 #, fuzzy msgid "Can't find backup directory." msgstr "스냅샷 디렉터리를 찾을 수 없습니다." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "이동식 드라이브에 있다면 우선 연결하십시오." #: common/snapshots.py:938 #, fuzzy, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "%s초 기다립니다." #: common/snapshots.py:1005 #, fuzzy, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "{snapshot_id} 스냅샷을 생성하지 못했습니다." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "잠시만 기다려주세요. 마무리 중…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "디렉터리를 만들 수 없습니다." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "구성 파일 저장 중…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "권한 저장 중…" #: common/snapshots.py:1377 #, fuzzy, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "계속할 수 있는 남은 {snapshot_id} 스냅샷을 찾았습니다." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "마지막 실행에서 남은 {snapshot_id} 디렉터리 제거 중" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "디렉터리를 제거할 수 없습니다" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "성공" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "오류 때문에 일부만 전송했습니다" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "사라진 소스 파일로 인한 부분 전송('man rsync' 참조)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync'가 종료 코드 {exit_code}로 종료되었습니다" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "자세한 내용은 'man rsync'를 참조하세요" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "rsync 음수 종료 코드는 시그널 번호입니다. 'kill -l' 및 'man kill'을 참조하세요" #: common/snapshots.py:1566 #, fuzzy msgid "Nothing changed, no new backup necessary" msgstr "아무것도 변경되지 않았으며 새 스냅샷이 필요하지 않습니다" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "{new_path} 경로 이름을 {path} 경로 이름으로 바꿀 수 없습니다." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "오래된 스냅샷을 제거할 규칙 적용" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "보호 정책 적용 중" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "최소 여유 공간을 유지하려고 합니다" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "최소 {perc}개의 사용 가능한 아이노드를 유지하려고 합니다" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "현재" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "{sshfs}을(를) 마운트할 수 없습니다" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent가 없습니다. 설치 여부를 확인하십시오." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "SSH 개인 키를 잠금 해제할 수 없습니다. 잘못된 암호거나 cron 암호를 사용할 수 없습니다." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "원격 경로가 존재하지만 디렉터리가 아닙니다." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "원격 경로에 쓸 수 없습니다." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "원격 경로를 실행할 수 없습니다." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "원격 경로를 생성할 수 없습니다." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "원격 호스트 {host}은(는) {command}을(를) 지원하지 않습니다" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "호스트 {host}의 확인 명령이 알 수 없는 오류를 반환했습니다" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "원격 호스트 {host}은(는) 하드링크를 지원하지 않습니다" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "\"{pubkey}\" 공개 SSH 키를 \"{host}\" 원격 호스트에 복사합니다." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "\"{user}\" 암호를 입력하십시오." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "{path}의 대상 파일 시스템은 유닉스 방식 파일 시스템과 호환성이 없다고 알려진 NTFS 형식으로 초기화했습니다." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path}은(는) 적절한 디렉터리가 아닙니다." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "해당 디렉토리 생성에 실패:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "쓰기 권한이 제한되어있습니다." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "{path}의 대상 파일 시스템은 하드 링크를 지원하지 않는 FAT 형식으로 포맷했습니다. GNU/Linux 자체 파일 시스템을 " "사용하십시오." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "{path}의 대상 파일 시스템은 SMB 형식 공유 마운트입니다. 원격 SMB 서버가 심볼릭 링크를 지원하는지 확인하거나 " "\"{expertOptions}\"에서 \"{copyLinks}\"를 활성화하십시오." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "링크 복사 (심볼릭 링크 역참조)" #: common/tools.py:487 msgid "Expert Options" msgstr "전문가 설정" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "{path}의 대상 파일 시스템은 SSHFS 공유 마운트 입니다. SSHFS는 하드 링크를 지원하지 않습니다. 대신 \"SSH\" 모드를" " 사용하십시오." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "디렉토리에서 파일 생성에 실패:" #: qt/aboutdlg.py:51 #, fuzzy msgid "About Back In Time" msgstr "Back In &Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 #, fuzzy msgid "Authors:" msgstr "저자" #: qt/aboutdlg.py:97 #, fuzzy msgid "Translators:" msgstr "번역" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "프로젝트 사이트" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "사용자 메뉴얼" #: qt/aboutdlg.py:227 qt/app.py:562 #, fuzzy msgid "Open user manual in browser (local if available, otherwise online)" msgstr "사용자 메뉴얼을 브라우저에서 열기(로컬이 안되면 온라인으로)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "{app_name}을 어떤 설정 없이 처음 실행하는 것 같습니다." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "(백업 대상 디렉터리 또는 다른 컴퓨터에서) 기존 설정을 가져오시겠습니까?" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "파일 변경 감지를 위해 수정 시간 및 크기를 사용합니다." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "체크섬을 포함한 스냅샷 생성하기" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "파일 변경 감지에 체크섬을 사용합니다." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "스냅샷 생성 일시 중지" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "스냅샷 생성 재시작" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "스냅샷 생성 중지" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "스냅샷 목록 새로 고침" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "스냅샷 제거" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "마지막 로그 보기" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "백업을 위해서는 적어도 하나의 디렉토리가 선택되어야 합니다." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "마지막 로그 보기" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "프로필 관리…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "user-callback 편집" #: qt/app.py:548 msgid "Shutdown" msgstr "끄기" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "스냅샷이 끝난 후 시스템 종료하기." #: qt/app.py:552 msgid "Setup language…" msgstr "언어 설정…" #: qt/app.py:556 msgid "Exit" msgstr "끝내기" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "맨 페이지: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Back In Time (backintime) 맨 페이지를 표시합니다" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "맨 페이지: 프로필 설정 파일" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "프로파일 설정(backintime-config)에 대한 man 페이지 열기" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "브라우저에서 Back In Time 웹사이트 열기" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "변경 내역" #: qt/app.py:586 #, fuzzy msgid "Open changelog (locally if available, otherwise from the web)" msgstr "사용자 메뉴얼을 브라우저에서 열기(로컬이 안되면 온라인으로)" #: qt/app.py:589 msgid "FAQ" msgstr "자주 묻는 질문" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "브라우저에서 자주 묻는 질문들 (FAQ) 열기" #: qt/app.py:593 msgid "Ask a question" msgstr "질문하기" #: qt/app.py:597 msgid "Report a bug" msgstr "버그 신고" #: qt/app.py:600 msgid "Translation" msgstr "번역" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "번역 참여에 대한 메세지를 다시 보기." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Transition 암호화 (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "EncFS 제거에 대한 메시지를 다시 보기." #: qt/app.py:615 msgid "About" msgstr "정보" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "복원" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "선택한 파일이나 디렉터리를 원래 대상으로 복원합니다." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "다음 위치에 복원 …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "선택한 파일 또는 디렉터리를 새로운 대상으로 복원합니다." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "현재 표시한 디렉터리와 해당 디렉터리의 모든 내용을 원래 대상으로 복원합니다." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "현재 나타난 디렉터리와 해당 디렉터리의 모든 내용을 새 대상으로 복원합니다." #: qt/app.py:640 msgid "Up" msgstr "위로" #: qt/app.py:643 msgid "Show hidden files" msgstr "숨겨진 파일 표시" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "스냅샷 비교…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "배포 후보" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "배포 후보에 대한 메시지 다시 보기." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "백업" #: qt/app.py:733 msgid "&Restore" msgstr "복원" #: qt/app.py:739 msgid "&Help" msgstr "도움말" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "아이콘만" #: qt/app.py:827 msgid "Text only" msgstr "글자만" #: qt/app.py:830 msgid "Text below icons" msgstr "아이콘 밑 글자" #: qt/app.py:833 msgid "Text beside icon" msgstr "아이콘 옆 글자" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "현재 선택한 스냅샷에\n" "이 디렉터리가 없습니다." #: qt/app.py:1005 msgid "Add to Include" msgstr "포함할 항목 추가" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "제외할 항목 추가" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "이 창을 닫으면 스냅샷을 마쳤을 때 Back In Time에서 시스템을 끌 수 없습니다." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "완료했습니다. 백업이 필요하지 않습니다" #: qt/app.py:1285 msgid "Working:" msgstr "진행 중:" #: qt/app.py:1292 msgid "Working" msgstr "진행 중" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "오류" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "전송:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "속도:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "남은시간:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "백업" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "{path} 복원" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "{path}를 다음 위치에 복원 …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "안녕하세요\n" "지금까지 여러분은 {language} 언어로 Back In Time을 몇 번 사용해 보셨습니다.\n" "설치된 Back In Time 버전의 {language} 번역이 {perc} 가량 끝났습니다. 여러분의 기술 전문 지식 수준에 관계없이 귀하는 번역에 기여하여 Back In Time 자체에 기여할 수 있습니다.\n" "기여하고 싶다면 {translation_platform_url}를 방문하세요. 추가 지원 및 질문이 있다면 {back_in_time_project_website}를 방문하세요.\n" "불편을 끼쳐드려 죄송하며 이 메시지는 다시 표시되지 않습니다. 이 대화 상자는 도움말 메뉴를 통해 언제든지 살펴보실 수 있습니다.\n" "여러분의 Back In Time 팀" #: qt/app.py:1709 msgid "translation platform" msgstr "번역 플랫폼" #: qt/app.py:1714 msgid "Website" msgstr "웹사이트" #: qt/app.py:1728 msgid "Your translation" msgstr "귀하의 번역" #: qt/app.py:1765 #, fuzzy, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Mastodon에서 보기: {link_and_label}" #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "{link_and_label} 메일링 리스트" #: qt/app.py:1774 #, fuzzy, python-brace-format msgid "Mailing list {link_and_label}." msgstr "{link_and_label} 메일링 리스트" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "프로젝트 웹사이트의 {link_and_label}." #: qt/app.py:1781 msgid "Open an issue" msgstr "문제 보고 열기" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "대신, 다른 채널을 활용하여 연락할 수 있습니다." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "이번 Back In Time 버전은 출시 후보작으로 다음 정식 출시 버전의 준비를 위한 안정화 시험이 주 목적입니다.\n" "사용자 데이터 또는 원격 데이터는 수집하지 않습니다. 그러나, Back In Time 팀에서는 출시 후보작의 사용 여부와 출시 이전 버전의 계속적 제공 가치 여부를 확인하고 싶습니다.\n" "따라서, 팀에서는 어떤 문제를 경험해보지 못했다 하더라도 이 버전의 시험 여부에 대한 간단한 고견을 듣고자 합니다. 몇 분동안의 간단한 시험 실행만으로도 저희에겐 큰 도움이 됩니다.\n" "다음과 같은 방식으로 연락할 수 있습니다:\n" "{contact_list}\n" "이 버전에서, 이 메시지는 더이상 나타나지 않지만 도움말 메뉴에서 언제든 살펴보실 수 있습니다.\n" "Back In Time 개선을 지원해주시는 여러분께 감사합니다!\n" "여러분의 Back In Time 팀" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "{BOLD}경고{BOLDEND}: 파일 시스템 루트에서 파일을 삭제하면 전체 시스템이 망가질 수 있습니다." #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "백업" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "언어 설정은 Back In Time을 다시 시작한 후에만 적용됩니다." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "이름이 붙은 스냅샷 유지." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "질문" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "로컬 요소를 덮어쓰거나 제거하기 전에\n" "뒤에 오는 {suffix}를 사용하여 백업 복사본을 만듭니다." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "파일 최신 버전은 복원하기 전 {suffix}를 붙여 이름을 바꿉니다. 해당 파일이 더이상 필요하지 않으면 다음 명령으로 제거할 수 " "있습니다:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "백업 대상 위치에 없거나\n" "해당 위치보다 최신인 항목만 복원합니다.\n" "\"rsync --update\" 옵션을 사용하십시오." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "원본 디렉터리에서 최신 요소를 제거합니다." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "선택한 파일 또는 디렉터리를 원래 대상으로 복원하고 스냅샷에 없는 파일 또는 디렉터리는 삭제합니다. 스냅샷을 취할 때 제외한 파일 및 " "디렉터리도 삭제하므로 취급에 신중을 기하십시오." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "이 항목을 새 디렉터리에 복원하시겠습니까?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "정말로 이 항목을 복원하시겠습니까?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "파일 및 디렉터리 포함" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "언어 설정" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "{percent} 번역됨" #: qt/languagedialog.py:132 msgid "System default" msgstr "시스템 기본값" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "운영 체제의 언어를 사용합니다." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "마지막 로그 보기" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "마지막 로그 보기" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "프로필:" #: qt/logviewdialog.py:86 #, fuzzy msgid "Backups:" msgstr "백업" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "필터:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] 오류, [I] 정보, [C] 변경" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "경로 디코딩" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "모두" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "변경" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "오류" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "정보" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync 전송 실패 (시험용)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "프로필 관리" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "편집" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "추가" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "삭제" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "일반(&G)" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "포함(&I)" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "제외(&E)" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "제거(&R) 및 보유" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "옵션(&O)" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "고급 설정" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "설정 복구" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "새로운 프로파일" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "프로파일명을 변경" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "정말 \"{name}\" 프로파일을 삭제하시겠습니까?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "스냅샷 생성 일시 중지" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "제외 파일" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "백업 디렉터리" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "디렉터리를 제거할 수 없습니다" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "숨겨진 파일 표시" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "스냅샷 생성 중지" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "제외 디렉터리" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "기본값" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "일정" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "일:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "요일:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "시간:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "시간:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "한시간 후" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "분:" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "드라이브를 연결하면 Back In Time을 실행합니다(매 X일에 한번씩). sudo 암호 입력이 필요합니다." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "반복적으로 Back In Time을 실행합니다. 컴퓨터를 비정기적으로 사용할 때 쓸만합니다." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "매:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "디버깅 메시지 기록 활성" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "디버깅 수준 메시지를 \"--debug\" 옵션으로 시스템 로그에 기록합니다." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "위험: 엄청난 양의 출력 내용을 만들어내므로 진단 목적으로 잠시 동안만 사용하십시오." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "비활성화됨" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "부팅/재부팅 할 때 마다" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "매 {n}분 마다" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "{n}시간마다" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "시간 주기 설정" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "매일" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "반복 (아나크론)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "드라이브를 연결했을 때(udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "매주" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "매월" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "매년" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "시간" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "일" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "주" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "월" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "개별 설정 시간은 쉼표로 구분한 시간 값(예: 8, 12, 18, 23)이거나 3시간당 주기 백업일 경우 */3 과 같은 형식의 " "값입니다." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Pasirinkti esamą privataus rakto failą iš kažkur kitur." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Sukurti naują SSH raktą be slaptafrazės." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Visas kelias: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Privatus raktas:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Naudoti sistemos SSH konfigūraciją" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Palieka rakto failą nepasirinktą. SSH ryšiai remsis sistemos esama kliento " "programos konfigūracija (pavyzdžiui, ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH įgaliotasis serveris" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 #, fuzzy msgid "Host:" msgstr "Pagrindinis kompiuteris:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Prievadas:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Naudotojas:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" #: qt/manageprofiles/tab_exclude.py:85 #, fuzzy msgid "Exclude patterns, files or directories" msgstr "Išskirkite šablonus, failus ar aplankus" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Išskirti šabloną" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Pridėti failų" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Pridėti katalogų" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Klausimas" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Išskirti failus, didesnius nei:" #: qt/manageprofiles/tab_exclude.py:138 #, fuzzy, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Išskirti failus, didesnius, nei: " #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Išskirkite failus, didesnius nei %(prefix)s.\n" "Išjungus „Visas rsync režimas“, tai turės įtakos tik naujiems failams\n" "nes rsync tai yra perdavimo parinktis, o ne išimtis.\n" "Taigi dideli failai, kurių atsarginės kopijos buvo sukurtos anksčiau, liks momentinėse nuotraukose\n" "net jei jie pasikeitė." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Išskirti šabloną" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Išskirti šabloną" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Išskirti failą" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Išskirti katalogą" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Šios parinktys yra skirtos išplėstinėms konfigūracijoms. Modifikuokite jas " "tik tuo atveju, jei visiškai suprantate jų reikšmę." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Paleisti „rsync“ su „{cmd}“:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 #, fuzzy msgid "as cron job" msgstr "kaip cron job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 #, fuzzy msgid "on remote host" msgstr "nuotoliniame pagrindiniame kompiuteryje" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "darant momentinę kopiją rankiniu būdu" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Norėdami įjungti šią parinktį, įsidiekite „nocache“." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "vietiniame kompiuteryje" #: qt/manageprofiles/tab_expert_options.py:130 #, fuzzy msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Nukreipkite stdout į /dev/null cronjobs." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:142 #, fuzzy msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Nukreipkite stderr į /dev/null cronjobs." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/sek" #: qt/manageprofiles/tab_expert_options.py:163 #, fuzzy msgid "Limit rsync bandwidth usage:" msgstr "Apriboti rsync pralaidumo naudojimą" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Išsaugoti ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Išsaugoti išplėstinius atributus (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "" #: qt/manageprofiles/tab_expert_options.py:267 #, fuzzy, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "" "Įklijuoti papildomas parinktis į rsyncOptions turi būti cituojamos pvz. " "{example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Įdėti papildomas parinktis, skirtas rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "" #: qt/manageprofiles/tab_expert_options.py:287 #, fuzzy, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Priešdėlis paleisti prieš kiekvieną komandą nuotoliniame pagrindiniame kompiuteryje.\n" "Kintamieji turi būti pakeisti naudojant \\$FOO.\n" "Tai neliečia rsync. Taigi, norėdami pridėti priešdėlį\n" "rsync naudokite „%(cbRsyncOptions)s“ su\n" "%(rsync_options_value)s\n" "\n" "%(default)s: %(def_value)s" #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "pagal numatymą" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Pridėti SSH komandoms priešdėlį" #: qt/manageprofiles/tab_expert_options.py:308 #, fuzzy msgid "Check if remote host is online" msgstr "Patikrinkite, ar nuotolinis kompiuteris yra prisijungęs" #: qt/manageprofiles/tab_expert_options.py:311 #, fuzzy msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Įspėjimas: jei išjungta ir nuotolinis kompiuteris\n" "nepasiekiamas, tai gali sukelti \n" "keistas klaidas." #: qt/manageprofiles/tab_expert_options.py:315 #, fuzzy msgid "Check if remote host supports all necessary commands." msgstr "" "Patikrinkite, ar nuotolinis kompiuteris palaiko visas reikalingas komandas" #: qt/manageprofiles/tab_expert_options.py:318 #, fuzzy msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Įspėjimas: jei išjungta ir nuotolinis kompiuteris\n" "nepalaiko visų reikalingų komandų,\n" "tai gali sukelti keistų klaidų." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(pagal numatymą: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "išjungta" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "įjungta" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Veiksena:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Kur įrašyti atsargines kopijas" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH nustatymai" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Kelias:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Rakto failas:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Slaptažodis" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Įrašyti slaptažodį į raktinę" #: qt/manageprofiles/tab_general.py:210 #, fuzzy msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Išsaugoti Cron slaptažodį (Saugumo spraga: root gali matyti slaptažodį)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Išplėstiniai" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Visas atsarginės kopijos kelias:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "EncFS slaptažodžiai nesutampa." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 #, fuzzy msgid "Proceed with copying the SSH key?" msgstr "Šalinti šią atsarginę kopiją?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Nepavyko nukopijuoti viešo SSH rakto. Taip gali būti dėl ryšio ar leidimų " "problemos." #: qt/manageprofiles/tab_general.py:606 #, fuzzy, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "" "{host} autentiškumo nustatyti nepavyko.\n" "\n" "{keytype} rakto kontrolinis kodas yra:" #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} rakto kontrolinis kodas yra:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "Patikrinkite šį kontrolinį kodą. Ar pridėti jį į „known_hosts“ failą?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Ar tikrai pakeisti atsarginės kopijos katalogą?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Neteisingas failas: Nėra privatus SSH raktas" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Pasirinktas failas ({path}) yra viešas SSH raktas. Vietoj jo, pasirinkite " "atitinkamą privataus rakto failą (be „.pub“)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Failas {path} jau yra. Negalima sukurti naujo SSH raktu tokiu pavadinimu." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Nepavyko sukurti naujo SSH rakto ties {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Įtraukti failus bei katalogus" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "„{path}“ yra simbolinė nuoroda. Susieto paskirties objekto atsarginė kopija " "nebus padaryta tol, kol jis taip pat nebus įtrauktas." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Ar vietoj simbolinės nuorodos norite įtraukti paskirties objektą?" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Įtraukti failą" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Įtraukti katalogą" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Įjungti pranešimus" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Išjungti atsargines kopijas, kai naudojama akumuliatoriaus energija" #: qt/manageprofiles/tab_options.py:49 #, fuzzy msgid "Power status not available from system" msgstr "Maitinimo būsena nepasiekiama iš sistemos" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Vienu metu paleisti tik vieną momentinę kopiją" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Kitos momentinės kopijos bus blokuojamos, kol bus padaryta dabartinė momentinė kopija.\n" "Tai bendrasis variantas. Taigi tai turės įtakos visiems šio vartotojo profiliams.\n" "Bet jūs turite tai suaktyvinti ir visiems kitiems vartotojams." #: qt/manageprofiles/tab_options.py:63 #, fuzzy msgid "Backup replaced files on restore" msgstr "Atkūrimo metu sukurkite pakeistų failų atsarginę kopiją" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Tęsti, kai yra klaidų (palikti neužbaigtas atsargines kopijas)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Pakeitimų aptikimui naudoti kontrolines sumas" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" "Sukurti naują atsarginę kopiją, nepaisant to, ar buvo pakeitimų, ar ne." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Įspėti, jei laisvos vietos diske tampa mažiau nei" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Rodo įspėjimą, kai laisvos vietos atsarginės kopijos paskirties diske yra " "mažiau nei nurodyta reikšmė." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Žurnalo lygis:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nėra" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "naudotojo vadovą" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Šios taisyklės yra apdorojamos nuo viršaus į apačią. Vėlesnės taisyklės " "nustelbia ankstesnes. Norėdami gauti daugiau informacijos ir pavyzdžių, " "žiūrėkite {manual}." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Atverti naršyklėje naudotojo vadovą." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Palikti paskiausią atsarginę kopiją." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Ta elgsena negali būti pakeista." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Palikti atsargines kopijas, turinčias pavadinimus." #: qt/manageprofiles/tab_remove_retention.py:258 #, fuzzy msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Atsarginės kopijos, kurioms buvo suteiktas pavadinimas, kartu su įprastomis " "laiko žymomis, bus bet kokiomis sąlygomis iš" #: qt/manageprofiles/tab_remove_retention.py:273 #, fuzzy msgid "Year(s)" msgstr "Metai (-ų)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Šalinti atsargines kopijas, kurios senesnės nei" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12 mėnesių laikotarpiai. Dabartinio mėnesio yra nepaisoma." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:310 #, fuzzy msgid "Run in background on remote host." msgstr "Vykdykite nuotolinio pagrindinio kompiuterio fone." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dienos skaičiuojamos, pradedant nuo šiandien." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Išsaugokite visas momentines kopijas paskutinei" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 #, fuzzy msgid "day(s)." msgstr "Diena(os)." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Paskutinį kartą išsaugokite vieną momentinę kpiją per dieną" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Paskutinį kartą išsaugokite vieną momentinę kopiją per savaitę" #: qt/manageprofiles/tab_remove_retention.py:352 #, fuzzy msgid "week(s)." msgstr "Savaitė(s)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Paskutinį kartą išsaugokite vieną momentinę kopiją per mėnesį" #: qt/manageprofiles/tab_remove_retention.py:365 #, fuzzy msgid "month(s)." msgstr "Mėnesis(iai)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" "Metai yra skaičiuojami kaip kalendoriniai metai, pradedant dabartiniais " "metais." #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Išsaugokite visas momentines kopijas paskutinei" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "…laisvos vietos yra mažiau nei" #: qt/manageprofiles/tab_remove_retention.py:394 #, fuzzy msgid "… the free inodes are less than" msgstr "Jei laisvų inodų mažiau nei" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Šalinti seniausią atsarginę kopiją, jei…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 #, fuzzy msgid "Shortcuts" msgstr "Nuorodos" #: qt/placeswidget.py:63 msgid "Places" msgstr "Vietos" #: qt/placeswidget.py:64 msgid "File System" msgstr "Failų sistema" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Atsarginių kopijų katalogai" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profilis: {profile_name}" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profilis: {profile_name}" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Rodyti paskutinį žurnalą" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Paleisti {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Dirbama…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importuoti konfigūraciją" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importuoti" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Ieškoma…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Pasirinkite atsarginės kopijos katalogą, iš kurio turėtų būti importuotas " "konfigūracijos failas. Kelias gali atrodyti taip: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Jei katalogo vieta yra išoriniame ar nuotoliniame diske, jis privalo būti iš" " anksto prijungtas rankiniu būdu." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Peržiūrėti dar kartą" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Rodyti paslėptus katalogus" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Rodyti/slėpti paslėptus katalogus (Ctrl+H)" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Nepavyko sukurti failo šiame kataloge:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Paieška užbaigta." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Rodyti visą žurnalą" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Atvirkštinis skaičiavimas iki išjungimo" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Išjungti sistemą, kai atsarginės kopijos darymas bus užbaigtas." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Atsisakyti išjungimo" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Išjungti dabar" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Sistema išsijungs po {n} sekundės." msgstr[1] "Sistema išsijungs po {n} sekundžių." msgstr[2] "Sistema išsijungs po {n} sekundžių." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Atsarginių kopijų palyginimo parinktys" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Komanda:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametrai:" #: qt/snapshotsdialog.py:79 #, fuzzy msgid "Use %1 and %2 for path parameters" msgstr "naudoti %1 ir %2 kaip kelio parametrus" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "" #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Šioje sistemoje nepavyko rasti „{cmd}“ komandos. Pabandykite kažką kito arba" " paspauskite „Atsisakyti“." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Atsarginės kopijos" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Tik skirti skirtingus momentinius vaizdus" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "Išvardykite tik tokias momentines nuotraukas kaip: " #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Gilus tikrinimas (tikslesnis, bet lėtesnis)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Ištrinti" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Žymėti viską" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Palyginti" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Eiti į" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Parinktys" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Neįmanoma palyginti atsarginę kopiją su ja pačia, nes palyginimas būtų " "nereikalingas." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Ar tikrai ištrinti {file_or_dir}, esantį atsarginėje kopijoje {backup_id}?" #: qt/snapshotsdialog.py:445 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Ar tikrai norite ištrinti „{file}“ iš {count} momentinių nuotraukų?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "ĮSPĖJIMAS: To negalima bus panaikinti." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Išskirti {path} iš atsarginių kopijų ateityje?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Šaknis" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Šiandien" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Vakar" #: qt/timeline.py:87 msgid "This week" msgstr "Šią savaitę" #: qt/timeline.py:95 msgid "Last week" msgstr "Praeitą savaitę" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Tai NĖRA atsarginė kopija, o tiesioginis vietinių failų rodinys." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Paskutinis tikrinimas {time}" backintime-1.6.1/common/po/messages.pot000066400000000000000000001515471514264426600201150ustar00rootroot00000000000000# © 2008 Back In Time Team # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. #, fuzzy msgid "" msgstr "" "Project-Id-Version: \"Back In Time\" \"1.6.1\"\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "" #: common/config.py:237 msgid "Local" msgstr "" #: common/config.py:240 msgid "Local encrypted" msgstr "" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "" #: common/config.py:245 msgid "SSH" msgstr "" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "" #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "" #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "" #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" #: common/configfile.py:101 msgid "Failed to save config" msgstr "" #: common/configfile.py:137 msgid "Failed to load config" msgstr "" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "" #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "" #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "" #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "" #: common/encfstools.py:204 msgid "Cancel" msgstr "" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "" #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "" #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "" #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "" #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "" #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "" #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "" msgstr[1] "" #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "" #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "" #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "" #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "" #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "" #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "" #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "" #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "" #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "" #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "" #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "" #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "" #: common/tools.py:487 msgid "Expert Options" msgstr "" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "" #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "" #: qt/app.py:520 msgid "Refresh backup list" msgstr "" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 msgid "Remove backup" msgstr "" #: qt/app.py:532 msgid "Open backup log" msgstr "" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "" #: qt/app.py:536 msgid "Open last backup log" msgstr "" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "" #: qt/app.py:544 msgid "Edit user-callback" msgstr "" #: qt/app.py:548 msgid "Shutdown" msgstr "" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "" #: qt/app.py:552 msgid "Setup language…" msgstr "" #: qt/app.py:556 msgid "Exit" msgstr "" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" #: qt/app.py:589 msgid "FAQ" msgstr "" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "" #: qt/app.py:593 msgid "Ask a question" msgstr "" #: qt/app.py:597 msgid "Report a bug" msgstr "" #: qt/app.py:600 msgid "Translation" msgstr "" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "" #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "" #: qt/app.py:615 msgid "About" msgstr "" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "" #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "" #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" #: qt/app.py:640 msgid "Up" msgstr "" #: qt/app.py:643 msgid "Show hidden files" msgstr "" #: qt/app.py:646 msgid "Compare backups…" msgstr "" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "" #: qt/app.py:716 msgid "Back In &Time" msgstr "" #: qt/app.py:721 msgid "&Backup" msgstr "" #: qt/app.py:733 msgid "&Restore" msgstr "" #: qt/app.py:739 msgid "&Help" msgstr "" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "" #: qt/app.py:827 msgid "Text only" msgstr "" #: qt/app.py:830 msgid "Text below icons" msgstr "" #: qt/app.py:833 msgid "Text beside icon" msgstr "" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" #: qt/app.py:1005 msgid "Add to Include" msgstr "" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "" #: qt/app.py:1285 msgid "Working:" msgstr "" #: qt/app.py:1292 msgid "Working" msgstr "" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "" #: qt/app.py:1490 msgid "Backup:" msgstr "" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1709 msgid "translation platform" msgstr "" #: qt/app.py:1714 msgid "Website" msgstr "" #: qt/app.py:1728 msgid "Your translation" msgstr "" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "" #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "" #: qt/app.py:1781 msgid "Open an issue" msgstr "" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" #: qt/app.py:2167 msgid "Backup name" msgstr "" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" msgstr[1] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "" #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" msgstr[1] "" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "" msgstr[1] "" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "" #: qt/languagedialog.py:132 msgid "System default" msgstr "" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "" #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "" msgstr[1] "" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "" msgstr[1] "" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "" msgstr[1] "" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "Velg en eksisterende privat nøkkelfil (normalt kalt «id_ed25519», og i eldre" " oppsett «id_rsa»)." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "Mislyktes å lage ny SSH-nøkkel i {path}." #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "Full sti til øyeblikksbilde:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Privat SSH-nøkkel:" #: qt/manageprofiles/sshkeyselector.py:210 #, fuzzy msgid "Use system SSH configuration" msgstr "Importer konfigurasjon" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH-proxy" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Tjener:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Bruker:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Koble til målverten via denne proxyen (også kjent som en hoppvert). Se «-J» " "i dokumentasjonen for SSH-kommandoen eller «ProxyJump» i man-siden for " "«ssh_config» for detaljer." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Info{ENDBOLD}: I «SSH kryptert» modus fungerer kun enkle eller doble " "asterisk (f.eks. {example2}). Andre typer jokertegn og mønstre vil bli " "ignorert (f.eks. {example1}). Filnavn er uforutsigbare i denne modusen på " "grunn av kryptering med EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Ekskluder mønstre, filer eller mapper" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Legg til fil" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Legg til mappe" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Spørsmål" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Ekskluder filer som er større enn:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Ekskluder filer som er større enn {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Med «Full rsync mode» avslått vil dette kun påvirke nye filer ettersom for " "rsync er dette et overføringsvalg, ikke et ekskluderingsvalg. Derfor vil " "store filer som tidligere har blitt sikkerhetskopiert bli værende i " "øyeblikksbildet selv om de har blitt endret." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Ekskluder fil" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Ekskluder mappe" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Deaktivert fordi dette mønsteret ikke fungerer i «SSH kryptert» modus." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Disse innstillingene er for avanserte konfigurasjoner. Endre dem kun dersom " "du er fullt klar over konsekvensene." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Kjør «rsync» med «{cmd}»:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "som cron-jobb" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "på ekstern vert" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "når du tar et manuelt øyeblikksbilde" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Vennligst installer «nocache» for å slå på dette valget." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "på lokal maskin" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Videresend stdout til /dev/null i cron-jobber." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron vil automatisk sende en e-post med vedlagt utdata fra cron-jobber " "dersom en MTA er installert." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Videresend stderr til /dev/null i cron-jobber." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron vil automatisk sende en e-post med vedlagte feilmeldinger fra cron-" "jobber dersom en MTA er installert." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/sek" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Begrens båndbredden for rsync til:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Behold ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Behold utvidede attributter (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Begrens til ett filsystem" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Valgene må settes i anførselstegn, for eksempel {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Lim inn tilleggsopsjoner til rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Et prefiks som skal kjøres før hver kommando på ekstern vert." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variabler må innledes med en bakoverstrek, for eksempel \\$FOO. Dette " "påvirker ikke rsync. For å legge til et prefiks for rsync, bruk " "«{example_value}» sammen med {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "standard" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Legg til et prefiks for SSH-kommandoer" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Kontroller at den eksterne verten er tilgjengelig" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Advarsel: Om dette valget er avslått, og den eksterne verten ikke er " "tilgjengelig, kan det oppstå en del merkelige feil." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Kontroller at den eksterne verten støtter alle nødvendige kommandoer." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Advarsel: Om dette valget er avslått, og den eksterne verten ikke støtter " "alle nødvendige kommandoer, kan det oppstå en del merkelige feil." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(standard: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "avslått" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "påslått" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modus:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Hvor skal øyeblikksbilder lagres" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH-innstillinger" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Sti:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Ny profil" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Passord" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Lagre passord til nøkkelringen" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Legg passordet i hurtigminne for cron (sikkerhetsrisiko: root kan lese " "passordet)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avansert" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 #, fuzzy msgid "Full backup path:" msgstr "Full sti til øyeblikksbilde:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Passordene stemmer ikke overens." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 #, fuzzy msgid "Proceed with copying the SSH key?" msgstr "Fortsett med sikkerhetskopieringen?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Ektheten til vert {host} kan ikke fastslås." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Fingeravtrykket til {keytype}-nøkkelen er:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Vennligst kontroller dette fingeravtrykket. Vil du legge det til i filen " "«known_hosts»?" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Opprett en ny kryptert mappe?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "privat SSH-nøkkel" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Mislyktes å lage ny SSH-nøkkel i {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Inkluder filer og mapper" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "«{path}» er en symbolsk lenke. Målet for lenken sikkerhetskopieres ikke før " "du inkluderer det også." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Inkluder heller målet til den symbolske lenken i stedet?" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Inkluder fil" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Inkluder mappe" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Slå på varslinger" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Slå av øyeblikksbilder ved batteridrift" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Strømstatus er ikke tilgjengelig fra systemet" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Ta kun ett øyeblikksbilde om gangen" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Andre øyeblikksbilder vil bli blokkert inntil det nåværende øyeblikksbildet " "er fullført. Dette er et globalt valg, så det vil påvirke alle profiler for " "denne brukeren. Du må imidlertid slå dette på for alle andre brukere." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Sikkerhetskopier filer som overskrives ved gjenoppretting" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Fortsett ved feil (behold ufullstendige øyeblikksbilder)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Bruk sjekksum for å oppdage endringer" #: qt/manageprofiles/tab_options.py:86 #, fuzzy msgid "Create a new backup whether there were changes or not." msgstr "" "Ta et nytt øyeblikksbilde, uavhengig av om det har vært endringer eller " "ikke." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Advar hvis ledig diskplass faller under" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Viser en advarsel når ledig plass på plasseringen for sikkerhetskopi er " "mindre enn den angitte verdien." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Dersom regelen Fjern & Oppbevaring er aktivert, og eldre sikkerhetskopier " "fjernes basert på tilgjengelig ledig plass, kan ikke denne verdien være " "lavere enn verdien i regelen." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Logg-nivå:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Ingen" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "brukerhåndbok" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Følgende regler behandles fra topp til bunn. Senere regler overstyrer " "tidligere, og de er ikke begrenset av disse. Se {manual} for detaljer og " "eksempler." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Åpne brukerhåndboken i nettleseren." #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Behold det nyeste øyeblikksbildet." #: qt/manageprofiles/tab_remove_retention.py:241 #, fuzzy msgid "The most up-to-date backup is kept under all circumstances." msgstr "" "Det siste eller nyeste øyeblikksbildet beholdes under alle omstendigheter." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Denne oppførselen kan ikke endres." #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Behold navngitte øyeblikksbilder." #: qt/manageprofiles/tab_remove_retention.py:258 #, fuzzy msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Øyeblikksbilder som har blitt gitt et navn, i tillegg til det vanlige " "tidsstempelet, beholdes under alle omstendigheter og fjernes ikke." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "År" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Fjern øyeblikksbilder eldre enn" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Hele dager. Dagens dato ignoreres." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Kalenderuker med mandag som første dag. Nåværende uke ignoreres." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12-måneders perioder. Nåværende måned ignoreres." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Oppbevaringsregel" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Kjør i bakgrunnen på den eksterne verten." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Den smarte fjerningsprosedyren kjøres direkte på den eksterne maskinen, ikke" " lokalt. Kommandoene «bash», «screen» og «flock» må være installert og " "tilgjengelige på den eksterne maskinen." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Hvis valgt, vil Back In Time først teste den eksterne maskinen." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dager telles med utgangspunkt fra i dag." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Behold alle øyeblikksbilder tatt de siste" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "dag(ene)." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Behold det siste øyeblikksbildet for hver dag tatt de siste" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Ukene telles med utgangspunkt i den nåværende uken. En uke starter på " "mandag." #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Behold det siste øyeblikksbildet for hver uke tatt de siste" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "uke(ene)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "Månedene regnes som kalendermåneder, med utgangspunkt i den nåværende " "måneden." #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Behold det siste øyeblikksbildet for hver måned tatt de siste" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "måned(ene)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Årene telles som kalenderår med utgangspunkt i det nåværende året." #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Behold det siste øyeblikksbildet for hvert år for" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "alle år." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… den ledige plassen er mindre enn" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… ledige inoder er mindre enn" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Slett de eldste øyeblikksbildene om …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Snarveier" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Mapper for sikkerhetskopiering" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: {profile_name}" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: {profile_name}" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Vis siste logg" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Start {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Arbeider…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importer konfigurasjon" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importer" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Arbeider…" #: qt/restoreconfigdialog.py:211 #, fuzzy, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Velg mappen med øyeblikksbilder hvorfra konfigurasjonsfilen skal importeres." " Stien kan se slik ut: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Om mappen befinner seg på et flyttbar eller eksternt medium, må den monteres" " manuelt først." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Vis skjulte filer" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Inkluder filer og mapper" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Filoppretting mislyktes i denne mappen:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Vis hele loggen" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Nedtelling for avslutning" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Skrur av systemet etter at øyeblikksbildet er ferdig." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Skru av" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Skru av" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Systemet vil bli slått av om {n} sekund." msgstr[1] "Systemet vil bli slått av om {n} sekunder." #: qt/snapshotsdialog.py:63 #, fuzzy msgid "Options about comparing backups" msgstr "Opsjoner for å sammenligne øyeblikksbilder" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Kommando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametre:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Bruk %1 og %2 for sti-parametre" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Vennligst angi en diff-kommando, eller trykk avbryt." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Kommandoen «{cmd}» ble ikke funnet på dette systemet. Prøv noe annet, eller " "trykk avbryt." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Ingen parametrer er angitt for diff-kommandoen. Bruker standardverdien " "«{params}»." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Sikkerhetskopi" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Kun øyeblikksbilder med forskjeller" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "Vis kun øyeblikksbilder som er identiske med:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Grundig sjekk (mer nøyaktig, men treg)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Slett" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Velg alle" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Sammenlign" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Gå til" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Alternativer" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Det er ikke mulig å sammenligne en sikkerhetskopi med seg selv, da " "sammenligningen vil være unødvendig." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Ønsker du virkelig å slette {file_or_dir} i sikkerhetkopien {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Ønsker du virkelig å slette {file_or_dir} i {count} sikkerhetskopier?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "ADVARSEL: Dette kan ikke angres." #: qt/snapshotsdialog.py:465 #, fuzzy, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Utelat {path} fra fremtidige øyeblikksbilder?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Rot" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "I dag" #: qt/timeline.py:77 msgid "Yesterday" msgstr "I går" #: qt/timeline.py:87 msgid "This week" msgstr "Denne uken" #: qt/timeline.py:95 msgid "Last week" msgstr "Forrige uke" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Dette er IKKE en sikkerhetskopi, men en sanntidsvisning av de lokale filene." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Sist sjekket {time}" backintime-1.6.1/common/po/nl.po000066400000000000000000002324241514264426600165250ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-05 17:33+0000\n" "Last-Translator: buhtz \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Alle licenties in dit project bevinden zich in de {dir_link} map. Om de per-" "bestand licenties en auteursrecht informatie te extraheren, zie " "{readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Opgelet" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Hoofdprofiel" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokaal (EncFS-versleuteld)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS-versleuteld)" #: common/config.py:237 msgid "Local" msgstr "Lokaal" #: common/config.py:240 msgid "Local encrypted" msgstr "Lokaal versleuteld" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Versleuteling" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH private sleutel" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profiel: “{name}”" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Backup-folder is ongeldig." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Er moet minstens één backup map geselecteerd worden." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Map: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Deze map kan niet opgenomen worden in de back-up, want ze is onderdeel is " "van de back-up bestemming zelf." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "De waarde voor \"Verwijder oudste backup indien de vrije plaats kleiner is " "dan\" ({val_one}) moet kleiner dan of gelijk zijn aan de grenswaarde voor " "\"Waarschuw als de vrije schijfruimte minder is dan\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Pas aub. de waarden aan zodat limiet om backups te verwijderen niet groter " "is dan de limiet voor de waarschuwing." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udev methode werkt niet bij modus {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Kon geen nieuwe crontab schrijven." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron is niet actief, hoewel het commando crontab beschikbaar is. Geplande " "back-up taken worden niet uitgevoerd. Mogelijk is cron geïnstalleerd, maar " "niet geactiveerd. Probeer het commando \"systemctl enable cron\" of " "raadpleeg de ondersteuningskanalen van uw GNU/Linux-distributie." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Kon configuratie niet opslaan" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Kon configuratie niet laden" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profiel \"{name}\" bestaat al." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Het laatste profiel kan niet worden verwijderd." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Kan \"{command}\" niet aankoppelen" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Configuratie voor de versleutelde map niet gevonden." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Een nieuwe versleutelde map aanmaken?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Annuleren" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Voer het EncFS wachtwoord opnieuw in om te bevestigen." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "De EncFS wachtwoorden komen niet overeen." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Momentopname maken" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Kan het geëncrypteerde pad \"{command}\" niet initialiseren" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Kan {mountprocess} niet ontkoppelen van {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} niet gevonden. Installeer het a.u.b. (bijv. via " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Koppelpunt {mntpoint} niet leeg." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Voer het wachtwoord in voor {mode} profiel \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Kon Udev-regel voor profiel {profile_id} niet installeren. DBus-dienst " "'{dbus_interface}' was niet beschikbaar." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "" "Kon UUID (Universeel Unieke IDentificatiecode) voor \"{path}\" niet vinden" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "MISLUKT" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Rechten herstellen" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Voltooid" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "De volgende items uit de op te nemen lijst komen niet overeen met een " "bestand of map in de backup bron:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Back-up uitstellen indien op batterij" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Kan de back-up map niet vinden." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "" "Als deze op een verwijderbaar medium staat, gelieve dit aan te sluiten." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Wacht {n} seconde." msgstr[1] "Wacht {n} seconden." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Kon back-up {snapshot_id} niet maken." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Even geduld. Afronden…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Kan map niet aanmaken." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Configuratiebestand opslaan…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Rechten opslaan…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "Onvolledige back-up {snapshot_id} gevonden die kan voortgezet worden." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Onvolledige map {snapshot_id} van de laatste keer wordt verwijderd" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Kan map niet verwijderen" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Aanmaken backup" #: common/snapshots.py:1517 msgid "Success" msgstr "Succes" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Gedeeltelijke overdracht vanwege een fout" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Gedeeltelijke overdracht vanwege verdwenen bronbestanden (zie 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' eindigde met exitcode {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Zie 'man rsync' voor meer informatie" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negatieve rsync-exitcodes zijn signaalnummers, zie 'kill -l' en 'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Er is niets veranderd, geen nieuwe back-up nodig" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Kan {new_path} niet hernoemen naar {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Regels om oude back-ups te verwijderen worden toegepast" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Bewaarbeleid wordt toegepast" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Een minimum aan vrije ruimte proberen te behouden" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Een minimum van {perc} vrije inodes proberen te behouden" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Nu" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Kan {sshfs} niet aankoppelen" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" "ssh-agent niet gevonden. Gelieve te controleren of deze is geïnstalleerd." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Kon SSH-privésleutel niet ontgrendelen. Het wachtwoord is ongeldig of is " "niet beschikbaar voor cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Extern pad bestaat maar is geen map." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Extern pad is niet beschrijfbaar." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Extern pad is niet uitvoerbaar." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Kon extern pad niet aanmaken." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Externe host {host} ondersteunt {command} niet" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Controlecommando's op host {host} gaven onbekende foutmelding" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Externe host {host} ondersteunt geen harde koppelingen" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "De openbare SSH-sleutel \"{pubkey}\" kopiëren naar externe host \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Voer het wachtwoord in voor \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Het doelbestandssysteem van ‘{path}’ is geformatteerd als NTFS, dat geen " "harde koppeling, hard-links, ondersteunt. Gebruik in plaats daarvan een " "authentiek Linux-bestandssysteem." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} is geen geldige map." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Aanmaken van de volgende map is mislukt:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Schrijftoegang kan begrensd zijn." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Het doel-bestandssysteem van {path} is geformatteerd als FAT, dat geen harde" " koppelingen ondersteunt. Gebruik in plaats daarvan een ondersteund " "GNU/Linux-bestandssysteem." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Het doel-bestandssysteem van {path} is een met SMB aangekoppelde " "netwerkopslag. Zorg ervoor dat de externe SMB-server symbolische koppelingen" " ondersteunt of activeer \"{copyLinks}\" in \"{expertOptions}\"." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Koppelingen kopiëren (symbolische koppelingen derefereren)" #: common/tools.py:487 msgid "Expert Options" msgstr "Geavanceerde opties" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Doel-bestandssysteem voor {path} is een met sshfs aangekoppelde " "netwerkopslag. Sshfs ondersteunt geen harde koppelingen. Gebruik in plaats " "daarvan de modus \"SSH\"." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Kon geen bestand aanmaken in deze map:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Over Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Copyright:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Auteurs:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Vertalingen:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Geen vertaler credits bechikbaar voor de huidige taal." #: qt/aboutdlg.py:116 msgid "this link" msgstr "deze link" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "Volg {thislink} om vertaler credits te verkrijgen voor alle talen." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Projectwebsite" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Gebruikershandleiding" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Open de gebuikershandleiding in de browser (lokaal indien beschikbaar, " "anders online)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versie{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Het lijkt erop dat {app_name} voor de eerste keer wordt uitgevoerd, want er " "is geen configuratie gevonden." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Een bestaande configuratie importeren vanuit een back-up doelmap of een " "andere computer?" #: qt/app.py:395 msgid "Then press OK." msgstr "Druk vervolgens op OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Maak een backup" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Modificatietijd en grootte gebruiken voor detectie van bestandswijzigingen." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Back-up maken (modus controlegetal)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Controlegetallen gebruiken voor het opsporen van bestandswijzigingen." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Back-up proces pauzeren" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Back-up proces hervatten" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Back-up proces stoppen" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Back-up lijst vernieuwen" #: qt/app.py:524 msgid "Name backup" msgstr "Naam van de backup" #: qt/app.py:528 msgid "Remove backup" msgstr "Back-up verwijderen" #: qt/app.py:532 msgid "Open backup log" msgstr "Logboek openen" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Bekijk de log van de geselecteerde back-up." #: qt/app.py:536 msgid "Open last backup log" msgstr "Open de laatste back-up log" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Bekijk de laatste backuplog." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Profielen beheren…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "user-callback bewerken" #: qt/app.py:548 msgid "Shutdown" msgstr "Uitschakelen" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Computer uitschakelen wanneer de back-up voltooid is." #: qt/app.py:552 msgid "Setup language…" msgstr "Taal instellen…" #: qt/app.py:556 msgid "Exit" msgstr "Afsluiten" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man-pagina: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Toont de help pagina over Back In Time(backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man-pagina: Profielconfiguratiebestand" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Toont de help pagina over profiel configuratie bestanden(backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Open Back In Time website in de browser" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Wijzigingslogboek" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "Toon het wijzigingslogboek (lokaal als beschikbaar, anders online)" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Toon de Vaak Gestelde Vragen (FAQ) in de browser" #: qt/app.py:593 msgid "Ask a question" msgstr "Een vraag stellen" #: qt/app.py:597 msgid "Report a bug" msgstr "Een fout melden" #: qt/app.py:600 msgid "Translation" msgstr "Vertaling" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Toont het bericht over deelname aan vertaling opnieuw." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Versleutelingsovergang (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Toont opnieuw het bericht over het verwijderen van EncFS." #: qt/app.py:615 msgid "About" msgstr "Info" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Herstellen" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "" "De geselecteerde bestanden of mappen naar de oorspronkelijke bestemming " "herstellen." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Herstellen naar …" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "" "De geselecteerde bestanden of mappen naar een nieuw bestemming herstellen." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "De momenteel weergegeven map en alle inhoud ervan naar de oorspronkelijke " "bestemming herstellen." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "De momenteel weergegeven map en alle inhoud ervan naar een nieuwe bestemming" " herstellen." #: qt/app.py:640 msgid "Up" msgstr "Omhoog" #: qt/app.py:643 msgid "Show hidden files" msgstr "Verborgen bestanden tonen" #: qt/app.py:646 msgid "Compare backups…" msgstr "Back-ups vergelijken…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Release Candidate" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Toont het bericht over deze Release Candidate opnieuw." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Back-up" #: qt/app.py:733 msgid "&Restore" msgstr "Te&rugzetten" #: qt/app.py:739 msgid "&Help" msgstr "&Hulp" #: qt/app.py:790 msgid "Systray Icon" msgstr "Systeemvak pictogram" #: qt/app.py:796 msgid "Automatic" msgstr "Automatisch" #: qt/app.py:800 msgid "Light icon" msgstr "Licht icoon" #: qt/app.py:801 msgid "Dark icon" msgstr "Donker icoon" #: qt/app.py:824 msgid "Icons only" msgstr "Enkel iconen" #: qt/app.py:827 msgid "Text only" msgstr "Enkel tekst" #: qt/app.py:830 msgid "Text below icons" msgstr "Tekst onder de iconen" #: qt/app.py:833 msgid "Text beside icon" msgstr "Tekst naast de iconen" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Deze map bestaat niet\n" "in de momenteel geselecteerde back-up." #: qt/app.py:1005 msgid "Add to Include" msgstr "Toevoegen aan Opnemen" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Toevoegen aan Uitsluiten" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Als u dit venster sluit, zal Back In Time de computer niet uit kunnen " "schakelen wanneer de back-up voltooid is." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Het venster toch sluiten?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Klaar, geen back-up nodig" #: qt/app.py:1285 msgid "Working:" msgstr "Bezig:" #: qt/app.py:1292 msgid "Working" msgstr "Bezig" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Fout" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Verzonden:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Snelheid:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Geschatte afhandelingstijd:" #: qt/app.py:1490 msgid "Backup:" msgstr "Back-up:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "{path} terugzetten" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "{path} terugzetten naar …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Hallo\n" "U heeft Back In Time nu al een paar keer gebruikt in het {language}.\n" "De vertaling van de geïnstalleerde versie van Back In Time in het {language} is {perc} voltooid. Ongeacht uw niveau van technische expertise kunt u een bijdrage leveren aan de vertaling en daarmee aan Back In Time zelf.\n" "Bezoek {translation_platform_url} als u een bijdrage wilt leveren. Voor verdere hulp en vragen kunt u de {back_in_time_project_website} bezoeken.\n" "Onze excuses voor de onderbreking. Dit bericht zal niet opnieuw worden weergegeven. Dit dialoogvenster is op elk moment beschikbaar via het hulpmenu.\n" "Uw Back In Time-team" #: qt/app.py:1709 msgid "translation platform" msgstr "vertaalplatform" #: qt/app.py:1714 msgid "Website" msgstr "Website" #: qt/app.py:1728 msgid "Your translation" msgstr "Uw vertaling" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "In de Fediverse op Mastodon: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "E-mail naar {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Mailinglijst {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} op de website van het project." #: qt/app.py:1781 msgid "Open an issue" msgstr "Meld een probleem" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "U kunt ook een ander kanaal naar keuze gebruiken." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Deze versie van Back In Time is een Release Candidate en is voornamelijk bedoeld voor stabiliteitstesten ter voorbereiding op de volgende officiële release.\n" "Er worden geen gebruikersgegevens of telemetrie verzameld. Het Back In Time-team is echter zeer geïnteresseerd in het gebruik van de Release Candidate en of het de moeite waard is om dergelijke pre-releaseversies te blijven aanbieden.\n" "Daarom vraagt het team vriendelijk om een korte feedback over het testen van deze versie, zelfs als u geen problemen bent tegengekomen. Zelfs een korte test van een paar minuten zou ons enorm helpen.\n" "U kunt contact met ons opnemen via de volgende contactgegevens:\n" "{contact_list}\n" "In deze versie wordt dit bericht niet meer weergegeven, maar u kunt het op elk moment raadplegen via het helpmenu.\n" "Bedankt voor uw steun en voor uw hulp bij het verbeteren van Back In Time!\n" "Uw Back In Time-team" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Er is slechts {free} vrije plaats beschikbaar op de bestemming, minder dan " "het geconfigureerde minimum van {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Doorgaan met de backup?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Alle nieuwere bestanden in {path} zullen verwijderd worden. Doorgaan?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Alle recentere bestanden in de originele map zullen verwijderd worden. " "Doorgaan?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Let op:{BOLDEND} Het verwijderen van bestanden uit de hoofdmap van het" " bestandssysteem kan uw hele systeem ruïneren." #: qt/app.py:2167 msgid "Backup name" msgstr "Back-up naam" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Deze backup verwijderen?" msgstr[1] "Deze backups verwijderen?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "De taalinstellingen worden pas van kracht na het herstarten van Back In " "Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Versie-beheerde back-ups (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Gebruiksvriendelijke GUI voor versie-beheerde back-ups die het schijfgebruik" " vermindert (root mode)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Versie-beheerde Back-ups" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Gebruiksvriendelijke GUI voor versie-beheerde back-ups die het schijfgebruik" " vermindert" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Vraag" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Back-ups met achtervoegsel {suffix} maken voordat lokale elementen " "overschreven of verwijderd worden." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Nieuwere versies van bestanden worden hernoemd met achtervoegsel {suffix} " "voordat ze worden teruggezet. Als u ze niet meer nodig heeft kunt u ze " "verwijderen met het volgende commando:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Alleen elementen terugzetten die niet bestaan of nieuwer zijn dan die in de " "bestemming. De optie \"{rsync_example}\" wordt gebruikt." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Nieuwere elementen in oorspronkelijke map verwijderen." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Geselecteerde bestanden of mappen naar de oorspronkelijke bestemming " "herstellen en bestanden/mappen die niet in de back-up voorkomen, " "verwijderen. Wees hier uiterst voorzichtig mee want hierdoor worden " "bestanden/mappen verwijderd die waren uitgesloten tijdens het maken van de " "back-up." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Weet u zeker dat u dit element wilt herstellen naar de nieuwe map?" msgstr[1] "" "Weet u zeker dat u deze elementen wilt herstellen naar de nieuwe map?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Weet u zeker dat u dit element wilt herstellen?" msgstr[1] "Weet u zeker dat u deze elementen wilt herstellen?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Gebruikerscallback: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Het gebruiker-callback-script moet een shebang op de eerste regel bevatten " "(bijv. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Verborgen bestanden en mappen tonen (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Taal instellen" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Vertaald: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Systeemstandaard" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "De taal van het besturingssysteem gebruiken." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Back-up Log Weergave" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Laatste logboekweergave" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profiel:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Back-ups:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filter:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Fout, [I] Informatie, [C] Wijziging" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "paden decoderen" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Alles" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Wijzigingen" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Fouten" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informatie" msgstr[1] "Informatie" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "fouten in de rsync-overdracht (experimenteel)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Profielen beheren" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Bewerken" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Toevoegen" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Verwijderen" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Algemeen" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Opnemen" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Uitsluiten" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Verwijderen en Bewaren" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "O&pties" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "&Geavanceerde opties" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Configuratie herstellen" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Nieuw profiel" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Profiel hernoemen" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Profiel \"{name}\" verwijderen?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Kopier symbolische links als bestanden" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Kopieer symbolische links als echte bestanden of mappen in de back-up. " "Selecteer of alle links of alleen de verwijzingen buiten de bron worden " "gekopieerd." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Deze optie kan de back-up meer plaats doen innemen." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Standaard niet actief." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Alle symbolische links worden vervangen door de echte bestanden of mappen " "waar ze naar verwijzen. Dit vergroot het plaatsgebruik van de back-up en kan" " hetzelfde bestand meerdere malen opslaan." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Gebruikt 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Alleen extern" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Alleen links die verwijzen naar items buiten de back-up bron worden " "gekopieerd als bestanden. Dit vergroot het plaatsgebruik van de back-up en " "kan hetzelfde bestand meerdere keren opslaan." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Gebruikt 'rsync --copy-unsafe-links'." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Editor en Office tijdelijke bestanden" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacs back-up bestanden" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs automatisch-bewaren bestanden" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Vim swap bestanden" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Office tijdelijke bestanden" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice en andere OpenDocument Editor vergrendelingsbestanden" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniaturen en Tijdelijke Afbeeldingen" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "Miniatuur cache op GNU/Linux en andere unix-achtige OS'en" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Miniatuur database op Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Metadate map op MacOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Applicatie-specifieke vergrendelingen" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discord applicatie vergrendelingsbestand" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord session vergrendelingsbestand" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Mozilla Firefox & Thunkderbird vergrendelingsbestand" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Caches & Tijdelijke mappen" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Gebruiker applicatie cache" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Tijdelijke map van het systeem" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Pakketcache voor Debian(-gebaseerde) GNU/Linux distributies" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Flatpak app en runtime opslag" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Rubtime mappen van het systeem" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Kernel en proces informatie" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Toestel en andere hardware informatie (sysfs interface)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Apparaat knooppunten" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Runtime systeembestanden" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Andere niet-blijvend" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Lijst van de actueel aangekoppelde bestandssystemen" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Systeem swapfile (virtueel geheugen)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Gnome virtueel bestandssysteem aankoppelpunt" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Herstelde bestandssysteem objecten" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Gemengd" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Metadate map op Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Prullenmand van de gebruiker" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Back-up bestanden van het systeem" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Suggesties voor uitsluiten" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Selecteer veelgebruikte items om toe te voegen aan de back-up uitsluitingen." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Standaard" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Zet terug naar voorgedefinieerde selectie" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Planning" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dag:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Dag van de week:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Tijd:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Uren:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "na het uur" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minuten:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Back In Time uitvoeren zodra de schijf is aangesloten (slechts één keer per " "X dagen). Er zal om het beheerderswachtwoord gevraagd worden." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Back In Time herhaaldelijk uitvoeren. Dit is handig wanneer de computer niet" " regelmatig wordt gebruikt." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Elk(e):" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Het loggen van foutopsporingsberichten inschakelen" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Schrijft berichten van debug-gehalte naar het systeemlogboek via \"--" "debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Let op: gebruik dit alleen tijdelijk voor diagnostische doeleinden, omdat " "het een grote hoeveelheid uitvoer genereert." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Uitgeschakeld" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Bij elke opstart/herstart" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Elke minuut" msgstr[1] "Elke {n} minuten" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Elk uur" msgstr[1] "Elke {n} uur" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Aangepaste tijdstippen" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Dagelijks" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Herhaaldelijk (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Zodra de schijf is aangesloten (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Wekelijks" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Maandelijks" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Jaarlijks" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Uur/Uren" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dag(en)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Week/Weken" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Maand(en)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Aangepaste uren kunnen alleen een door komma's gescheiden lijst met uren " "zijn (bijv. 8,12,18,23) of */3 voor periodieke back-ups om de 3 uur." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "Vel ei eksisterande privatnykelfil (normalt namngitt \"id_ed25519\" eller " "\"id_rsa\" i eldre oppsett)." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "Ny SSH lykjel i {path} kunne ikkje lagast" #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "Full sti til augneblinksbilete:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Privat lykjel:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Vert:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Brukar:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" #: qt/manageprofiles/tab_exclude.py:85 #, fuzzy msgid "Exclude patterns, files or directories" msgstr "Ekskluder mønster, filer eller mapper" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Legg til fil" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Legg til mappe" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Spørsmål" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Ekskluder filer større enn:" #: qt/manageprofiles/tab_exclude.py:138 #, fuzzy, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Ekskluder filer større enn: " #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Ekskluder filer høgare enn verdien %(prefix)s.\n" "Med 'full rsync modus' avslått vil kun nye filer bli handsama\n" "fordi rsync handterer dette som eit overførings val, ikkje ei ekskludering.\n" "Så store filer som har blitt tatt backup av før blir i snapshot\n" "sjølv om dei har blitt endra." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Ekskluder mønster" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Ekskluder fil" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Ekskluder mappe" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Køyr 'rsync' med '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "Som cron jobb" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "på fjern vert" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "Medan eit manuelt snapshot vert tatt" #: qt/manageprofiles/tab_expert_options.py:110 #, fuzzy msgid "Please install 'nocache' to enable this option." msgstr "(Ver gild å installer 'nocache' for å aktivera dette valet)" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "På lokal maskin" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Omdiriger stdout til /dev/null i kronjobbar." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Omdiriger stderr til /dev/null i kronjobbar." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/sek" #: qt/manageprofiles/tab_expert_options.py:163 #, fuzzy msgid "Limit rsync bandwidth usage:" msgstr "Avgrensa rsync båndbreddebruk" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Hald på ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Hald på utvida attributtar (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Valet må vera sitert t.d. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Lim inn ytterlegare val til rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "" #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variablar må ha kontrollsekvensen \\$FOO. Dette påverkar ikkje rsync. For å " "legge til prefiks for rsync, bruk \"{example_value}\" med " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "standardverdi" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Legg til prefiks til ssh kommandoer" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Sjekk om nettverksvert er på nettet" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Åtvaring: dersom deaktivert og nettverksverten ikkje er tilgjengeleg kan det" " føre til rare feil." #: qt/manageprofiles/tab_expert_options.py:315 #, fuzzy msgid "Check if remote host supports all necessary commands." msgstr "Sjekk om nettverksvert støttar alle naudsynte kommandoar" #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Åtvaring: Om avskrudd og nettverksverten ikkje støttar alle påkrevde " "kommandoar kan dette føre til rare feil." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(standardverdi: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "deaktivert" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "aktivert" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modus:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Kvar vil du lagra snapshot" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH innstillingar" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Sti:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Ny profil" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Passord" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Lagra passord til lykjelring" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "Cache passord for Cron (Tryggleiksproblem: root kan lesa passord)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avansert" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 #, fuzzy msgid "Full backup path:" msgstr "Full sti til augneblinksbilete:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Passordene stemmer ikkje overeins." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Autentiseringa av verten {host} er ikkje mogleg." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype}-nykelen sitt fingeravtrykk er:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Verifiser dette fingeravtrykket. Vil du legge det til di 'known_hosts' fil?" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Lage ei ny kryptert mappe?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "SSH privatlykjel" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, fuzzy, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Ny SSH lykjel i {path} kunne ikkje lagast" #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Inkluder filer og mapper" #: qt/manageprofiles/tab_include.py:168 #, fuzzy, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" er ein symlink. Det lenka målet vil ikkje bli tatt backup av med mindre du inkluderer det og.\n" "Har du lyst til å inkludera symlinkmålet i staden?" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Inkluder fil" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Inkluder mappe" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Aktiver notifikasjonar" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Deaktiver snapshot når batteri er i bruk" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Straumstatus ikkje tilgjengeleg frå systemet" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Køyr kun eit snapshot i slengen" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Andre snapshot blir blokkerte intil der aktive snapshot er ferdig\n" "Dette er eit globalt val. Så det vil påverka alle profilar for denne brukaren.\n" "Du må aktivera dette for alle andre brukarar og." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Backup endrar filer under gjennoppretting" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Fortsett ved feil (hald på ufullstendige snapshot)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Bruk sjekksum for å oppdaga endringar" #: qt/manageprofiles/tab_options.py:86 #, fuzzy msgid "Create a new backup whether there were changes or not." msgstr "Ta eit nytt snapshot uansett om det har vore endringar eller ei." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 #, fuzzy msgid "Log Level:" msgstr "Loggnivå" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Ingen" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Ikkje fjern namngitte snapshot." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Ikkje fjern namngitte snapshot." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "År" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Fjern augneblinksbilete" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Kalenderveker med mondag som fyrste dag. Gjeldande veke er ignorert." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12-månaders periode. Gjeldande månad er ignorert." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Tilbakehaldsretningslinje" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Køyr i bakgrunnen på nettverksvert." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Smart fjerning vil køyre på nettverkstenaren, ikkje lokalt. Kommandoane " "\"bash\", \"screen\" og \"flock\" må vere installerte og tilgjengeleg på " "nettverkstenaren." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Om valt vil Back In Time fyrst teste nettverkstenaren." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dagane er talde frå og med i dag." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Hald på snapshots dei siste" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "Dag(ar)." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Hald på eit augneblinksbilete per dag for dei siste" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "Vekene er talde frå og med denne veka. Ei veke startar på måndag." #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Hald på eit augneblinksbilete per veka for dei siste" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "Veke(r)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Månedane er talde som kalendermånader frå og med inneverande månad." #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Hald på eit augneblinksbilete per månad for dei siste" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "Månad(ar)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Hald på snapshots dei siste" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "" #: qt/manageprofiles/tab_remove_retention.py:389 #, fuzzy msgid "… the free space is less than" msgstr "Viss ledig plass er mindre enn" #: qt/manageprofiles/tab_remove_retention.py:394 #, fuzzy msgid "… the free inodes are less than" msgstr "Viss ledige inodes er mindre enn" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Fjern gamle augneblinksbilete" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Snarvegar" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Sikkerheitskopieringsmapper" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Sjå siste logg" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Start {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Arbeider…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Arbeider…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Dersom mappa er på ein ekstern eller fjerntilkopla disk, må den monterast " "manuelt først." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Vis gøymde filer" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Inkluder filer og mapper" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Oppretting av filer i denne katalogen feila:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Vis full logg" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Slår av systemet etter at augneblinksbilete er ferdig." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Slå av" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Slå av" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" #: qt/snapshotsdialog.py:63 #, fuzzy msgid "Options about comparing backups" msgstr "Val om å samanlikna snapshot" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Kommando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametrar:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Bruk %1 og %2 for sti parametrar" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Sett ein diff-kommando eller trykk avbryt." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Sikkerheitskopier" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Berre forskjellige snapshot" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "List opp like snapshot til: " #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Djupsjekk (Meir eksakt, men treigare)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Slett" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Vel alle" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Samanlikna" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Gå til" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Alternativa" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Vil du verkeleg sletta {file} i dette snapshot{snapshot_id}?" #: qt/snapshotsdialog.py:445 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Vil du verkeleg sletta {file} i {count} snapshot?" #: qt/snapshotsdialog.py:448 #, fuzzy msgid "WARNING: This cannot be revoked." msgstr "Dette kan ikkje gjerast om!" #: qt/snapshotsdialog.py:465 #, fuzzy, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Ekskluder {path} frå nye snapshot?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "I dag" #: qt/timeline.py:77 msgid "Yesterday" msgstr "I går" #: qt/timeline.py:87 msgid "This week" msgstr "Denne veka" #: qt/timeline.py:95 msgid "Last week" msgstr "Førre veke" #: qt/timeline.py:270 #, fuzzy msgid "This is NOT a backup but a live view of the local files." msgstr "" "Dette er IKKJE eit snapshot, det er ei notids visning av dine lokale filer" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Sist sjekka {time}" backintime-1.6.1/common/po/pl.po000066400000000000000000002364171514264426600165350ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Paweł Hołuj # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-01-27 08:10+0000\n" "Last-Translator: Merik \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Wszystkie licencje użyte w tym projekcie znajdują się w katalogu {dir_link}." " Aby wyodrębnić informacje o licencjach i prawach autorskich dla " "poszczególnych plików przy użyciu metadanych SPDX, zapoznaj się " "z {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Ostrzeżenie" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Profil główny" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokalny (zaszyfrowane EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (zaszyfrowane EncFS)" #: common/config.py:237 msgid "Local" msgstr "Lokalny" #: common/config.py:240 msgid "Local encrypted" msgstr "Zaszyfrowany lokalnie" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Szyfrowanie" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Prywatny klucz SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: „{name}”" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Katalog kopii zapasowych jest nieprawidłowy." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "" "Należy wybrać co najmniej jeden katalog do utworzenia kopii zapasowej." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Katalog: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Tego katalogu nie można uwzględnić w kopii zapasowej, ponieważ jest on " "częścią miejsca docelowego kopii zapasowej." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Wartość parametru „Usuń najstarszą kopię zapasową, jeśli ilość wolnego " "miejsca jest mniejsza niż” ({val_one}) musi być mniejsza lub równa progowi " "parametru „Ostrzegaj, jeśli ilość wolnego miejsca na dysku spadnie poniżej” " "({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Dostosuj ustawienia tak, aby limit usuwania kopii zapasowych nie był wyższy " "niż limit ostrzegawczy." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Harmonogram udev nie działa z trybem {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Nie udało się zapisać nowej tablicy zadań (crontab)." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron nie działa pomimo dostępnego polecenia crontab. Zaplanowane zadania " "tworzenia kopii zapasowych nie będą działać. Cron może być zainstalowany, " "ale nie jest włączony. Spróbuj uruchomić dwa polecenia: „systemctl enable " "cron” i „systemctl start cron” lub skorzystaj z kanałów wsparcia aktualnie " "używanej dystrybucji GNU/Linux, aby uzyskać pomoc." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Nie udało się zapisać konfiguracji" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Nie udało się wczytać konfiguracji" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profil „{name}” już istnieje." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Ostatniego profilu nie można usunąć." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Nie można zamontować „{command}”" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Nie znaleziono konfiguracji dla zaszyfrowanego katalogu." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Czy stworzyć nowy zaszyfrowany katalog?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Anuluj" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Ponownie wpisz hasło EncFS, aby potwierdzić." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Hasła EncFS nie są takie same." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Utwórz migawkę" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Nie można zainicjować zaszyfrowanej ścieżki „{command}”" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Nie można odmontować {mountprocess} z {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "Nie znaleziono {command}. Zainstaluj to (np. poprzez „{installcommand}”)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Punkt montowania {mntpoint} nie jest pusty." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Wpisz hasło do profilu „{profile}” {mode}:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Nie można zainstalować reguły Udev dla profilu {profile_id}. Usługa DBus " "„{dbus_interface}” była niedostępna." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Nie udało się odnaleźć UUID dla {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "NIEPOWODZENIE" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Przywracanie uprawnień" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Gotowe" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Następujące wpisy z listy uwzględnionych nie mają odpowiadającego im pliku " "lub katalogu w źródle kopii zapasowej:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Kopia zapasowa przełożona z powodu pracy na baterii" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Nie można odnaleźć katalogu kopii zapasowych." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Jeśli znajduje się na dysku wymiennym, podłącz go." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Pozostała {n} sekunda." msgstr[1] "Pozostały {n} sekundy." msgstr[2] "Pozostało {n} sekund." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Nie udało się utworzyć kopii zapasowej {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Prosimy o cierpliwość. Finalizowanie…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Nie można utworzyć katalogu." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Zapisywanie pliku konfiguracyjnego…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Zapisywanie uprawnień…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Znaleziono niekompletną kopię zapasową {snapshot_id}, która może być " "kontynuowana." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Usuwanie niekompletnego katalogu {snapshot_id} z ostatniego uruchomienia" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Nie mogę usunąć katalogu" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Tworzenie kopii zapasowej" #: common/snapshots.py:1517 msgid "Success" msgstr "Sukces" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Transfer częściowy z powodu błędu" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transfer częściowy z powodu zaginionych plików źródłowych (patrz „man " "rsync”)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "„rsync” zakończył się kodem wyjścia {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Więcej informacji można znaleźć w „man rsync”" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negatywne kody wyjściowe rsync to liczby sygnałów, patrz „kill -l” i „man " "kill”" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Nic się nie zmieniło, nie jest konieczna żadna nowa kopia zapasowa" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Nie można zmienić nazwy z {new_path} na {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Stosowanie reguł usuwania starych kopii zapasowych" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Stosowanie zasad przechowywania" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Próba utrzymamia minimum wolnego miejsca" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Próba utrzymania minimum {perc} wolnych i-węzłów" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Teraz" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Nie można zamontować {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" "Nie znaleziono programu ssh-agent. Upewnij się, że jest zainstalowany." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Nie można odblokować klucza prywatnego SSH. Hasło niewłaściwe lub " "niedostępne dla cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Zdalna ścieżka istnieje, ale nie jest katalogiem." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Ścieżka zdalna nie jest zapisywalna." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Ścieżka zdalna nie jest wykonywalna." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Nie można utworzyć zdalnej ścieżki." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Zdalny host {host} nie obsługuje {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Sprawdzanie poleceń na hoście {host} zwróciło nieznany błąd" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Zdalny host {host} nie obsługuje dowiązań twardych" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Skopiuj klucz publiczny SSH „{pubkey}” do zdalnego hosta „{host}”." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Wpisz hasło dla „{user}”." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Docelowy system plików dla {path} jest sformatowany za pomocą NTFS, w którym" " występują znane niezgodności z systemami plików w stylu uniksowym." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} nie jest prawidłowym katalogiem." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Utworzenie następującego katalogu nie powiodło się:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Dostęp do zapisu może być ograniczony." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Docelowy system plików dla {path} jest sformatowany za pomocą FAT, który nie" " wspiera dowiązań twardych. Użyj natywnego systemu plików GNU/Linux." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Docelowy system plików dla {path} to udział zamontowany za pomocą SMB. " "Upewnij się, że zdalny serwer SMB wspiera dowiązania symboliczne lub aktywuj" " „{copyLinks}” w „{expertOptions}”." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopiowanie dowiązań (odwołanie dowiązań symbolicznych)" #: common/tools.py:487 msgid "Expert Options" msgstr "Opcje zaawansowane" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Docelowy system plików dla {path} to udział zamontowany za pomocą sshfs, " "który nie wspiera dowiązań twardych. Użyj trybu „SSH”." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Tworzenie pliku w tym katalogu nie powiodło się:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Informacje o Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Prawo autorskie:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Autorzy:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Tłumacze:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Paweł Hołuj " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Informacje o tłumaczach w bieżącym języku są niedostępne." #: qt/aboutdlg.py:116 msgid "this link" msgstr "to łącze" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Kliknij {thislink}, aby uzyskać informacje o tłumaczach wszystkich języków." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Strona internetowa projektu" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Instrukcja obsługi" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Otwórz instrukcję obsługi w przeglądarce (lokalnie, jeśli jest dostępna, " "w przeciwnym razie online)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Wersja{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} prawdopodobnie działa po raz pierwszy, ponieważ nie znaleziono " "żadnej konfiguracji." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Czy zaimportować istniejącą konfigurację z kopii zapasowej lub innego " "komputera?" #: qt/app.py:395 msgid "Then press OK." msgstr "Następnie naciśnij OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Utwórz kopię zapasową" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Użyj czasu i rozmiaru modyfikacji do wykrywania zmian w pliku." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Utwórz kopię zapasową (tryb sumy kontrolnej)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Używaj sum kontrolnych do wykrywania zmian plików." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Wstrzymaj tworzenie kopii zapasowej" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Wznów tworzenie kopii zapasowej" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Zatrzymaj tworzenie kopii zapasowej" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Odśwież listę kopii zapasowych" #: qt/app.py:524 msgid "Name backup" msgstr "Nazwij kopię zapasową" #: qt/app.py:528 msgid "Remove backup" msgstr "Usuń kopię zapasową" #: qt/app.py:532 msgid "Open backup log" msgstr "Otwórz dziennik kopii zapasowej" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Wyświetl dziennik wybranej kopii zapasowej." #: qt/app.py:536 msgid "Open last backup log" msgstr "Otwórz dziennik ostatniej kopii zapasowej" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Wyświetl dziennik ostatniej kopii zapasowej." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Zarządzaj profilami…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Edytuj user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Zamknięcie" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Zamknij system po zakończeniu tworzenia kopii zapasowej." #: qt/app.py:552 msgid "Setup language…" msgstr "Ustaw język…" #: qt/app.py:556 msgid "Exit" msgstr "Wyjście" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man page: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Wyświetla man page dotyczącą Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man page: Plik konfiguracyjny profili" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Wyświetla man page dotyczącą pliku konfiguracyjnego profili (backintime-" "config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Otwórz witrynę Back In Time w przeglądarce" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Lista zmian" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Otwórz dziennik zmian (lokalnie, jeśli jest dostępny, w przeciwnym razie " "online)" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Otwórz często zadawane pytania (FAQ) w przeglądarce" #: qt/app.py:593 msgid "Ask a question" msgstr "Zadaj pytanie" #: qt/app.py:597 msgid "Report a bug" msgstr "Zgłoś błąd" #: qt/app.py:600 msgid "Translation" msgstr "Tłumaczenie" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Ponownie pokazuje komunikat o uczestnictwie w tłumaczeniu." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Przejście szyfrowania (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Ponownie pokazuje komunikat o usuwaniu EncFS." #: qt/app.py:615 msgid "About" msgstr "O programie" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Przywróć" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Przywróć wybrane pliki lub katalogi do pierwotnej lokalizacji." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Przywróć do…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Przywróć wybrane pliki lub katalogi do nowej lokalizacji." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Przywróć aktualnie wyświetlany katalog i całą jego zawartość do pierwotnej " "lokalizacji." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Przywróć aktualnie wyświetlany katalog i całą jego zawartość do nowej " "lokalizacji." #: qt/app.py:640 msgid "Up" msgstr "Do góry" #: qt/app.py:643 msgid "Show hidden files" msgstr "Pokaż ukryte pliki" #: qt/app.py:646 msgid "Compare backups…" msgstr "Porównaj kopie zapasowe…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Wydanie kandydujące" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Wyświetla ponownie komunikat o wydaniu kandydującym." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Kopia zapasowa" #: qt/app.py:733 msgid "&Restore" msgstr "&Przywróć" #: qt/app.py:739 msgid "&Help" msgstr "P&omoc" #: qt/app.py:790 msgid "Systray Icon" msgstr "Ikona zasobnika systemowego" #: qt/app.py:796 msgid "Automatic" msgstr "Automatycznie" #: qt/app.py:800 msgid "Light icon" msgstr "Jasna ikona" #: qt/app.py:801 msgid "Dark icon" msgstr "Ciemna ikona" #: qt/app.py:824 msgid "Icons only" msgstr "Tylko ikony" #: qt/app.py:827 msgid "Text only" msgstr "Tylko tekst" #: qt/app.py:830 msgid "Text below icons" msgstr "Tekst pod ikonami" #: qt/app.py:833 msgid "Text beside icon" msgstr "Tekst obok ikony" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Ten katalog nie istnieje\n" "w wybranej kopii zapasowej." #: qt/app.py:1005 msgid "Add to Include" msgstr "Dodaj do uwzględnionych" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Dodaj do wykluczonych" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Jeśli to okno będzie zamknięte, Back In Time nie będzie mógł zamknąć systemu" " po zakończeniu tworzenia kopii zapasowej." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Zamknąć okno mimo wszystko?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Gotowe, archiwizacja niepotrzebna" #: qt/app.py:1285 msgid "Working:" msgstr "Działanie:" #: qt/app.py:1292 msgid "Working" msgstr "Działanie" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Błąd" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Wysłane:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Prędkość:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Czas do końca:" #: qt/app.py:1490 msgid "Backup:" msgstr "Kopia zapasowa:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Przywróć {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Przywróć {path} do…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Witaj!\n" "Back In Time w języku {language} został użyty już kilka razy.\n" "Tłumaczenie zainstalowanej wersji Back In Time na język {language} jest kompletne w {perc}. Możesz pomóc w ulepszeniu tłumaczeń, a poprzez to w ulepszaniu samego Back In Time bez posiadania żadnej wiedzy technicznej.\n" "Odwiedź {translation_platform_url}, jeśli chcesz pomóc. W celu uzyskania odpowiedzi na pytania lub dalszych wskazówek odwiedź {back_in_time_project_website}.\n" "Przepraszamy za utrudniania, ten komunikat nie pojawi się sam ponownie, ale będzie dostępny w menu pomocy.\n" "Zespół Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "platformę do tłumaczenia" #: qt/app.py:1714 msgid "Website" msgstr "Strona WWW" #: qt/app.py:1728 msgid "Your translation" msgstr "Twoje tłumaczenia" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "W Fediverse na platformie Mastodon: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Wyślij wiadomość e-mail na adres {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Lista mailingowa {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} na stronie internetowej projektu." #: qt/app.py:1781 msgid "Open an issue" msgstr "Otwórz zagadnienie" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Możesz również użyć innego wybranego kanału." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Ta wersja Back In Time jest wydaniem kandydującym i jest przeznaczona głównie do testów stabilności w przygotowaniu do kolejnej oficjalnej wersji.\n" "Nie są gromadzone żadne dane użytkowników ani dane telemetryczne. Jednak zespół Back In Time jest bardzo zainteresowany tym, czy wydanie kandydujące jest używane i czy warto nadal udostępniać takie wersje przedpremierowe.\n" "Dlatego zespół uprzejmie prosi użytkowników o krótką opinię na temat tego, czy ta wersja była przez nich testowana, nawet jeśli nie napotkali żadnych problemów. Zaledwie krótki test trwający kilka minut bardzo by nam pomógł.\n" "Dostępne są następujące opcje kontaktu:\n" "{contact_list}\n" "W tej wersji ten komunikat nie zostanie ponownie wyświetlony, ale można uzyskać do niego dostęp w dowolnym momencie za pośrednictwem menu pomocy.\n" "Dziękujemy za wsparcie i pomoc w ulepszaniu Back In Time!\n" "Twój zespół Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Dostępne jest tylko {free} wolnego miejsca w miejscu docelowym, co jest " "poniżej skonfigurowanego progu {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Kontynuować tworzenie kopii zapasowej?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Wszystkie nowsze pliki w  {path} zostaną usunięte. Kontynuować?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Wszystkie nowsze pliki w oryginalnym katalogu zostaną usunięte. Kontynuować?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Ostrzeżenie{BOLDEND}: usunięcie plików z katalogu głównego systemu " "plików może spowodować uszkodzenie całego systemu." #: qt/app.py:2167 msgid "Backup name" msgstr "Nazwa kopii zapasowej" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Usunąć tę kopię zapasową?" msgstr[1] "Usunąć te kopie zapasowe?" msgstr[2] "Usunąć te kopie zapasowe?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Ustawienia języka zaczną obowiązywać dopiero po ponownym uruchomieniu " "programu Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Wersjonowane kopie zapasowe (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Łatwy w obsłudze interfejs do tworzenia wersjonowanych kopii zapasowych " "(root)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Wersjonowane kopie zapasowe" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Łatwy w obsłudze interfejs do tworzenia wersjonowanych kopii zapasowych" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Pytanie" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Utwórz kopie zapasowe z końcowym {suffix} przed nadpisaniem lub usunięciem " "elementów lokalnych." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Przed przywróceniem nowsze wersje plików zostaną przemianowane z dodanym " "{suffix}. Te pliki można usunąć za pomocą następującego polecenia:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Przywróć tylko te elementy, które nie istnieją lub są nowsze niż te " "w miejscu docelowym. Korzystanie z opcji „{rsync_example}”." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Usuń nowsze elementy z pierwotnego katalogu." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Przywróć wybrane pliki lub katalogi do oryginalnego miejsca docelowego " "i usuń pliki lub katalogi, których nie ma w kopii zapasowej. Zachowaj " "szczególną ostrożność, ponieważ spowoduje to usunięcie plików i katalogów, " "które zostały wykluczone podczas tworzenia kopii zapasowej." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Czy na pewno przywrócić ten element do nowego katalogu?" msgstr[1] "Czy na pewno przywrócić te elementy do nowego katalogu?" msgstr[2] "Czy na pewno przywrócić te elementy do nowego katalogu?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Czy na pewno przywrócić ten element?" msgstr[1] "Czy na pewno przywrócić te elementy?" msgstr[2] "Czy na pewno przywrócić te elementy?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Wywołanie zwrotne użytkownika: „{filename}”" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Skrypt wywołania zwrotnego użytkownika musi zawierać shebang w pierwszym " "wierszu (np. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Pokaż/ukryj ukryte pliki i katalogi (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Ustaw język" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Przetłumaczono: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Domyślne systemowe" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Użyj języka systemu operacyjnego." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Widok dziennika kopii zapasowej" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Ostatni widok dziennika" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Kopie zapasowe:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtr:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] błąd, [I] informacja, [C] zmiana" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "dekoduj ścieżki" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "wszystkie" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "zmiany" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "błędy" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informacja" msgstr[1] "Informacje" msgstr[2] "Informacji" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "błędy transferu rsync (eksperymentalne)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Zarządzaj profilami" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Edycja" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Dodaj" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Usuń" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Ogólne" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Dołącz" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Wyklucz" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Usuń i &przechowuj" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Ustawienia" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Opcje e&ksperta" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Przywróć konfigurację" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Nowy profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Zmień nazwę profilu" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Usuń profil „{name}”?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Kopiuj dowiązania symboliczne jako pliki" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Kopiuj dowiązania symboliczne jako rzeczywiste pliki lub katalogi w kopii " "zapasowej. Wybierz, czy mają zostać skopiowane wszystkie dowiązania, czy " "tylko te wskazujące na zewnątrz źródła." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Ta opcja może zwiększyć rozmiar kopii zapasowej." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Domyślnie wyłączona." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Wszystkie dowiązania symboliczne są zastępowane rzeczywistymi plikami lub " "katalogami, do których wskazują. Zwiększa to rozmiar kopii zapasowej i może " "powodować wielokrotne zapisywanie tych samych plików." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Używa „rsync --copy-links”." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Tylko zewnętrzne" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Tylko dowiązania prowadzące poza źródło kopii zapasowej są kopiowane jako " "pliki. Zwiększa to rozmiar kopii zapasowej i może powodować wielokrotne " "zapisywanie tych samych plików." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Używa „rsync --copy-unsafe-links”." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Pliki tymczasowe edytora i pakietu biurowego" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Pliki kopii zapasowej Emacsa" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Pliki automatycznego zapisywania Emacsa" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Pliki wymiany Vima" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Pliki tymczasowe pakietu Microsoft Office" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "Pliki blokady LibreOffice i innych edytorów OpenDocument" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Miniatury i zdjęcia tymczasowe" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "Pamięć podręczna miniatur w systemach GNU/Linux i innych systemach " "uniksopodobnych" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Baza miniatur w systemie Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Katalog metadanych w systemie MacOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Blokady specyficzne dla aplikacji" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Plik blokady aplikacji Discord" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Plik blokady sesji aplikacji Discord" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Plik blokady programów Mozilla Firefox i  Thunderbird" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Pamięci podręczne i katalogi tymczasowe" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Pamięć podręczna aplikacji użytkownika" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Tymczasowy katalog systemowy" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Pamięć podręczna pakietów dystrybucji GNU/Linux opartych na Debianie" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Repozytorium aplikacji i środowiska wykonawczego Flatpak" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Katalogi środowiska wykonawczego systemu" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Informacje o jądrze i procesach" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Informacje o urządzeniu i innym sprzęcie (interfejs sysfs)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Węzły urządzeń" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Pliki systemowe środowiska wykonawczego" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Inne nietrwałe" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Lista aktualnie zamontowanych systemów plików" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Plik wymiany systemu (pamięć wirtualna)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Punkt montowania wirtualnego systemu plików w środowisku GNOME" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Odzyskane obiekty systemu plików" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Różne" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Katalog metadanych w systemie Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Kosz użytkownika" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Pliki kopii zapasowej systemu" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Wyklucz sugestie" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Wybierz często używane elementy, które chcesz dodać do wykluczeń kopii " "zapasowej." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Domyślne" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Resetuj do wstępnie zdefiniowanego wyboru" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Harmonogram" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dzień:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Dzień powszedni:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Czas:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Godziny:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "po godzinie" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minuty:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Uruchom Back In Time, gdy tylko dysk zostanie podłączony (tylko raz co X " "dni). Pojawi się monit o hasło sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Uruchamiaj Back In Time wielokrotnie. Jest to przydatne, jeśli komputer nie " "działa regularnie." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Co:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Włącz rejestrowanie komunikatów debugowania" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Zapisuje komunikaty poziomu debugowania w dzienniku systemowym poprzez " "„--debug”." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Uwaga: używaj tego tylko tymczasowo do diagnostyki, ponieważ generuje to " "dużą ilość danych wyjściowych." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Nieaktywny" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Przy każdym uruchomieniu / restarcie" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Co minutę" msgstr[1] "Co {n} minuty" msgstr[2] "Co {n} minut" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Co godzinę" msgstr[1] "Co {n} godziny" msgstr[2] "Co {n} godzin" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Własny harmonogram" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Codziennie" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Wielokrotnie (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Po podłączeniu dysku (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Co tydzień" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Co miesiąc" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Co rok" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "godzin" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "dni" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "tygodni" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "miesięcy" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Godziny niestandardowe mogą być jedynie listą godzin oddzielonych " "przecinkami (np. 8,12,18,23) lub */3 w przypadku okresowych kopii zapasowych" " co 3 godziny." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Escolher uma chave privada existente de outro local." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Falha ao criar chave SSH sem senha." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Caminho completo: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Chave Privada:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Usar configuração SSH do sistema" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Deixa o ficheiro de chave desselecionado. Conexões SSH usarão a configuração" " do cliente existente do sistema (e.g., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proxy SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Servidor:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Porta:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Usuário:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Ligar ao servidor de destino através deste proxy (também conhecido com " "servidor de salto). Ver \"-J\" na documentação do comando \"ssh\" ou " "\"ProxyJump\" em \"ssh_config\" para maiores detalhes." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Informação{ENDBOLD}: no modo \"encriptado por SSH\", apenas funcionam " "asteriscos simples ou duplos (exemplo, {example2}). Outros tipos de " "caracteres especiais e padrões serão ignorados (exemplo, {example1}). Os " "nomes de arquivos são imprevisíveis neste modo devido à encriptação por " "EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Excluir padrões, arquivos ou pastas" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Adicionar padrão" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Adicionar ficheiros" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Adicionar pastas" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Sugestões" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Selecione dos items usados frequementemente para o adicionar à lista de " "exclusão." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Excluir arquivos maiores que:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Excluir arquivos maiores que o valor em {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Com o 'modo rsync completo' desativado, isto apenas afetará os novos " "arquivos, uma vez que para o rsync esta é uma opção de transferência, não " "uma opção de exclusão. Portanto, arquivos grandes que se encontram presentes" " em cópias de segurança antigas irão persistir nas cópias, mesmo que tenham " "sido modificados." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Excluir padrão" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Insira um padrão de exclusão:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Para ajuda, use a página de ‘man’ secção {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Abrir página de man rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Excluir arquivos" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Excluir diretórios" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "Desativado porque este padrão não funciona no modo 'SSH encriptado'." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Estas opções dão para configurações avançadas. Modifique somente o que você " "tiver conhecimento dos resultados." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Execute 'rsync' com '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "como cron job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "no servidor remoto" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "ao tirar uma cópia manual" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Por favor instale 'nocache' para ativar esta opção." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "na máquina local" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Redirecione stdout para /dev/null em cronjobs." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "O Cron enviará automaticamente um e-mail com a saída anexada dos cronjobs se" " estiver instalado um MTA." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Redirecione stderr para /dev/null em cronjobs." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "O Cron enviará automaticamente um e-mail com erros anexados de cronjobs se " "um MTA estiver instalado." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/seg" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Limite a utilização da largura de banda rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Preservar ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Preservar atributos estendidos (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Restringir a um sistema de arquivos" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "As opções devem ser citadas, p. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Cole opções adicionais para rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefixo a ser executado antes de cada comando no servidor remoto." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "As variáveis precisam de ser escapadas com \\$FOO. Isto não afeta o rsync. " "Assim, para adicionar um prefixo ao rsync, utilize \"{example_value}\" com " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "padrão" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Adicionar prefixo aos comandos SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Verificar se o servidor remoto está online" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Aviso: Se estiver desativado e o servidor remoto não estiver disponível, " "isto poderá levar a alguns erros estranhos." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Verifique se o servidor remoto suporta todos os comandos necessários." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Aviso: Se estiver desativado e o servidor remoto não suportar todos os " "comandos necessários, poderá levar a alguns erros estranhos." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(padrão: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "desativado" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "ativado" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Modo:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Onde guardar as cópias de segurança" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Definições de SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Caminho:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Ficheiro da chave:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Senha" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Guardar a Senha em um Keyring" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Senha de Cache para Cron (problema de segurança: o root consegue ler a " "senha)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avançado" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Caminho completo da cópia:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "A planificação está desativada porque nenhuma instalação do cron foi " "encontrado. Por favor, instale cron para criar cópias de segurança " "planificado." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "O caminho de destino da cópia não pode estar vazio." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "A password de encriptação não pode estar vazia." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Um erro ocorreu ao tentar entrar no servidor remoto. A seguinte mensagem foi" " recebida:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Para ativar login sem password, a chave de SSH pública pode ser copiada para" " o host remoto." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Proceder a copiar a chave de SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Não foi possível copiar a chave pública de SSH. Isto poderá ser devido a um " "problema de conexão ou permissão." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "A autenticidade do servidor {host} não pode ser verificada." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "A impressão digital da chave {keytype} é:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Verifique esta impressão digital. Gostaria de adicioná-la ao arquivo de " "'known_hosts'?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Mudar mesmo a pasta de cópias de segurança?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "O destino de cópia selecionado não está vazio." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Precisa de estar vazio para usar encriptação." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Ficheiro inválido: Não é uma chave SSH privada" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "O ficheiro selecionado ({path}) parece ser uma chave de SSH pública. Por " "favor, selecione um ficheiro de chave privada (sem uma extensão\".pub\")." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "O ficheiro {path} já existe. Impossível criar uma chave SSH com esse nome." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Falha ao criar nova chave SSH em {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Incluir arquivos e pastas" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" é um link simbólico (symlink). Não será feito uma cópia de " "segurança do destino selecionado até o incluir, também." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Incluir o alvo do link simbólico (symlink)?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Incluir ficheiros" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Incluir pastas" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Ativar notificações" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Desativar cópias quando usando a bateria" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Estado de energia não disponível no sistema" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Executar uma cópia de cada vez" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Outras cópias de segurança serão bloqueadas até que a cópia atual esteja " "concluída. Esta é uma opção global. Portanto, isto afetará todos os perfis " "deste utilizador. Mas também precisará ativar isto para todos os outros " "utilizadores." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Cópia de segurança dos arquivos substituídos na restauração" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Continuar com erros (manter cópias incompletas)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Use a soma de verificação para detectar mudanças" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Criar uma cópia independentemente de haver alterações ou não." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Avisar se o espaço de disco é reduzido abaixo" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Mostra um aviso quando o espaço livre no destinatário de cópias de segurança" " é inferior ao valor especificado." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Se a política de Remoção & Retenção estiver ativada e cópias de segurança " "antigas estiverem a ser removidas conforme o espaço livre disponível, este " "valor não pode ser inferior do que o valor estabelecido na política." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Nível de Registro:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nenhum" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "manual do usuário" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "As seguintes regras foram processadas de cima para baixo. As últimas regras " "substituem as anteriores. Verifique o {manual_link} para detalhes e " "exemplos." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Abrir o manual do usuário no navegador." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Manter a cópia mais recente." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "" "A cópia de segurança mais recente é mantida sob quaisquer circunstâncias." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "O comportamento não será alterado." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Manter as cópias nomeadas." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "As cópias de segurança que possuírem um nome dado em adição ao carimbo de " "data/hora padrão, serão mantidas sob quaisquer circunstâncias e não serão " "removidas." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Ano(s)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Remover cópias mais antigas que" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Dias completos. O dia atual será ignorado." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Semanas iniciadas com Segunda-feira. A semana atual sera ignorada." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Períodos de 12 meses. O mês atual será ignorado." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Política de retenção" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Executar em segundo plano no servidor remoto." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "O procedimento de remoção inteligente irá rodar diretamente no servidor, não" " localmente. Os comandos \"bash\", \"screen\"e \"flock\" precisam estar " "instalados e disponíveis no servidor remoto." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Se selecionado, Back In Time primeiramente testará o servidor remoto." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dias contados começando a partir de hoje." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Mantenha todas as cópias pelo(s) último(s)" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "dia(s)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Mantenha uma cópia para cada dia pelo(s) último(s)" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "As semanas começam a ser contadas a partir da semana atual. A semana começa " "na Segunda-feira." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Mantenha uma cópia por semana pela(s) última(s)" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "semana(s)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "Os meses são contados pelo calendário atual e iniciando a partir do mês " "atual." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Mantenha uma cópia por mês pelo(s) último(s)" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "mês/meses." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Os anos são contados pelo calendário e a partir do ano atual." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Mantenha todas cópias a cada ano por" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "todo os anos." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "... o espaço livre é menor que" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "... os inodes livres são menores que" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Remover as cópias de segurança antigas se …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Autenticação é necessária para executar Back In Time como root." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Autenticação é necessária para mudar cópias programadas acionadas por " "conexões de dispositivos de armazenamento externos." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Atalhos" #: qt/placeswidget.py:63 msgid "Places" msgstr "Lugares" #: qt/placeswidget.py:64 msgid "File System" msgstr "Sistema de Ficheiros" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Diretórios de Cópia de Segurança" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Perfil: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Perfil: {profile_name} (por utilizador \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Ver Último Registro" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Iniciar {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Trabalhando…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "página do man: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importar configuração" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Nenhuma diretória selecionada" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importar" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Procurando…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Selecione a pasta de cópias de segurança a partir da qual o arquivo de " "configuração deverá ser importado. O caminho será parecido com: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Se a pasta estiver localizada numa unidade externa ou remota, terá de ser " "montada manualmente antes." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Procurar novamente" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Mostrar diretórios ocultos" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Mostrar/esconder diretórios escondidos (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Nenhuma configuração encontrada neste diretório" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Busca completa." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Mostrar registro completo" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Contagem até Encerramento" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "A cópia de segurança acabou." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Cancelar Encerramento" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Encerrar Agora" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "O sistema irá encerrar em {n} segundo." msgstr[1] "O sistema irá encerrar em {n} segundos." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opções sobre a comparação de cópias" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Comando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parâmetros:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Utilize %1 e %2 para os parâmetros do caminho" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Por favor, defina um comando diff ou pressione Cancelar." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "O comando \"{cmd}\" não pode ser encontrado neste sistema. Por favor, tente " "algo diferente ou aperte Cancelar." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Nenhum parâmetro definido para o comando diff. Utilizando o valor padrão " "\"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Cópias de Segurança" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Apenas cópias diferentes" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Enumerar apenas cópias que sejam iguais a:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Verificação profunda (mais precisa, mas lenta)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Eliminar" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Selecionar Todos" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Comparar" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Ir para" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opções" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Não é possível comparar uma cópia de segurança a si mesma, já que a " "comparação seria redundante." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Deseja realmente apagar {file_or_dir} da cópia de segurança {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Deseja realmente apagar {file_or_dir} das {count} cópias?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "AVISO: Isto não pode ser revogado." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Excluir {path} das futuras cópias?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Modo root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time está a correr sem privilégios de root (completo acesso ao " "sistema)" #: qt/timeline.py:69 msgid "Today" msgstr "Hoje" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Ontem" #: qt/timeline.py:87 msgid "This week" msgstr "Esta semana" #: qt/timeline.py:95 msgid "Last week" msgstr "Semana passada" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Isto NÃO É uma cópia de segurança, mas uma visualização em tempo real dos " "seus arquivos locais." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Última marcação {time}" backintime-1.6.1/common/po/pt_BR.po000066400000000000000000002241151514264426600171200ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Andre Desgualdo Pereira # SPDX-FileCopyrightText: © Scythemare # SPDX-FileCopyrightText: © Yuri Musachio # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-06-09 11:28+0000\n" "Last-Translator: pablolucas890 \n" "Language-Team: Portuguese (Brazil) \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 5.11.4\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Todas as licenças usadas neste projeto estão localizadas no diretório " "{dir_link}. Para extrair informações de licença e direitos autorais por " "arquivo usando metadados SPDX, consulte {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Aviso" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Perfil principal" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Local (criptografado com EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (criptografado com EncFS)" #: common/config.py:237 msgid "Local" msgstr "Local" #: common/config.py:240 msgid "Local encrypted" msgstr "Criptografia local" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Criptografia" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Chave privada SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Perfil: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Diretório de backup inválido." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Pelo menos um diretório precisa ser selecionado para o backup." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Diretório: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Este diretório não pode ser incluído no backup pois faz parte do próprio " "destino do backup." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Agendamento udev não funciona com o modo {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Falha ao escrever um novo crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron não está em execução, embora o comando crontab esteja disponível. Os " "backups agendados não serão executados. O cron pode estar instalado, mas não" " habilitado. Tente os dois comandos \"systemctl enable cron\" e \"systemctl " "start cron\", ou consulte os canais de suporte da distribuição GNU/Linux " "usada atualmente para assistência." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Falha ao salvar a configuração" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Falha ao carregar a configuração" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "O perfil \"{name}\" já existe." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "O último perfil não pode ser removido." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Não foi possível montar '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Configuração para o diretório criptografado não encontrada." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Criar um novo diretório criptografado?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Cancelar" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "Por favor, digite a senha para \"{user}\"." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "A senha não corresponde." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Criar snapshot" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Não foi possível montar '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Incapaz de desmontar {mountprocess} de {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} não encontrado. Por favor, instale-o (ex. via \"{installcommand}\"" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Ponto de montagem {mntpoint} não está vazio." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Digite a senha para o perfil {mode} \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Não foi possível instalar a regra Udev para o perfil {profile_id}. O serviço" " DBus '{dbus_interface}' não estava disponível." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Não foi possível encontrar o UUID para {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "FALHOU" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Restaurar permissões" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Concluído" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Backup adiado devido ao uso de bateria" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Não foi possível encontrar o diretório de backups." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "Se estiver em uma unidade removível, por favor, insira-o." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Aguardando {n} segundo." msgstr[1] "Aguardando {n} segundos." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Falha ao criar o backup {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Por favor, aguarde. Finalizando…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Não é possível criar a pasta." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Salvando o arquivo de configuração…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Salvando as permissões…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Foi encontrado o backup incompleto {snapshot_id} que pode ser continuado." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Removendo o diretório {snapshot_id} incompleto da última execução" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Não é possível remover o diretório" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Criando backup" #: common/snapshots.py:1517 msgid "Success" msgstr "Sucesso" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Transferência parcial devido a um erro" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Transferência parcial devido a arquivos de origem ausentes (consulte 'man " "rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "O 'rsync' terminou com o código de saída {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Veja 'man rsync' para mais detalhes" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Códigos de saída negativos do rsync são números de sinal, veja 'kill -l' e " "'man kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Nada mudou, nenhum novo backup é necessário" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Não foi possível renomear {new_path} para {path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Aplicar regras para remover os backups antigos" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "Aplicar política de retenção" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Tentando manter o mínimo de espaço livre" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Tentando manter no mínimo {perc} de inodes livres" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Agora" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Não foi possível montar {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "" "ssh-agent não encontrado. Por favor, certifique-se de que está instalado." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Não é possível desbloquear a chave privada ssh. A senha está errada ou não " "está disponível para o cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "O caminho remoto existe, mas não é um diretório." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "O caminho remoto não é gravável." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "O caminho remoto não é executável." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Não é possível criar o caminho remoto." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "O host remoto {host} não suporta {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Verificação dos comandos no host {host} retornou um erro desconhecido" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "O host remoto {host} não suporta hardlinks" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Copiar chave ssh pública \"{pubkey}\" para o host remoto \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Por favor, digite a senha para \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "O sistema de arquivos de destino para '{path}' está formatado com NTFS, que " "possui incompatibilidades conhecidas com sistemas de arquivos estilo Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} não é um diretório válido." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "A criação do seguinte diretório falhou:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "O acesso de escrita pode estar restrito." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "O sistema de arquivos de destino para '{path}' está formatado com FAT, que " "não suporta hard-links. Por favor, utilize um sistema de arquivos nativo do " "GNU/Linux." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "O sistema de arquivos de destino para '{path}' é um compartilhamento montado" " via SMB. Por favor, tenha certeza que o servidor SMB remoto suporta links " "simbólicos ou ative a opção '{copyLinks}' em '{expertOptions}'." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Copiar links (desreferenciar links simbólicos)" #: common/tools.py:487 msgid "Expert Options" msgstr "Opções avançadas" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "O sistema de arquivos de destino para '{path}' é um compartilhamento via " "sshfs. O sshfs não suporta hard-links. Por favor, utilize o modo \"SSH\" em " "vez disso." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "A criação de arquivo falhou neste diretório:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Sobre o Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Copyright:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Autores:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Tradutores:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Andre Desgualdo Pereira\n" "Scythemare\n" "Yuri Musachio " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Os créditos dos tradutores não disponíveis para a linguagem atual." #: qt/aboutdlg.py:116 msgid "this link" msgstr "este link" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Clique {thislink} para ver os créditos de tradutores para todos os idiomas." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Site do projeto" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Manual do usuário" #: qt/aboutdlg.py:227 qt/app.py:562 #, fuzzy msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Abrir o manual do usuário no navegador (local, se disponível, caso contrário" " online)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versão{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} parece estar em execução pela primeira vez, pois nenhuma " "configuração foi encontrada." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Importar uma configuração existente (de um diretório de destino de backup ou" " de outro computador)?" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "Criar um backup" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Usar horário de modificação e tamanho para detectar alterações nos arquivos." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "Criar snapshot (modo checksum)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Usar checksums para detectar alterações nos arquivos." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "Pausar o processo de snapshot" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "Retomar o processo de snapshot" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "Parar processo de snapshot" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "Atualizar lista de snapshots" #: qt/app.py:524 msgid "Name backup" msgstr "Nomear o backup" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "Remover snapshot" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "Visualizar último log" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Pelo menos um diretório precisa ser selecionado para o backup." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "Visualizar último log" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "Gerenciar perfis…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Editar user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Desligar" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "Desligar o sistema após o snapshot ser finalizado." #: qt/app.py:552 msgid "Setup language…" msgstr "Configurar idioma…" #: qt/app.py:556 msgid "Exit" msgstr "Sair" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "Página do manual: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Exibe a página do manual sobre o Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "Página do manual: Arquivo de configuração de perfis" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Exibe a página do manual sobre o arquivo de configuração de perfis " "(backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Abrir o site do Back In Time no navegador" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Registro de alterações" #: qt/app.py:586 #, fuzzy msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Abrir o manual do usuário no navegador (local, se disponível, caso contrário" " online)" #: qt/app.py:589 msgid "FAQ" msgstr "FAQ (Perguntas Frequentes)" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Abrir Perguntas Frequentes (FAQ) no navegador.\"" #: qt/app.py:593 msgid "Ask a question" msgstr "Fazer uma pergunta" #: qt/app.py:597 msgid "Report a bug" msgstr "Reportar um bug" #: qt/app.py:600 msgid "Translation" msgstr "Traduções" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Exibe novamente a mensagem sobre participação na tradução." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Transição de Criptografia (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Exibe novamente a mensagem sobre a remoção do EncFS." #: qt/app.py:615 msgid "About" msgstr "Sobre" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Restaurar" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "" "Restaurar os arquivos ou diretórios selecionados para o destino original." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Restaurar para …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "" "Restaurar os arquivos ou diretórios selecionados para um novo destino." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Restaurar o diretório exibido atualmente e todos os seus conteúdos para o " "destino original." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Restaurar o diretório exibido atualmente e todos os seus conteúdos para um " "novo destino." #: qt/app.py:640 msgid "Up" msgstr "Acima" #: qt/app.py:643 msgid "Show hidden files" msgstr "Exibir arquivos ocultos" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "Comparar snapshots…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Versão Candidata a Lançamento" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Exibe a mensagem sobre esta versão candidata a lançamento novamente." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Backup" #: qt/app.py:733 msgid "&Restore" msgstr "&Restaurar" #: qt/app.py:739 msgid "&Help" msgstr "&Ajuda" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "Apenas ícones" #: qt/app.py:827 msgid "Text only" msgstr "Apenas texto" #: qt/app.py:830 msgid "Text below icons" msgstr "Texto abaixo dos ícones" #: qt/app.py:833 msgid "Text beside icon" msgstr "Texto ao lado do ícone" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Esse diretório não existe\n" "no backup atual selecionado." #: qt/app.py:1005 msgid "Add to Include" msgstr "Adicione à Lista de Inclusão" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Adicione à Lista de Exclusão" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Se você fechar esta janela, o Back In Time não será capaz de desligar seu " "sistema quando o snapshot for finalizado." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Fechar a janela mesmo assim?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Concluído, nenhum backup necessário" #: qt/app.py:1285 msgid "Working:" msgstr "Trabalhando:" #: qt/app.py:1292 msgid "Working" msgstr "Trabalhando" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Erro" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Enviado:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Velocidade:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "Backups:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Restaurar {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Restaurar {path} para …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Olá\n" "Você tem usado o Back In Time no idioma {language} algumas vezes até agora.\n" "A tradução da sua versão instalada do Back In Time para o {language} está {perc} completa. Independentemente do seu nível de conhecimento técnico, você pode contribuir para a tradução e, para o Back In Time em si.\n" "Por favor, visite a {translation_platform_url} se desejar contribuir. Para assistência adicional e dúvidas, por favor acesse o projeto do {back_in_time_project_website}.\n" "Pedimos desculpas pela interrupção, e esta mensagem não será exibida novamente. Este diálogo está disponível a qualquer momento pelo menu de ajuda.\n" "Sua equipe Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "plataforma de tradução" #: qt/app.py:1714 msgid "Website" msgstr "através do site" #: qt/app.py:1728 msgid "Your translation" msgstr "Sua tradução" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "No Fediverse do Mastodon: {link_and_label}." #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Lista de emails {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Lista de emails {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} no site do projeto." #: qt/app.py:1781 msgid "Open an issue" msgstr "Abra uma demanda" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Alternativamente, você pode usar outro canal de sua escolha." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Esta versão do Back In Time é um Candidato de Lançamento e é destinada principalmente para testes de estabilidade em preparação para o próximo lançamento oficial.\n" "Nenhum dado do usuário ou telemetria é coletado. No entanto, a equipe do Back In Time está muito interessada em saber se o Candidato de Lançamento está sendo utilizado e se vale a pena continuar a fornecer essas versões de pré-lançamento.\n" "Portanto, a equipe solicita gentilmente um breve feedback sobre se você testou esta versão, mesmo que não tenha encontrado nenhum problema. Mesmo um teste rápido de alguns minutos nos ajudaria muito.\n" "As seguintes opções de contato estão disponíveis:\n" "{contact_list}\n" "Nesta versão, esta mensagem não será exibida novamente, mas pode ser acessada a qualquer momento pelo menu de ajuda.\n" "Obrigado pelo seu apoio e por nos ajudar a melhorar o Back In Time!\n" "Sua equipe do Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 #, fuzzy msgid "Proceed with the backup?" msgstr "Remover este backup?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Todos os arquivos mais recentes em {path} serão removidos. Continuar?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Todos os arquivos mais recentes no diretório original serão removidos. " "Continuar?" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Atenção{BOLDEND}: Deletar arquivos no sistema de arquivos raiz pode " "quebrar todo o seu sistema." #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "&Backup" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Remover este backup?" msgstr[1] "Remover estes backups?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "As configurações de idioma só têm efeito após reiniciar o Back in Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "Manter os snapshots nomeados." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Pergunta" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Criar cópias de backup com o sufixo {suffix}\n" "antes de sobrescrever ou remover elementos locais." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Versões mais recentes dos arquivos serão renomeadas com o sufixo {suffix} " "antes da restauração. Se não precisar mais deles, poderá removê-los com o " "seguinte comando:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Restaure apenas elementos que não existem ou\n" "que são mais recentes do que os do destino.\n" "Usando a opção \"rsync --update\"." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Remover os elementos mais recentes do diretório original." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Restaure os arquivos ou diretórios selecionados para o destino original e " "exclua os arquivos ou diretórios que não estão no snapshot. Tenha extrema " "cautela, pois isso excluirá arquivos e diretórios que foram omitidos durante" " a criação do snapshot." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Você realmente deseja restaurar este elemento no novo diretório?" msgstr[1] "Você realmente deseja restaurar estes elementos no novo diretório?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Você realmente deseja restaurar este elemento?" msgstr[1] "Você realmente deseja restaurar estes elementos?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Incluir arquivos e diretórios" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Configurar idioma" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Traduzido: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Padrão do sistema" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "Use o idioma do sistema operacional." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "Visualização do Último Log" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Visualização do Último Log" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Perfil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Backups:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtrar:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Erro, [I] Informação, [C] Alteração" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "decodificar caminhos" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Tudo" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Alterações" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Erros" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informação" msgstr[1] "Informações" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "Falhas na transferência do rsync (experimental)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Gerenciar perfis" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Editar" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Adicionar" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Remover" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Geral" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Incluir" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Excluir" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Remover & Reter" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Opções" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "O&pções Avançadas" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Restaurar Configuração" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Novo perfil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Renomear perfil" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Você tem certeza que deseja excluir o perfil \"{name}\" ?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Pausar o processo de snapshot" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Excluir arquivo" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Diretórios de backup" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Não é possível remover o diretório" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Exibir arquivos ocultos" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Parar processo de snapshot" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Excluir diretório" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "padrão" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Agendar" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dia:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Dia da Semana:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Tempo:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Horas:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "depois da hora" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minutos:" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Executar o Back In Time assim que o dispositivo for conectado (apenas uma " "vez a cada X dias). Você será solicitado a fornecer sua senha sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Executar o Back In Time repetidamente. Isto é útil se o computador não é " "executado regularmente." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Todo:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Habilitar registro de mensagens de depuração" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "Grava mensagens de nível de depuração no log do sistema via \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Cuidado: Use-o apenas temporariamente para diagnóstico por gerar um excesso " "de resultados." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Desabilitado" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Em cada início/reinício" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "A cada {n} minuto" msgstr[1] "A cada {n} minutos" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "A cada hora" msgstr[1] "A cada {n} horas" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Horas personalizadas" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Todo dia" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Repetidamente (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Quando o drive for conectado (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Toda semana" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Todo mês" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Todo ano" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Hora(s)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dia(s)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Semana(s)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mês(es)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Horas personalizadas podem ser apenas uma lista de horários separados por " "vírgula (ex. 8,12,18,23) ou */3 para backups periódicos a cada 3 horas." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Alegeți un fișier de cheie privată existent, din altă parte." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Creează o nouă cheie SSH fără parolă." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Ruta completă: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Cheie privată:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Utilizează configurația SSH a sistemului" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Lasă fișierul cheie neselectat. Conexiunile SSH se vor baza pe configurația " "clientului existentă în sistem (de exemplu, ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proxy SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Gazdă:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Utilizator:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Conectați-vă la gazda țintă prin acest proxy (cunoscut și ca gazdă de salt)." " Consultați „-J” în documentația comenzii «ssh» sau „ProxyJump” în pagina de" " manual „ssh_config” pentru detalii." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Informații{ENDBOLD}: În modul „SSH criptat”, doar asteriscurile simple" " sau duble sunt funcționale (de exemplu {example2}). Alte tipuri de " "caractere joker și modele vor fi ignorate (de exemplu {example1}). Numele " "fișierelor sunt impredictibile în acest mod din cauza criptării cu EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Exclude modele, fișiere sau directoare" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Adaugă un model" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Adaugă fișiere" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Adaugă directoare" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Sugestii" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" "Selectați din elementele utilizate frecvent pentru a le adăuga la lista de " "excluderi." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Exclude fișierele mai mari decât:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Exclude fișierele mai mari decât valoarea în {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Cu «Modul rsync complet» dezactivat, această opțiune afectează numai " "fișierele nou create, deoarece rsync o tratează ca opțiune de transfer, și " "nu ca regulă de excludere. În consecință, fișierele mari care au fost deja " "copiate vor rămâne în copiile de rezervă, chiar dacă sunt modificate." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Exclude modelul" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Introduceți un model de excludere:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" "Pentru ajutor, consultați secțiunea {link} din pagina de manual rsync." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Deschide pagina de manual rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Exclude fișiere" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Exclude directoare" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Dezactivat pentru că acest model nu este funcțional în modul „SSH criptat”." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Aceste opțiuni sunt destinate configurațiilor avansate. Modificați-le numai " "dacă sunteți pe deplin conștient de implicațiile lor." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Rulează «rsync» cu „{cmd}”:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "ca sarcină cron" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "pe gazda de la distanță" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "atunci când se efectuează manual o copie de rezervă" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Instalați „nocache” pentru a activa această opțiune." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "pe mașina locală" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "" "Redirecționează ieșirea standard (stdout) către „/dev/null” în sarcinile " "cron." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron va trimite automat un email cu rezultatul sarcinilor cronjobs atașat " "dacă un MTA este instalat." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "" "Redirecționează ieșirea de eroare standard (stderr) către „/dev/null” în " "sarcinile cron." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron va trimite automat un email cu erorile sarcinilor cronjob atașate dacă " "un MTA este instalat." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "Ko/sec" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Limitează utilizarea lățimii de bandă a «rsync»:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Păstrează ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Păstrează atributele extinse (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Restricționează la un singur sistem de fișiere" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Opțiunile trebuie să fie puse între ghilimele, de exemplu: {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Lipește opțiunile adiționale la «rsync»" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefix de rulat înainte de fiecare comandă pe gazda de la distanță." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variabilele trebuie să fie eludate cu \\$FOO. Acest lucru nu afectează " "«rsync». Deci, pentru a adăuga un prefix pentru «rsync» utilizați " "„{example_value}” cu {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "implicit" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Adaugă un prefix la comenzile SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Verifică dacă gazda de la distanță este conectată" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Avertisment: dacă este dezactivată și gazda de la distanță nu este " "disponibilă, acest lucru ar putea duce la unele erori ciudate." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Verifică dacă gazda de la distanță acceptă toate comenzile necesare." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Avertisment: dacă este dezactivată și gazda de la distanță nu acceptă toate " "comenzile necesare, acest lucru ar putea duce la unele erori ciudate." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(implicit: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "dezactivată" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "activată" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Mod:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Unde să se salveze copiile de rezervă" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Configurări SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Ruta:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Fișierul de cheie:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Parola" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Salvează parola în inelul de chei" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Memorează parola pentru «cron» în cache (problemă de securitate: root poate " "să citească parola)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avansat" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Ruta completă a copiei de rezervă:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Programarea este dezactivată deoarece nu a fost găsită nicio instalare " "«cron». Vă rugăm să instalați «cron» pentru a activa copiile de rezervă " "programate." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Ruta de destinație a copiei de rezervă nu poate fi goală." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Parola de criptare nu poate fi goală." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "A apărut o eroare în timpul încercării de conectare la gazda de la distanță." " A fost returnat următorul mesaj de eroare:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Pentru a permite conectarea fără parolă, cheia SSH publică poate fi copiată " "pe gazda de la distanță." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Continuați cu copierea cheii SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Cheia SSH publică nu a putut fi copiată. Acest lucru se poate datora unei " "probleme de conexiune sau de permisiuni." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Autenticitatea gazdei {host} nu poate fi stabilită." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Amprenta cheii {keytype} este:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Verificați această amprentă. Doriți să o adăugați la fișierul „known_hosts”?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Doriți cu adevărat să schimbați directorul copiilor de rezervă?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Destinația de copie de rezervă selectată nu este goală." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Aceasta trebuie să fie goală pentru a utiliza criptarea." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Fișier nevalid: Nu este o cheie SSH privată" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Fișierul selectat ({path}) este o cheie SSH publică. Vă rugăm să alegeți " "fișierul de cheie privată corespunzător (fără sufixul „.pub”)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Fișierul {path} există deja. Nu se poate crea o nouă cheie SSH cu acest " "nume." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Nu s-a putut crea o cheie SSH nouă în {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Include fișiere și directoare" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "„{path}” este o legătură simbolică. Ținta asociată nu va fi salvată până " "când nu este inclusă și ea." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Doriți să includeți în schimb ținta legăturii simbolice?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Include fișiere" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Include directoare" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Activează notificările" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "" "Dezactivează efectuarea de copii de rezervă atunci când mașina funcționează " "pe baterie" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Starea alimentării nu este disponibilă din sistem" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Rulează doar o copiere de rezervă la un moment dat" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Alte operații de copiere de rezervă vor fi blocate până la finalizarea " "operației de copiere curente. Aceasta este o opțiune globală, ceea ce " "înseamnă că va afecta toate profilele pentru acest utilizator. Cu toate " "acestea, trebuie să fie activată de asemenea pentru toți ceilalți " "utilizatori." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Efectuează o copie de rezervă a fișierelor înlocuite la restaurare" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Continuă în caz de erori (păstrează copii de rezervă incomplete)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Utilizează suma de control pentru a detecta modificările" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "" "Creează o nouă copie de rezervă, indiferent dacă au existat modificări sau " "nu." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Avertizează dacă spațiul liber pe disc scade sub" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Afișează un avertisment atunci când spațiul liber de pe discul de destinație" " al copiei de rezervă este mai mic decât valoarea specificată." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Dacă este activată politica «Elimină și păstrează» și copiile de rezervă " "vechi sunt eliminate pe baza spațiului liber disponibil, această valoare nu " "poate fi mai mică decăt valoarea stabilită în politică." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Nivel de jurnalizare:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Nimic" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "manual de utilizare" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Următoarele reguli sunt procesate de sus în jos. Regulile ulterioare " "prevalează asupra celor anterioare. Consultați {manual_link} pentru detalii " "și exemple." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Deschide manualul de utilizare în navigator." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Păstrează cea mai recentă copie de rezervă." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Cea mai recentă copie de rezervă este păstrată în orice situație." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Acest comportament nu poate fi modificat." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Păstrează copiile de siguranță numite." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Copiile de rezervă care au primit un nume, pe lângă marcajul de timp " "obișnuit, vor fi păstrate în orice situație și nu vor fi eliminate." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "An (Ani)" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Elimină copiile de rezervă mai vechi de" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Zile întregi. Ziua curentă este ignorată." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Săptămâni calendaristice cu luni ca primă zi. Săptămâna curentă este " "ignorată." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Perioade de 12 luni. Luna curentă este ignorată." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Politica de păstrare" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Rulează în fundal pe gazda de la distanță." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Politica de păstrare va fi executată direct pe mașina de la distanță, nu " "local. Comenzile „bash”, «screen» și «flock» trebuie să fie instalate și " "disponibile pe mașina de la distanță respectivă." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "" "Dacă este activată, Back In Time va testa mai întâi mașina de la distanță." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Zilele sunt numărate începând de astăzi." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Păstrează toate copiile de rezervă pentru ultima(ultimele)" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "zi(zile)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Păstrează ultima copie de rezervă pentru fiecare zi din ultimele" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Săptămânile sunt numărate începând cu săptămâna curentă. O săptămână începe " "luni." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "" "Păstrează ultima copie de rezervă pentru fiecare săptămână din ultimele" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "săptămână(săptămâni)." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Lunile sunt numărate ca luni calendaristice începând cu luna curentă." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Păstrează ultima copie de rezervă pentru fiecare lună din ultimele" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "lună(luni)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Anii sunt numărați ca ani calendaristici începând cu anul curent." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Păstrează ultima copie de rezervă pentru fiecare an din" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "toți anii." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… spațiul liber este mai mic decât" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… nodurile-i libere sunt mai puține decât" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Elimină cea mai veche copie de rezervă dacă …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Autentificarea este necesară pentru a rula Back In Time ca root." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Autentificarea este necesară pentru a modifica programările de copie de " "rezervă declanșate de conectările dispozitivelor de stocare externe." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Scurtături" #: qt/placeswidget.py:63 msgid "Places" msgstr "Locuri" #: qt/placeswidget.py:64 msgid "File System" msgstr "Sistemul de fișiere" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Directoare copie de rezervă" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: {profile_name}(al utilizatorului „{desktop_user}”)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Vizualizează ultimul jurnal" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Pornește {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Se lucrează…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "pagina de manual: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importă configurația" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Nu a fost selectat niciun director" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importă" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Se caută…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Selectați directorul de copii de rezervă din care trebuie importat fișierul " "de configurare. Ruta poate arăta astfel: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Dacă directorul este localizat pe o unitate externă sau la distanță, aceasta" " trebuie să fie montată manual în prealabil." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Scanează din nou" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Afișează directoarele ascunse" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Afișează/ascunde directoarele ascunse (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Nu s-a găsit niciun fișier de configurare în acest director" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Căutare finalizată." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Afișează jurnalul complet" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Numărătoarea inversă până la oprire" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Copia de rezervă a fost finalizată." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Anulează oprirea" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Oprește acum" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Sistemul se va opri în {n} secundă." msgstr[1] "Sistemul se va opri în {n} secunde." msgstr[2] "Sistemul se va opri în {n} de secunde." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Opțiuni privind compararea copiilor de rezervă" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Comandă:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametri:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Utilizați %1 și %2 pentru parametrii rutei" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Stabiliți o comandă «diff» sau apăsați butonul «Anulează»." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Comanda „{cmd}” nu poate fi găsită pe acest sistem. Încercați altceva sau " "apăsați butonul «Anulează»." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Nu s-au stabilit parametri pentru comanda «diff». Se utilizează valoarea " "implicită «{params}»." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Copii de rezervă" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Doar copiile de rexervă care diferă" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Listează doar copiile de siguranță care sunt egale cu:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Verificare profundă (mai precis, dar încet)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Șterge" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Selectează toate" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Compară" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Navighează la" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Opțiuni" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Nu este posibil să se compare o copie de rezervă cu ea însăși, deoarece " "comparația ar fi redundantă." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "" "Sigur doriți să ștergeți {file_or_dir} din copia de rezervă {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Sigur doriți să ștergeți {file_or_dir} din {count} copii de rezervă?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "AVERTISMENT: Această acțiune nu poate fi revocată." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Excludeți {path} din copiile de rezervă viitoare?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Modul root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time rulează în prezent cu privilegii root (acces complet la sistem)" #: qt/timeline.py:69 msgid "Today" msgstr "Astăzi" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Ieri" #: qt/timeline.py:87 msgid "This week" msgstr "Săptămâna aceasta" #: qt/timeline.py:95 msgid "Last week" msgstr "Săptămâna trecută" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Aceasta NU este o copie de rezervă, ci o vizualizare „live” a fișierelor " "locale." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Ultima verificare: {time}" backintime-1.6.1/common/po/ru.po000066400000000000000000002760551514264426600165520ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Vadim Peretokin # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-08 06:18+0000\n" "Last-Translator: AndrewG \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Все лицензии, используемые в этом проекте, находятся в папке {dir_link}. " "Чтобы извлечь информацию о лицензии и авторских правах для каждого файла с " "помощью метаданных SPDX, обратитесь к {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Предупреждение" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Основной профиль" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Локально (шифрование EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (шифрование EncFS)" #: common/config.py:237 msgid "Local" msgstr "Локально" #: common/config.py:240 msgid "Local encrypted" msgstr "Локально, зашифровано" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Шифрование" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Приватный ключ SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Профиль: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Папка снимков задана неверно." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Для резервного копирования должна быть выбрана хотя бы одна папка." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Папка: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Эта папка не может быть включен в резервную копию, поскольку она является " "частью самого места назначения резервной копии." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "Значение для параметра \"Удалить самую старую резервную копию, если " "свободного места меньше чем\" ({val_one}) должно быть меньше или равно " "пороговому значению для параметра \"Предупреждать, если свободного места на " "диске становится меньше чем\" ({val_two})." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Пожалуйста, измените настройки таким образом, чтобы лимит удаления резервной" " копии не превышал лимит предупреждения." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Расписание udev не работает в режиме {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Не удалось записать новый crontab." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron не запущена, хотя присутствует команда crontab. Резервное копирование " "по расписанию выполняться не будет. Возможно, cron установлена, но не " "включена. Попробуйте выполнить команду «system enable cron» или свяжитесь с " "поддержкой вашего дистрибутива Linux." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Не удалось сохранить конфигурацию" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Не удалось загрузить конфигурацию" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Профиль \"{name}\" уже существует." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Последний профиль не может быть удален." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Невозможно смонтировать \"{command}\"" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Не найдена конфигурация для зашифрованной папки." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Создать новую зашифрованную папку?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Отмена" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "" "Для подтверждения повторите ввод пароля для зашифрованной файловой системы." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "Пароль для EncFS не подходит." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Сделать снимок" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Не удается инициализировать зашифрованный путь \"{command}\"" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Не удалось размонтировать {mountprocess} из {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "Программа {command} не найдена. Установите ее (например через " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Точка монтирования {mntpoint} не пустая." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Введите пароль для {mode} профиля \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Не удалось установить правило Udev для профиля {profile_id}. Служба DBus " "'{dbus_interface}' недоступна." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Не удалось найти UUID для {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "НЕУСПЕШНО" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Восстановить права" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Готово" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Следующие записи из включаемого списка не имеют соответствующих файла или " "папки в источнике резервной копии:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Отсрочка резервного копирования при работе от батареи" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Невозможно найти папку снимков." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "" "Если она находится на съёмном диске, пожалуйста, подключите его и нажмите " "ОК." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Ожидание {n} секунду." msgstr[1] "Ожидание {n} секунды." msgstr[2] "Ожидание {n} секунд." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Не удалось создать резервную копию {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Пожалуйста, подождите. Завершение…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Невозможно создать папку." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Сохранение файла конфигурации…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Сохранение разрешений…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "Найден незавершённый бекап {snapshot_id}, который можно продолжить." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Удаление папки незавершённого {snapshot_id}, оставшегося после последнего " "запуска" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Невозможно удалить папку" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Создание резервной копии" #: common/snapshots.py:1517 msgid "Success" msgstr "Успешно" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Неполная передача из-за ошибки" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Частичный перенос из-за исчезновения исходных файлов (см. «man rsync»)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "rsync завершился c кодом {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Подробнее см. «man rsync»" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Неудачные коды выхода из rsync - это номера сигналов, см. 'kill -l' и 'man " "kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Ничего не изменилось, нет необходимости в новой резервной копии" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Невозможно переименовать {new_path} в {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Удаление старых резервных копий" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Применяется политика хранения" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Стараться сохранять минимальное свободное место" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Попытка сохранить минимум {perc} свободных инодов" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Сейчас" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Невозможно смонтировать {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-агент не найден. Убедитесь, что он установлен." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Не удалось разблокировать приватный ключ ssh. Пароль неверный или не " "подходит для cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Удаленный путь существует, но не является папкой." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Удаленный путь недоступен для записи." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Удаленный путь не доступен для выполнения." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Не удалось создать удаленный путь." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Удаленный узел {host} не поддерживает{command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Команды проверки на хосте {host} вернули неизвестную ошибку" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Удаленный хост {host} не поддерживает жесткие ссылки" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Скопировать открытый ssh-ключ \"{pubkey}\" на удаленный хост \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Пожалуйста, подтвердите пароль для \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Файловая система назначения {path} отформатирована в NTFS и не полностью " "совместима с файловыми системами Unix." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} существует, но не является папкой." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Не удалось создать папку:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Доступ на запись может быть ограничен." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Файловая система назначения {path} отформатирована в FAT и не поддерживает " "\"жесткие\" ссылки. Используйте нативные файловые системы GNU/Linux." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Файловая система назначения {path} является сетевым ресурсом " "примонтированным через SMB. Убедитесь, что удаленный SMB-сервер поддерживает" " симлинки, или активируйте \"{copyLinks}\" в \"{expertOptions}\"." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Копировать ссылки (разыменование символических ссылок)" #: common/tools.py:487 msgid "Expert Options" msgstr "Расширенные настройки" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Файловая система назначения для {path} является сетевым ресурсом " "смонтированным через sshfs. Sshfs не поддерживает \"жесткие\" ссылки. " "Используйте режим «SSH»." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Не удалось создать файл в папке:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Инфо про Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Авторские права:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Разработчики:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Переводы:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Vadim Peretokin " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Для текущего языка титров переводчика нет." #: qt/aboutdlg.py:116 msgid "this link" msgstr "эту ссылку" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Для просмотра титров переводчиков для всех языков откройте {thislink}." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Сайт проекта" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Руководство пользователя" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Открыть руководство пользователя в браузере (локальное если есть, иначе в " "интернете)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Версия{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Похоже, {app_name} запускается впервые, так как конфигурация не найдена." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Импортировать существующую конфигурацию (из резервной целевой папки или с " "другого компьютера)?" #: qt/app.py:395 msgid "Then press OK." msgstr "Затем щёлкни ОК." #: qt/app.py:499 msgid "Create a backup" msgstr "Создать резервную копию" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Используйте время модификации и размер для обнаружения изменений файла." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Создать резервную копию (режим контрольной суммы)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Использовать контрольную сумму для обнаружения изменений." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Приостановить процесс создания резервной копии" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Продолжить процесс создания резервной копии" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Остановить процесс создания резервной копии" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Обновить список моментальных резервных копий" #: qt/app.py:524 msgid "Name backup" msgstr "Название резервной копии" #: qt/app.py:528 msgid "Remove backup" msgstr "Удалить резервную копию" #: qt/app.py:532 msgid "Open backup log" msgstr "Открыть журнал" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Просмотр журнала выбранной резервной копии." #: qt/app.py:536 msgid "Open last backup log" msgstr "Открыть журнал последней резервной копии" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "Просмотреть журнал последней резервной копии." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Управление профилями…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Редактирование отзыва пользователя" #: qt/app.py:548 msgid "Shutdown" msgstr "Выключить" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Выключить систему после завершения создания резервной копии." #: qt/app.py:552 msgid "Setup language…" msgstr "Изменить язык…" #: qt/app.py:556 msgid "Exit" msgstr "Выйти" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "Страница man: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Показать страницу man по Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "Страница man для файла конфигурации профилей" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Показать страницу man про файл конфигурации профиля (backintime-config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Открыть в браузере сайт Back In Time" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Список изменений" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "Открыть список изменений (локально если можно, иначе из интернета)" #: qt/app.py:589 msgid "FAQ" msgstr "ЧаВо" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Открыть в браузере список часто задаваемых вопросов" #: qt/app.py:593 msgid "Ask a question" msgstr "Задать вопрос" #: qt/app.py:597 msgid "Report a bug" msgstr "Сообщить об ошибке" #: qt/app.py:600 msgid "Translation" msgstr "Перевод" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Показать сообщение об участии в переводе." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Миграция с шифрования EncFS" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Показать сообщение об удалении EncFS." #: qt/app.py:615 msgid "About" msgstr "О программе" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Восстановить" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Восстановить выбранные файлы или папки в исходное место назначения." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Восстановить в…" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Восстановить выбранные файлы или папки в новое место назначения." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Восстановление текущей показанной папки и всего её содержимого в исходное " "место." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Восстановление текущей показанной папки и всего её содержимого в новое " "место." #: qt/app.py:640 msgid "Up" msgstr "Вверх" #: qt/app.py:643 msgid "Show hidden files" msgstr "Показать скрытые файлы" #: qt/app.py:646 msgid "Compare backups…" msgstr "Сравнить резервные копии…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Кандидат на релиз" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Снова показывает сообщение об этом релизе-кандидате." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Резервное копирование" #: qt/app.py:733 msgid "&Restore" msgstr "&Восстановление" #: qt/app.py:739 msgid "&Help" msgstr "&Справка" #: qt/app.py:790 msgid "Systray Icon" msgstr "Значок в системной планке" #: qt/app.py:796 msgid "Automatic" msgstr "Автоматически" #: qt/app.py:800 msgid "Light icon" msgstr "Светлый" #: qt/app.py:801 msgid "Dark icon" msgstr "Тёмный" #: qt/app.py:824 msgid "Icons only" msgstr "Только значки" #: qt/app.py:827 msgid "Text only" msgstr "Только текст" #: qt/app.py:830 msgid "Text below icons" msgstr "Текст под значками" #: qt/app.py:833 msgid "Text beside icon" msgstr "Текст рядом со значками" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Этой папки не существует\n" "в выбранной резервной копии." #: qt/app.py:1005 msgid "Add to Include" msgstr "Включить" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Добавить в исключения" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Если вы закроете это окно, то Back In Time не сможет выключить систему после" " завершения создания резервной копии." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Закрыть окно в любом случае?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Сделано, резервная копия не нужна" #: qt/app.py:1285 msgid "Working:" msgstr "Работаю:" #: qt/app.py:1292 msgid "Working" msgstr "Работаю" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Ошибка" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Отправлено:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Скорость:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Ещё примерно:" #: qt/app.py:1490 msgid "Backup:" msgstr "Резервное копирование:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Восстановить {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Восстановить {path} в…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Здравствуйте!\n" "При работе с Back In Time вы используете {language} язык.\n" "Перевод установленной вами версии Back In Time на {language} завершён на {perc}. Каким бы ни был ваш уровень знаний, вы можете внести свой вклад в перевод и тем самым помочь Back In Time.\n" "Если вы хотите поучаствовать в переводе — пожалуйста, посетите {translation_platform_url}. Задать вопросы и получить помощь можно на {back_in_time_project_website}.\n" "Приносим извинения за неудобства — это сообщение больше не появится. Снова найти это диалоговое окно можно будет в меню помощи.\n" "Ваша команда Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "платформы для перевода" #: qt/app.py:1714 msgid "Website" msgstr "Сайт" #: qt/app.py:1728 msgid "Your translation" msgstr "Ваш перевод" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "В децентрализованной сети Mastodon: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "Email: {link_and_label}." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Список рассылки: {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} на сайте проекта." #: qt/app.py:1781 msgid "Open an issue" msgstr "Подать заявку" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Либо вы можете использовать любо другой способ связи." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Эта версия Back In Time является версией-кандидатом на релиз и в основном предназначена для тестирования стабильности и подготовки к к следующему официальному выпуску.\n" "Никаких пользовательских данных и телеметрии не собирается. Однако команде Back In Time очень интересно узнать, используется ли версия-кандидат и стоит ли продолжать предоставлять такие предварительные версии.\n" "Поэтому команда любезно просит вас оставить краткий отзыв о том, тестировали ли вы эту версию, даже если у вас не возникло никаких проблем. Даже быстрый тестовый запуск в течение нескольких минут нам бы очень помог.\n" "Доступны следующие варианты связи:\n" "{contact_list}\n" "В этой версии это сообщение больше не будет отображаться, но к нему можно получить доступ в любое время через меню \"Справка\".\n" "Спасибо вам за вашу поддержку и за помощь в улучшении Back In Time!\n" "Ваша команда Back In Time" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "В целевой папке доступно {free} свободного места, что ниже " "сконфигурированного порога в {threshold}." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Продолжить резервное копирование?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "Все новые файлы в {path} будут удалены. Продолжать?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" "Все файлы, которые новее, из исходной папки будут удалены. Продолжить?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}ВНИМАНИЕ{BOLDEND}: Удаление файлов в корне файловой системы может " "сломать всю вашу систему." #: qt/app.py:2167 msgid "Backup name" msgstr "Название бекапа" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Эту резервную копию удалить?" msgstr[1] "Эти резервные копии удалить?" msgstr[2] "Эти резервные копии удалить?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "Смена языка произойдет только после перезапуска Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Версионные резервные копии (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "GUI для версионных резервных копий, которые уменьшают расход диска (режим " "root)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Версионные резервные копии" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Графический интерфейс для версионных резервных копий, которые уменьшают " "расход диска" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Вопрос" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Создать резервные копии с последующим {suffix} перед перезаписью или " "удалением локальных файлов." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Более новые версии файлов перед восстановлением будут переименованы с " "добавлением {suffix}. Эти файлы могут быть удалены следующей командой:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Восстанавливать только несуществующие элементы или элементы новее, чем " "имеющиеся. Использует опцию \"{rsync_example}\"." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Удалять более новые файлы в исходной папке." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Восстановить выбранные файлы или папки в исходное место назначения и удалить" " файлы или папки, которых нет в снимке. Будьте предельно осторожны, потому " "что при этом будут удалены файлы и папки, исключенные при создании снимка." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Вы действительно хотите восстановить этот файл в новую папку?" msgstr[1] "Вы действительно хотите восстановить эти файлы в новую папку?" msgstr[2] "Вы действительно хотите восстановить эти файлы в новую папку?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Вы действительно хотите восстановить этот файл?" msgstr[1] "Вы действительно хотите восстановить эти файлы?" msgstr[2] "Вы действительно хотите восстановить эти файлы?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Пользовательский скрипт: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "В первой строке пользовательского скрипта должна быть строка, указывающая " "интерпретатор (например, {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Показать/скрыть скрытые файлы и папки (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Установить язык" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Переведено: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Язык системы" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Использовать язык операционной системы." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Просмотр лога резервной копии" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Просмотр последнего журнала" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Профиль:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Бекапы:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Фильтр:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Ошибка, [I] Информация, [C] Изменение" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "декодировать пути" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Все" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Изменения" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Ошибки" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Информация" msgstr[1] "Информация" msgstr[2] "Информации" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "сбои передач rsync (экспериментально)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Управление профилями" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Изменить" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Добавить" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Удалить" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Общие" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Включить" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Исключить" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "Удаление и хранение" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Параметры" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Р&асширенные параметры" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Восстановить конфигурацию" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Новый профиль" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Переименовать профиль" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Вы действительно хотите удалить профиль \"{name}\"?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Копировать символьные ссылки в виде файлов" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Символьные ссылки сохраняются в резервную копию как реальные файлы или " "папки. Выберите, будут ли копироваться все ссылки или только те, которые " "указывают за пределы источника." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Этот параметр может увеличить размер резервной копии." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "По-умолчанию отключено." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Все символьные ссылки заменяются реальными файлами или папками, на которые " "они указывают. Это увеличивает размер резервной копии и может привести к " "многократному хранению одних и тех же файлов." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "Применяется 'rsync --copy-links'." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Только внешние" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "В виде файлов копируются только ссылки, указывающие за пределы источника " "резервной копии. Это увеличивает размер резервной копии и может привести к " "многократному хранению одних и тех же файлов." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "Применяется 'rsync --copy-unsafe-links'." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Временные файлы редакторов и Офиса" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Резервные копии Emacs" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Файлы автосохранения Emacs" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Своп файлы Vim" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Временные файлы Microsoft Office" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "Лок файлы LibreOffice и других редакторов OpenDocument" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Миниатюры и временные изображения" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "Кэш миниатюр на GNU/Linux и других Юникс подобных ОС" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "База данных миниатюр на Windows" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "Папка метаданных на macOS" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Лок файлы некоторых приложений" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Лок файлы приложения Discord" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Лок файлы сессии Discord" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Лок файлы Mozilla Firefox и Thunderbird" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Папки кеша и временных файлов" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Прикладной кэш пользователя" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Системная временная папка" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "Пакетный кэш дистрибутивов, основанных на Debian GNU/Linux" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Репозиторий Flatpak приложения и времени выпонения" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Системные каталоги времени выполнения" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Информация ядра и процессов" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Информация об устройствах и оборудовании (интерфейс sysfs)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Узлы устройств" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Системные файлы времени выполнения" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Прочее непостоянное" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Список подключенных в данный момент файловых систем" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Системный файл подкачки (виртуальная память)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "Точка монтирования виртуальной файловой системы GNOME" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Восстановленные объекты файловой системы" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Разное" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Папка метаданных на Microsoft Windows" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Пользовательская корзина" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Системные файлы резервных копий" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Рекомендуемые исключения" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "Выберите что исключить из резервной копии." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "По умолчанию" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Сброс к предопределенному выбору" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Расписание" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Число:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "День недели:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Время:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Часа:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "после часа" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Минут:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Запускать Back In Time как только диск подключен (только один раз каждые X " "дней). Будет запрошен sudo-пароль." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Многократный запуск программы Back In Time. Это удобно если компьютер " "работает нерегулярно." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Каждые:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Записывать отладочные сообщения в журнал" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Записать в системный журнал сообщения уровня отладки с помощью \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Внимание: используйте временно для диагностики, так как генерируется большой" " объем выходных данных." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Отключено" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "При каждой загрузке системы" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Каждую {n} минуту" msgstr[1] "Каждые {n} минут" msgstr[2] "Каждые {n} минут" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Каждый {n} час" msgstr[1] "Каждые {n} часа" msgstr[2] "Каждые {n} часов" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Другой период (в часах)" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Каждый день" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Периодически (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "При подключении носителя (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Каждую неделю" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Каждый месяц" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Ежегодно" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Час(ов)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Дней (Дня)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Недель" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Месяцев" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Настроенные часы могут быть только списком часов, разделенных запятыми " "(например, 8,12,18,23) или */3 для периодического резервного копирования " "каждые 3 часа." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "Vyberte existujúci súbor privátneho kľúča (zvyčajne s názvom \"id_ed25519\" " "a v starších nastaveniach \"id_rsa\")." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "Nepodarilo sa vytvoriť nový SSH kľúč v {path}." #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "Úplná cesta k snímke:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Privátny kľúč:" #: qt/manageprofiles/sshkeyselector.py:210 #, fuzzy msgid "Use system SSH configuration" msgstr "Importovať konfiguráciu" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH Proxy" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Server:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Používateľ:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Pripojiť sa k cieľovému hostiteľovi cez tento proxy server (známy aj ako " "jump host). Podrobnosti nájdete v \"-J\" v dokumentácii príkazu \"ssh\" " "alebo v \"ProxyJump\" v manuálovej stránke \"ssh_config\"." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Informácia{ENDBOLD}: V režime \"Šifrované cez SSH\" sú funkčné iba " "jednoduché alebo dvojité hviezdičky (napr. {example2}). Ostatné typy " "zástupných znakov a vzorov budú ignorované (napr. {example1}). Názvy súborov" " sú v tomto režime nepredvídateľné kvôli šifrovaniu pomocou EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Vylúčiť vzory, súbory alebo adresáre" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Vylúčiť vzor" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Pridať súbor" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Pridať adresár" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Otázka" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Vylúčiť súbor:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Vylúčiť súbory väčšie ako hodnota v {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Pri vypnutom režime \"Úplný rsync režim\" to ovplyvní iba nové súbory, " "pretože pre rsync je toto možnosť prenosu, nie možnosť vylúčenia. Preto " "veľké súbory, ktoré boli predtým zálohované, zostanú v snímkach, aj keď boli" " upravené." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Vylúčiť vzor" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Vylúčiť vzor" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Vylúčiť súbor" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Vylúčiť adresár" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Zakázané, pretože tento vzor nie je funkčný v režime \"Šifrované cez SSH\"." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Tieto možnosti sú pre pokročilé konfigurácie. Upravujte ich len vtedy, ak si" " plne uvedomujete ich dôsledky." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Spustiť 'rsync' s '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "ako úloha cronu" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "na vzdialenom hostiteľovi" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "pri vytváraní manuálnej snímky" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Prosím, nainštalujte 'nocache' na povolenie tejto možnosti." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "na lokálnom počítači" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Presmerovať stdout do /dev/null v cron úlohách." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron automaticky odošle e-mail s pripojeným výstupom cron úloh, ak je " "nainštalovaný MTA." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Presmerovať stderr do /dev/null v cron úlohách." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron automaticky odošle e-mail s pripojenými chybami cron úloh, ak je " "nainštalovaný MTA." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/sek" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Obmedziť rýchlosť prenosu rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Zachovať ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Zachovať rozšírené atribúty (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Obmedziť na jeden súborový systém" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Možnosti musia byť v úvodzovkách, napr. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Vložte dodatočné možnosti pre rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Predpona na spustenie pred každým príkazom na vzdialenom hostiteľovi." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Premenné je potrebné escapovať pomocou \\$FOO. Toto sa netýka rsync. Takže " "pre pridanie predpony pre rsync použite \"{example_value}\" s " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "predvolené" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Pridať predponu k SSH príkazom" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Overiť, či je vzdialený hostiteľ online" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Upozornenie: Ak je táto možnosť vypnutá a vzdialený hostiteľ nie je " "dostupný, môže to viesť k zvláštnym chybám." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Overiť, či vzdialený hostiteľ podporuje všetky potrebné príkazy." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Upozornenie: Ak je táto možnosť vypnutá a vzdialený hostiteľ nepodporuje " "všetky potrebné príkazy, môže to viesť k zvláštnym chybám." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(predvolené: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "zakázané" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "povolené" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Režim:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Kam sa uložia snímky" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH Nastavenia" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Cesta:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Nový profil" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Heslo" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Uložiť Heslo do Kľúčenky" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Uložiť Heslo do vyrovnávacej pamäte pre Cron (Bezpečnostný problém: root " "môže čítať heslo)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Pokročilé" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 #, fuzzy msgid "Full backup path:" msgstr "Úplná cesta k snímke:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Heslo sa nezhoduje." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Autenticita hostiteľa {host} nemôže byť overená." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Odtlačok {keytype} kľúča je:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Prosím, overte tento odtlačok. Chcete ho pridať do vášho súboru " "'known_hosts'?" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Vytvoriť nový šifrovaný priečinok?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "SSH privátny kľúč" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Nepodarilo sa vytvoriť nový SSH kľúč v {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Zahrňuje súbory a adresáre" #: qt/manageprofiles/tab_include.py:168 #, fuzzy, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" je symbolický odkaz. Prepojený cieľ nebude zálohovaný, pokiaľ ho tiež nezahrniete.\n" "Chcete namiesto toho zahrnúť cieľ symbolického odkazu?" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Zahrnúť súbor" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Zahrnúť adresár" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Povoliť upozornenia" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Nevytvárať snímky pokiaľ systém beží na batérii" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Nie je možné zistiť stav napájania" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Spustiť len jednu snímku naraz" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Ostatné snímky budú blokované, kým sa aktuálna snímka nedokončí. Toto je " "globálna možnosť. Takže ovplyvní všetky profily pre tohto používateľa. Ale " "musíte to aktivovať aj pre všetkých ostatných používateľov." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Zálohovať nahradené súbory pri obnovení" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Pokračovať pri chybách (zachovať nekompletné snímky)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Použiť kontrolný súčet pre zistenie zmien" #: qt/manageprofiles/tab_options.py:86 #, fuzzy msgid "Create a new backup whether there were changes or not." msgstr "Vytvoriť novú snímku bez ohľadu na to, či došlo k zmenám." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Úroveň záznamu:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Žiadne" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "užívateľská príručka" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Nasledujúce pravidlá sa spracúvajú zhora nadol. Neskôr uvedené pravidlá " "prepíšu skoršie a nie sú nimi obmedzené. Podrobnosti a príklady nájdete v " "{manual}." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Otvoriť používateľskú príručku v prehliadači." #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Ponechať najnovšiu snímku." #: qt/manageprofiles/tab_remove_retention.py:241 #, fuzzy msgid "The most up-to-date backup is kept under all circumstances." msgstr "Posledná alebo najnovšia snímka sa uchová za každých okolností." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Tento priebeh sa nedá zmeniť." #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Ponechať pomenované snímky." #: qt/manageprofiles/tab_remove_retention.py:258 #, fuzzy msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Snímky, ktorým bol okrem bežnej časovej pečiatky priradený aj názov, budú " "uchované za každých okolností a nebudú odstránené." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Roky" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Odstrániť snímky staršie ako" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Celé dni. Aktuálny deň sa ignoruje." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Kalendárne týždne s pondelkom ako prvým dňom. Aktuálny týždeň sa ignoruje." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12-mesačné obdobia. Aktuálny mesiac sa ignoruje." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Pravidlá uchovávania" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Spustiť na pozadí na vzdialenom hostiteľovi." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Procedúra inteligentného odstraňovania sa spustí priamo na vzdialenom " "počítači, nie lokálne. Príkazy \"bash\", \"screen\" a \"flock\" musia byť " "nainštalované a dostupné na vzdialenom počítači." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Ak je vybraté, Back In Time najprv otestuje vzdialený počítač." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dni sa počítajú od dnešného dňa." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Uchovať všetky snímky za posledných" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "Počet dní." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Uchovať poslednú snímku z každého dňa za posledných" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Týždne sa počítajú od aktuálneho prebiehajúceho týždňa. Týždeň začína v " "pondelok." #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Uchovať poslednú snímku z každého týždňa za posledných" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "Týždne." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "" "Mesiace sa počítajú ako kalendárne mesiace, počnúc aktuálnym mesiacom." #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Uchovať poslednú snímku z každého mesiaca za posledných" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "mesiac(e)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Roky sa počítajú ako kalendárne roky, počnúc aktuálnym rokom." #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Uchovať poslednú snímku z každého roka za" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "všetky roky." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… voľný priestor je menší ako" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… voľné i-uzly sú menšie ako" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Odstrániť najstaršie snímky, ak …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Skratky" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Adresár záloh" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Zobraziť posledný log" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Spustiť {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Prebieha…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importovať konfiguráciu" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importovať" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Prebieha…" #: qt/restoreconfigdialog.py:211 #, fuzzy, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Vyberte adresár snímky, z ktorého sa má importovať konfiguračný súbor. Cesta" " môže vyzerať napríklad takto: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Ak sa adresár nachádza na externom alebo vzdialenom disku, musí byť predtým " "manuálne pripojený." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Ukázať skryté súbory" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Zahrňuje súbory a adresáre" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Vytvorenie súboru v tomto adresári zlyhalo:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Zobraziť celý záznam" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Vypnúť systém po dokončení snímky." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Vypnúť" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Vypnúť" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: qt/snapshotsdialog.py:63 #, fuzzy msgid "Options about comparing backups" msgstr "Možnosti porovnávania snímok" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Príkaz:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametre:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Použiť %1 a %2 parametre cesty" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Prosím, nastavte príkaz diff alebo stlačte Zrušiť." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Príkaz \"{cmd}\" sa v tomto systéme nenašiel. Skúste niečo iné alebo stlačte" " Zrušiť." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Pre príkaz diff neboli nastavené žiadne parametre. Používa sa predvolená " "hodnota \"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Záloha" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Iba odlišné snímky" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "Zoznam snímok, ktoré sú rovné:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Hĺbková kontrola (presnejšia, ale pomalšia)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Vymazať" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Vybrať všetko" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Porovnať" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Ísť na" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Možnosti" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" #: qt/snapshotsdialog.py:440 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Naozaj chcete odstrániť {file} zo snímky {snapshot_id}?" #: qt/snapshotsdialog.py:445 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Naozaj chcete odstrániť {file} v {count} snímkach?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "UPOZORNENIE: Nie je možné odvolať." #: qt/snapshotsdialog.py:465 #, fuzzy, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Vylúčiť {path} z budúcich snímok?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Koreňový priečinok" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Dnes" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Včera" #: qt/timeline.py:87 msgid "This week" msgstr "Tento týždeň" #: qt/timeline.py:95 msgid "Last week" msgstr "Minulý týždeň" #: qt/timeline.py:270 #, fuzzy msgid "This is NOT a backup but a live view of the local files." msgstr "Toto NIE JE snímka, ale živý náhľad vašich lokálnych súborov" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Posledná kontrola {time}" backintime-1.6.1/common/po/sl.po000066400000000000000000002106731514264426600165340ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Liam Starič (ravijol1) # SPDX-FileCopyrightText: © Vanja Cvelbar # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-01-28 13:53+0000\n" "Last-Translator: ravijol1 \n" "Language-Team: Slovenian \n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);\n" "X-Generator: Weblate 5.15.2\n" "X-Poedit-Country: SLOVENIA\n" "X-Poedit-Language: Slovenian\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Opozorilo" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Glavni profil" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokalno šifrirano (EncFC)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH šifrirano (EncFS)" #: common/config.py:237 msgid "Local" msgstr "Lokalno" #: common/config.py:240 msgid "Local encrypted" msgstr "Lokalno šifrirano" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Šifriranje" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Privatni ključ SSH" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Mapa z varnostnimi kopijami ni veljavna." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "" #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Mapa: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Tega direktorija ni mogoče vključiti v varnostno kopijo, ker je del samega " "cilja varnostne kopije." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udev razpored ne deluje z načinom {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Novega crontaba ni mogoče zapisati." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" #: common/configfile.py:101 msgid "Failed to save config" msgstr "Konfiguracije ni bilo mogoče shraniti" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Konfiguracije ni bilo mogoče naložiti" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profil \"{name}\" že obstaja." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Zadnjega profila ni mogoče odstraniti." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Ni mogoče vmestiti \"{command}\"" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Konfiguracije za šifrirano mapo ni bilo mogoče najti." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Želite ustvariti novo šifrirano mapo?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Prekliči" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Prosimo, da za potrditev še enkrat vpišete geslo za EncFS." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS gesla se ne ujemajo." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Ustvari posnetek" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Ni bilo mogoče inicializirati pot \"{command}\"" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "{mountprocess} ni bilo mogoče odklopiti iz {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "{command} ni mogoče najti. Namestite ga (npr. z \"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Točka priklopa {mntpoint} ni prazna." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Vpišite geslo za profil {mode} \"{profile}\":" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Ni bilo mogoče namestiti pravila Udev za profil {profile_id}. Storitev DBus " "'{dbus_interface}' ni bila na voljo." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Ni bilo mogoče najti UUID za {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "SPODLETELO" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Obnovi dovoljenja" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Končano" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Odložitev varnostnega kopiranja med delovanjem na bateriji" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Mape za varnostne kopije ni bilo mogoče najdi." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Če je na izmenljivem pogonu, ga priključite." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Čakanje {n} sekund." msgstr[1] "Čakanje {n} sekundo." msgstr[2] "Čakanje {n} sekundi." msgstr[3] "Čakanje {n} sekunde." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Ustvarjanje varnostne kopije {snapshot_id} ni uspelo." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Mape ni mogoče ustvariti." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Shranjevanje konfiguracijske datoteke…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Shranjevanje dovoljenj…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "" "Najdena nedokončana varnostna kopija {snapshot_id}, ki jo je mogoče " "nadaljevati." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Odstranjevanje nedokončane {snapshot_id} mape od zadnjega zagona" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Mape ni bilo mogoče odstraniti" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Ustvarjane varnostne kopije" #: common/snapshots.py:1517 msgid "Success" msgstr "Uspeh" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Delni prenos zaradi napake" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "Delni prenos zaradi izginulih izvornih datotek (glej 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' se je končal z izhodno kodo {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Za več informacij glej 'man rsync'" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negativne izhodne kode rsync so signalne številke, glej 'kill -l' in 'man " "kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Nič se ni spremenilo, nova varnostna kopija ni potrebna" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "{new_path} ni mogoče preimenovati v {path}." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Uveljavljanje pravil za odstranjevanje starih varnostnih kopij" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Poskus ohranjanja minimalnega prostora" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Poskus ohranjanja najmanj {perc} prostih inodov" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Zdaj" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "{sshfs} ni bilo mogoče vmestiti" #: common/sshtools.py:306 #, fuzzy msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent ni bil najden. Prepričajte se, da je nameščen." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Zasebnega ključa ssh ni bilo mogoče odkleniti. Napačno geslo ali geslo ni na" " voljo za cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Oddaljena pot obstaja, ampak ni mapa." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Oddaljena pot ni zapisljiva." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Oddaljena pot ni izvršljiva." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Oddaljene poti ni bilo mogoče ustvariti." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Oddaljeni gostitelj {host} ne podpira {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Ukazi za preverjanje na gostitelju {host} so vrnili neznano napako" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Oddaljeni gostitelj {host} ne podpira trdih povezav" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Kopiraj javni ssh-ključ \"{pubkey}\" na oddaljenega gostitelja \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Prosim vpišite geslo za \"{user}\"." #: common/tools.py:382 #, fuzzy, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Ciljni datotečni sistem za {path} je formatiran s FAT, ki ne podpira trdih " "povezav. Uporabite lastni datotečni sistem Linux." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "Oddaljena pot {path} obstaja, ampak ni mapa." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "" #: common/tools.py:471 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Ciljni datotečni sistem za {path} je formatiran s FAT, ki ne podpira trdih " "povezav. Uporabite lastni datotečni sistem Linux." #: common/tools.py:482 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Ciljni datotečni sistem za {path} je SMB priklopjen v skupno rabo. " "Preverite, ali oddaljeni strežnik SMB podpira simbolne povezave ali " "aktivirajte {copyLinks} v {expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopiraj povezave (dereferenciraj simbolne povezave)" #: common/tools.py:487 msgid "Expert Options" msgstr "Napredne možnosti" #: common/tools.py:491 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Ciljni datotečni sistem za {path} je priklopljen v skupno rabo s protokolom " "sshfs . Sshfs ne podpira trdih povezav. Namesto tega uporabite način 'SSH'." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "O Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Avtorske pravice:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Avtorji:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Prevajalci:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Liam Starič (ravijol1) \n" "Vanja Cvelbar " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "ta povezava" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Spletno mesto projekta" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Navodila za uporabo" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Različica{BOLDEND}: {version}" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Zgleda, da ste prvič zagnali {app_name}, ker ni mogoče najti konfiguracije." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Uvozi obstoječo konfiguracijo (iz imenika varnostne kopije ali iz drugega " "računalnika)?" #: qt/app.py:395 msgid "Then press OK." msgstr "Potem pritisnite OK." #: qt/app.py:499 msgid "Create a backup" msgstr "Ustvari varnostno kopijo" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Za zaznavanje datotečnih sprememb uporabite čas in velikost." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "Ustvari posnetek (način checksum)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Za zaznavanje datotečnih sprememb uporabite checksum." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Začasno ustavi postopek varnostnega kopiranja" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Nadaljuj postopek varnostnega kopiranja" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Ustavi postopek varnostega kopiranja" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Osveži seznam varnostnih kopij" #: qt/app.py:524 msgid "Name backup" msgstr "Imenuj varnostno kopijo" #: qt/app.py:528 msgid "Remove backup" msgstr "Odstrani varnostno kopijo" #: qt/app.py:532 msgid "Open backup log" msgstr "Ogled dnevnika varnostnih kopij" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Ne odstranjuj posnetkov z imenom." #: qt/app.py:536 msgid "Open last backup log" msgstr "Odpri zadnji dnevnik varnostnih kopij" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "Upravljanje profilov…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Uredi user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Zaustavi" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "Zaustavite sistem, ko je posnetek končan." #: qt/app.py:552 msgid "Setup language…" msgstr "Nastavitev jezika…" #: qt/app.py:556 msgid "Exit" msgstr "Izhod" #: qt/app.py:566 #, fuzzy msgid "man page: Back In Time" msgstr "Back In &Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "" #: qt/app.py:571 #, fuzzy msgid "man page: Profiles config file" msgstr "Konfiguracijska datoteka profilov" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Dnevnik sprememb" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" #: qt/app.py:589 msgid "FAQ" msgstr "Pogosta vprašanja" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "" #: qt/app.py:593 msgid "Ask a question" msgstr "Postavite vprašanje" #: qt/app.py:597 msgid "Report a bug" msgstr "Prijavite napako" #: qt/app.py:600 msgid "Translation" msgstr "Prevod" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "" #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Prehod šifriranja (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "" #: qt/app.py:615 msgid "About" msgstr "O programu" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Obnovi" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "Obnovi izbrane datoteke ali mape v prvotni cilj." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Obnovi v …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "Obnovi izbrane datoteke ali mape v nov cilj." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "Obnovi trenutno prikazano mapo in vso njeno vsebino v prvotni cilj." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "Obnovi trenutno prikazano mapo in vso njeno vsebino v nov cilj." #: qt/app.py:640 msgid "Up" msgstr "Gor" #: qt/app.py:643 msgid "Show hidden files" msgstr "Pokaži skrite datoteke" #: qt/app.py:646 msgid "Compare backups…" msgstr "Primerjaj varnostne kopije…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "" #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&VarnostnaKopija" #: qt/app.py:733 msgid "&Restore" msgstr "&Obnovi" #: qt/app.py:739 msgid "&Help" msgstr "&Pomoč" #: qt/app.py:790 msgid "Systray Icon" msgstr "Systray ikona" #: qt/app.py:796 msgid "Automatic" msgstr "Samodejno" #: qt/app.py:800 msgid "Light icon" msgstr "Svetla ikona" #: qt/app.py:801 msgid "Dark icon" msgstr "Temna ikona" #: qt/app.py:824 msgid "Icons only" msgstr "Samo ikone" #: qt/app.py:827 msgid "Text only" msgstr "Samo besedilo" #: qt/app.py:830 msgid "Text below icons" msgstr "Besedilo pod ikonami" #: qt/app.py:833 msgid "Text beside icon" msgstr "Besedilo zraven ikone" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Ta mapa ne obstaja\n" "v trenutno izbranem posnetku." #: qt/app.py:1005 msgid "Add to Include" msgstr "Dodaj v Vključi" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Dodaj v Izključi" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Če zaprete to okno, Back In Time ne bo mogel ugasniti vašega sistema, ko se " "posnetek stanja zaključi." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Narejeno, varnostna kopija ni potrebna" #: qt/app.py:1285 msgid "Working:" msgstr "V obdelavi:" #: qt/app.py:1292 msgid "Working" msgstr "V obdelavi" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Napaka" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Poslano:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Hitrost:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 msgid "Backup:" msgstr "Varnostna kopija:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Obnovi {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Obnovi {path} v …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Pozdravljeni!\n" "Back In Time v jeziku {language} ste do zdaj že nekajkrat uporabljali.\n" "Prevod vaše nameščene verzije Back In Time v {language} je {perc} dokončan. Ne glede na vaš nivo na tehničnega znanja, lahko prispevate k prevodu in s tem k samemu projektu Back In Time.\n" "Če želite prispevati, obiščite {translation_platform_url}. Za dodatno pomoč in vprašanja, prosimo obiščite {back_in_time_project_website}.\n" "Opravičujemo se za prekinitev, to sporočilo ne bo več prikazano. To pogovorno okno je kadar koli na voljo prek menija za pomoč.\n" "Vaša ekipa Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "prevajalna platforma" #: qt/app.py:1714 msgid "Website" msgstr "Spletna stran" #: qt/app.py:1728 msgid "Your translation" msgstr "Vaš prevod" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "" #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Mailing lista {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "" #: qt/app.py:1781 msgid "Open an issue" msgstr "Prijavi napako" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}POZOR{BOLDEND}: Brisanje datotek v korenskem datotečnem sistemu lahko " "pokvari ves sistem." #: qt/app.py:2167 msgid "Backup name" msgstr "Ime varnostne kopije" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "Nastavitve jezika se uveljavijo po ponovnem zagonu Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Verzijske varnostne kopije" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Vprašanje" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Pred prepisom ali odstranitvijo lokalnih datotek, ustvarite varnostne kopije" " s pripono {suffix}." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Imenom novejših različic datotek bo pred obnovitvijo dodana pripona " "{suffix}. Če jih ne potrebujete več, jih lahko odstranite z naslednjim " "ukazom:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Obnovi le datoteke, ki ne obstajajo ali so novejše od tistih na ciljni " "lokaciji. Uporablja možnost \"{rsync_example}\"." #: qt/confirmrestoredialog.py:133 #, fuzzy msgid "Remove newer elements in original directory." msgstr "Odstrani novejše datoteke v prvotni mapi." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Obnovite izbrane datoteke ali mape na prvotno ciljno lokacijo in odstranite " "datoteke ali mape, ki jih ni v posnetku. Bodite zelo previdni, saj bo to " "odstranilo datoteke in mape, ki so bile izključene med ustvarjanjem " "posnetka." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "Ali res želite obnoviti te elemente v novo mapo?" msgstr[1] "Ali res želite obnoviti ta element v novo mapo?" msgstr[2] "Ali res želite obnoviti ta elementa v novo mapo?" msgstr[3] "Ali res želite obnoviti te elemente v novo mapo?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Ali res želite obnoviti te elemente?" msgstr[1] "Ali res želite obnoviti ta element?" msgstr[2] "Ali res želite obnoviti ta elementa?" msgstr[3] "Ali res želite obnoviti te elemente?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Vključi datoteke in mape" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Nastavitev jezika" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Prevedeno: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Sistemsko privzeto" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "Uporabi jezik operacijskega sistema." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Dnevnik varnostnih kopij" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Zadnji dnevnik" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Varnostne kopije:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filter:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Napake, [I] Informacije, [C] Spremembe" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "dekodiranje poti" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Vse" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Spremembe" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Napake" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informacij" msgstr[1] "Informacija" msgstr[2] "Informaciji" msgstr[3] "Informacije" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "Neuspešni prenosi rsync (eksperimentalno)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Upravljanje profilov" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Uredi" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Dodaj" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Odstrani" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Splošno" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Vključitev" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Izključitev" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Možnosti" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "&Napredne nastavitve" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Obnovi konfiguracijo" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Nov profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Preimenuj profil" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Odstrani profil \"{name}\"?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Samo zunanje" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Varnostne kopije Emacs datotek" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs autosave datoteke" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Mape za varnostno kopijo" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Sistemska začasna mapa" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Pokaži skrite datoteke" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Razno" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Varnostne kopije sistemskih datotek" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Izključi predloge" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Privzeto" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Časovni razpored" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dan:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Dan v tednu:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Čas:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Ur:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "po tej uri" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minute:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Zaženi Back In Time takoj, ko se disk poveže (zgolj enkrat na X dni). Od vas" " bo zahtevan vpis sudo gesla." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Zaženi Back In Time večkrat. To služi za primer, ko računalnik ni redno " "prižgan." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Vsakih:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Omogoči beleženje razhroščevalnih sporočil" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Zapiše razhroščevalna poročila v sistemsko beleženje z uporabo \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Pozor: uporabite samo začasno za odpravljanje napak, ker ustvari zelo veliko" " podatkov." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Onemogočeno" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Ob vsakem zagonu/ponovnem zagonu" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Vsakih {n} minut" msgstr[1] "Vsako {n} minuto" msgstr[2] "Vsake {n} minute" msgstr[3] "Vsake {n} minute" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Vsakih {n} ur" msgstr[1] "Vsakih {n} uro" msgstr[2] "Vsaki {n} uri" msgstr[3] "Vsake {n} ure" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Ure po meri" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Vsak dan" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Ponavljajoče (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Ko se priključi disk (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Vsak teden" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Vsak mesec" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Vsako leto" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Ura/ur" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dan/dni" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Teden/tednov" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mesec/mesecev" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Ure po meri so lahko samo seznam ur, ločenih z vejicami (npr. 8,12,18,23) " "ali */3 za občasne varnostne kopije vsake 3 ure." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 #, fuzzy msgid "Choose an existing private key file from somewhere else." msgstr "" "Изаберите постојећи приватни кључ фајл (обично именован \"id_ed25519\" а у " "старијим подешавањима \"id_rsa\")." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 #, fuzzy msgid "Create a new SSH key without passphrase." msgstr "Креирање новог SSH кључа у {path} није успело." #: qt/manageprofiles/sshkeyselector.py:92 #, fuzzy, python-brace-format msgid "Full path: {path}" msgstr "Пуна путања снимка:" #: qt/manageprofiles/sshkeyselector.py:205 #, fuzzy msgid "Private key:" msgstr "Приватни Кључ:" #: qt/manageprofiles/sshkeyselector.py:210 #, fuzzy msgid "Use system SSH configuration" msgstr "Увези конфигурацију" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH прокси" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Домаћин:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Порт:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Корисник:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Повежите се са циљним домаћином преко овог проксија (познатог и као jump " "host). Погледајте \"-J\" у документацији за \"ssh\" команду или " "\"ProxyJump\" у \"ssh_config\" man страници за детаље." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Информације{ENDBOLD}: У 'SSH шифровано' режиму, само једноструке или " "двоструке звездице су функционалне (нпр. {example2}). Други типови џокера и " "шаблона ће бити игнорисани (нпр. {example1}). Имена датотека су непредвидива" " у овом режиму због шифровања од стране EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Изоставите шаблоне, фајлове или директоријуме" #: qt/manageprofiles/tab_exclude.py:102 #, fuzzy msgid "Add pattern" msgstr "Изостави шаблон" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 #, fuzzy msgid "Add files" msgstr "Додај фајл" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 #, fuzzy msgid "Add directories" msgstr "Додајте директоријум" #: qt/manageprofiles/tab_exclude.py:118 #, fuzzy msgid "Suggestions" msgstr "Питање" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Изостави фајлове веће од:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Изостави фајлове веће од вредности у {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 #, fuzzy msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Са онемогућеним 'Full rsync mode', ово ће утицати само на нове фајлове јер " "је за rsync ово опција преноса, а не опција изостављања. Стога, велики " "фајлови који су претходно резервно копирани ће остати у снимцима чак и ако " "су модификовани." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Изостави шаблон" #: qt/manageprofiles/tab_exclude.py:267 #, fuzzy msgid "Enter an exclude pattern:" msgstr "Изостави шаблон" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "" #: qt/manageprofiles/tab_exclude.py:303 #, fuzzy msgid "Exclude files" msgstr "Изостави фајл" #: qt/manageprofiles/tab_exclude.py:316 #, fuzzy msgid "Exclude directories" msgstr "Изоставите директоријум" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "Деактивирано зато што шаблони не функционишу у 'SSH шифрованом' моду." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Ове опције су за напредне конфигурације. Измените само ако сте у потпуности " "свесни њихових импликација." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Покрените 'rsync' са '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "као cron посао" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "на удаљеном домаћину" #: qt/manageprofiles/tab_expert_options.py:86 #, fuzzy msgid "when taking a manual backup" msgstr "када се креира ручни снимак" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Молимо вас да инсталирате 'nocache' да бисте омогућили ову опцију." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "на локалној машини" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Преусмерите stdout ка /dev/null у cron пословима." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron ће аутоматски послати email са приложеним излазом cronjob-ова уколико " "је MTA инсталиран." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Преусмерите stderr према /dev/null у cron пословима." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron ће аутоматски послати email са приложеним грешкама од cronjob-ова " "уколико је MTA инсталиран." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/сек" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Ограничите употребу пропусног опсега rsync-а:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Сачувај ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Сачувај проширене атрибуте (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Ограничите на само један фајл систем" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Опције морају бити под наводницима нпр. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Налепи додатне опције за rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Префикс који ће се покретати пре сваке команде на удаљеном домаћину." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Променљиве треба искочити са \\$FOO. Ово не дотиче rsync. Тако да би додали " "префикс за rsync користите \"{example_value}\" са {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "подразумевано" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Додај префикс SSH командама" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Провери да ли је удаљени домаћин онлајн" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Упозорење: уколико је онемогућено и удаљени домаћин није доступан, ово може " "довести до неких чудних грешака." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Проверите да ли удаљени домаћин подржава све неопходне команде." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Упозорење: уколико је онемогућено и удаљени домаћин не подржава све " "неопходне команде, ово може довести до неких чудних грешака." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(подразумевано: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "онемогућено" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "омогућено" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Мод:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 #, fuzzy msgid "Where to save backups" msgstr "Где да чувам снимке" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH Поставке" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Путања:" #: qt/manageprofiles/tab_general.py:139 #, fuzzy msgid "Key file:" msgstr "Нови профил" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Лозинка" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Сачувај лозинку у Keyring" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Кеширај лозинку за Cron (Безбедносни проблем: root може читати лозинку)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Напредно" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 #, fuzzy msgid "Full backup path:" msgstr "Пуна путања снимка:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "" #: qt/manageprofiles/tab_general.py:404 #, fuzzy msgid "The encryption password cannot be empty." msgstr "Лозинка се не поклапа." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Аутентичност домаћина {host} се не може утврдити." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} отисак прста кључа је:" #: qt/manageprofiles/tab_general.py:613 #, fuzzy msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Молимо проверите овај отисак прста. Да ли желите да га додате у своју " "датотеку 'known_hosts'?" #: qt/manageprofiles/tab_general.py:709 #, fuzzy msgid "Really change the backup directory?" msgstr "Да ли желите да креирате нови шифровани директоријум?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "" #: qt/manageprofiles/tab_general.py:756 #, fuzzy msgid "Invalid file: Not a private SSH key" msgstr "SSH приватни кључ" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Креирање новог SSH кључа у {path} није успело." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Укључи фајлове и директоријуме" #: qt/manageprofiles/tab_include.py:168 #, fuzzy, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" је симболичка веза. Повезана мета неће бити резервно копирана док је не укључите.\n" "Да ли желите да укључите мету симболичке везе?" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Укључити циљ уместо симболичке везе?" #: qt/manageprofiles/tab_include.py:180 #, fuzzy msgid "Include files" msgstr "Укључи фајл" #: qt/manageprofiles/tab_include.py:199 #, fuzzy msgid "Include directories" msgstr "Укључите директоријум" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Омогући обавештења" #: qt/manageprofiles/tab_options.py:43 #, fuzzy msgid "Disable backups when on battery" msgstr "Онемогући снимке када се рачунар напаја из батерије" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Информација о статусу напајања није доступна од система" #: qt/manageprofiles/tab_options.py:52 #, fuzzy msgid "Run only one backup at a time" msgstr "Покрени само један снимак у исто време" #: qt/manageprofiles/tab_options.py:56 #, fuzzy msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Остали снимци ће бити блокирани док се тренутни снимак не заврши. Ово је " "глобална опција. Тако да ће утицати на све профиле за овог корисника. Али " "ово морате активирати и за све остале кориснике такође." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Резервна копија је заменила фајлове приликом враћања" #: qt/manageprofiles/tab_options.py:78 #, fuzzy msgid "Continue on errors (keep incomplete backups)" msgstr "Настави након грешке (задржи непотпун снимак)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Користи контролни број за примећивање промена" #: qt/manageprofiles/tab_options.py:86 #, fuzzy msgid "Create a new backup whether there were changes or not." msgstr "Направи нови снимак без обзира да ли је било промена или не." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Ниво детаља у извештају:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Ниједан" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "приручник за кориснике" #: qt/manageprofiles/tab_remove_retention.py:208 #, fuzzy, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Следећа правила се обрађују од врха до дна. Каснија правила надјачавају " "ранија и нису ограничена њима. Погледајте {manual} за детаље и примере." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Отворите приручник за кориснике у прегледачу." #: qt/manageprofiles/tab_remove_retention.py:237 #, fuzzy msgid "Keep the most recent backup." msgstr "Чувајте именоване снимке." #: qt/manageprofiles/tab_remove_retention.py:241 #, fuzzy msgid "The most up-to-date backup is kept under all circumstances." msgstr "Последњи или најсвежији снимак се чува под свим околностима." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "То понашање не може бити промењено." #: qt/manageprofiles/tab_remove_retention.py:255 #, fuzzy msgid "Keep named backups." msgstr "Чувајте именоване снимке." #: qt/manageprofiles/tab_remove_retention.py:258 #, fuzzy msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Снимци који, поред уобичајене временске ознаке, имају дато име неће бити " "обрисани." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "Година" #: qt/manageprofiles/tab_remove_retention.py:278 #, fuzzy msgid "Remove backups older than" msgstr "Уклони снимак" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Пуни дани. Текући дан се игнорише." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Календарске недеље са понедељком као првим даном. Текућа недеља се игнорише." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12-месечни периоди. Текући месец се игнорише." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Политика задржавања" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Покрени у позадини на удаљеном домаћину." #: qt/manageprofiles/tab_remove_retention.py:313 #, fuzzy msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Процедура паметног уклањања ће се извршити директно на удаљеној машини, а не" " локално. Команде \"bash\", \"screen\" и \"flock\" морају бити инсталиране и" " доступне на удаљеној машини." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Ако је изабрано, Back In Time ће прво тестирати удаљену машину." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Дани се броје од данас." #: qt/manageprofiles/tab_remove_retention.py:322 #, fuzzy msgid "Keep all backups for the last" msgstr "Задржи све снимке за последњи" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "дан(а)." #: qt/manageprofiles/tab_remove_retention.py:334 #, fuzzy msgid "Keep the last backup for each day for the last" msgstr "Задржи један снимак дневно за последњи" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "Недеље се броје од тренутне недеље. Недеља почиње у понедељак." #: qt/manageprofiles/tab_remove_retention.py:347 #, fuzzy msgid "Keep the last backup for each week for the last" msgstr "Задржи један снимак недељно за последњи" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "недеља/е." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Месеци се броје као календарски месеци, почевши од текућег месеца." #: qt/manageprofiles/tab_remove_retention.py:360 #, fuzzy msgid "Keep the last backup for each month for the last" msgstr "Задржи један снимак месечно за последњи" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "месец(и)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Године се броје као календарске године, почевши од текуће године." #: qt/manageprofiles/tab_remove_retention.py:372 #, fuzzy msgid "Keep the last backup for each year for" msgstr "Задржи све снимке за последњи" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "све године." #: qt/manageprofiles/tab_remove_retention.py:389 #, fuzzy msgid "… the free space is less than" msgstr "Ако је слободан простор мањи од:" #: qt/manageprofiles/tab_remove_retention.py:394 #, fuzzy msgid "… the free inodes are less than" msgstr "Ако је број слободних inode-ова мањи од:" #: qt/manageprofiles/tab_remove_retention.py:403 #, fuzzy msgid "Remove oldest backup if …" msgstr "Уклањање старог снимка" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Пречице" #: qt/placeswidget.py:63 msgid "Places" msgstr "" #: qt/placeswidget.py:64 msgid "File System" msgstr "" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Директоријуми резервне копије" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Профил: {profile_name}" #: qt/qtsystrayicon.py:112 #, fuzzy, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Профил: {profile_name}" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Прикажи последњи извештај" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Покрени {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Радим…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Увези конфигурацију" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Увези" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 #, fuzzy msgid "Searching…" msgstr "Радим…" #: qt/restoreconfigdialog.py:211 #, fuzzy, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Изаберите директоријум снимка из којег треба да се увезе конфигурациони " "фајл. Путања може изгледати овако: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Ако се директоријум налази на спољном или удаљеном диску, мора бити ручно " "монтиран пре тога." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "" #: qt/restoreconfigdialog.py:256 #, fuzzy msgid "Show hidden directories" msgstr "Прикажи скривене фајлове" #: qt/restoreconfigdialog.py:258 #, fuzzy msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Укључи фајлове и директоријуме" #: qt/restoreconfigdialog.py:305 #, fuzzy msgid "No config found in this directory" msgstr "Креирање фајла није успело у овом директоријуму:" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Прикажи целокупни дневник" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Одбројавање до гашења" #: qt/shutdowndlg.py:29 #, fuzzy msgid "The backup has finished." msgstr "Искључи систем након што снимак буде завршен." #: qt/shutdowndlg.py:36 #, fuzzy msgid "Cancel Shutdown" msgstr "Искључивање" #: qt/shutdowndlg.py:37 #, fuzzy msgid "Shutdown Now" msgstr "Искључивање" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: qt/snapshotsdialog.py:63 #, fuzzy msgid "Options about comparing backups" msgstr "Опције о упоређивању снимака" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Команда:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Параметри:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Користи %1 и %2 као параметре за путање" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Молим поставите команду за тражење разлика или притисните Откажи." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Команда \"{cmd}\" није пронађена на овом систему. Молимо пробајте нешто " "друго или притисните Откажи." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Параметри нису постављени за команду за тражење разлика. Користиће се " "подразумевана вредност \"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 #, fuzzy msgid "Backups" msgstr "&Резервна копија" #: qt/snapshotsdialog.py:152 #, fuzzy msgid "Differing backups only" msgstr "Само различити снимци" #: qt/snapshotsdialog.py:161 #, fuzzy msgid "List only backups that are equal to:" msgstr "Излистај само снимке једнаке следећим:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Дубока провера (прецизнија али спора)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Избриши" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Одабери Све" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Упореди" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Иди на" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Опције" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Нису могуће упоређивање резервне копије са самом собом, јер би упоређивање " "било редундантно." #: qt/snapshotsdialog.py:440 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Да ли стварно желите да избришете {file} у снимку {snapshot_id}?" #: qt/snapshotsdialog.py:445 #, fuzzy, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Да ли стварно желите да избришете {file} у {count} снимака?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "УПОЗОРЕЊЕ: Ово се не може опозвати." #: qt/snapshotsdialog.py:465 #, fuzzy, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Изостави {path} из будућих снимака?" #: qt/statusbar.py:85 #, fuzzy msgid "Root mode" msgstr "Корен (root)" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" #: qt/timeline.py:69 msgid "Today" msgstr "Данас" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Јуче" #: qt/timeline.py:87 msgid "This week" msgstr "Ове недеље" #: qt/timeline.py:95 msgid "Last week" msgstr "Претходна седмица" #: qt/timeline.py:270 #, fuzzy msgid "This is NOT a backup but a live view of the local files." msgstr "Ово НИЈЕ снимак, већ ужив приказ ваших локалних фајлова" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Задња провера {time}" backintime-1.6.1/common/po/sr_Latn.po000066400000000000000000002207411514264426600175150ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Mališa "Maki711" Jevremović # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-04-10 10:35+0000\n" "Last-Translator: buhtz \n" "Language-Team: Serbian (Latin script) \n" "Language: sr_Latn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 5.10.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Upozorenje" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Glavni profil" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Lokalno (EncFS šifrovano)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS šifrovano)" #: common/config.py:237 msgid "Local" msgstr "Lokalno" #: common/config.py:240 msgid "Local encrypted" msgstr "Lokalno šifrovano" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Enkripcija" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH privatni ključ" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: \"{name}\"" #: common/config.py:301 #, fuzzy msgid "Backup directory is not valid." msgstr "Direktorijum za snimak nije važeći." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Najmanje jedan direktorijum za rezerne kopije mora biti izabran." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "Direktorijum: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Ovaj direktorijum ne može biti izabran za rezervne kopije pošto je deo " "ciljnog direktorijuma za kopije." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udev raspored ne radi sa režimom {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Neuspešno čuvanje novog crontab-a." #: common/config.py:1577 #, fuzzy msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron nije pokrenut, uprkos tome što je crontab komanda dostupna. Zakazana " "rezervna kopija neće biti pokrenuta. Cron je možda instaliran ali nije " "omogućen. Isprobajte komandu \"systemctl enable cron\" ili kontaktirajte " "podršku za GNU/Linux distribuciju." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Neuspešno čuvanje konfiguracije" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Neuspešno učitavanje konfiguracije" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Profil \"{name}\" već postoji." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Poslednji profil se ne može ukloniti." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Nije moguće montirati '{command}'" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Podešavanja za enkriptovani direktorijum nisu pronađena." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Napraviti novi enkriptovani direktorijum?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Otkazati" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "Molim vas unesite lozinku za \"{user}\"." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "Lozinka se ne poklapa." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Napravi snimak" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Nije moguće montirati '{command}'" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Nije moguće demontirati {mountprocess} sa {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} nije pronađen. Molimo da ga instalirate (npr. sa " "\"{installcommand}\")" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Tačka montiranja {mntpoint} nije prazna." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Unesi šifru za {mode} profil \"{profile}\":" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Neuspešno instaliranje Udev pravila za profil {profile_id}. DBus servis " "'{dbus_interface}' nije dostupan" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Nije moguće naći UUID za {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "NEUSPEŠNO" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Povrati dozvole" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Gotovo" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Odlaganje sigurnosne kopije dok je uređaj na bateriji" #: common/snapshots.py:931 qt/app.py:393 #, fuzzy msgid "Can't find backup directory." msgstr "Ne mogu da pronađem direktorijum snimaka." #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "Ako je na prenosivom disku, priključite ga." #: common/snapshots.py:938 #, fuzzy, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Čeka se %s sekunda." msgstr[1] "Čeka se %s sekunde." msgstr[2] "Čeka se %s sekundi." #: common/snapshots.py:1005 #, fuzzy, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Neuspešno čuvanje snimka {snapshot_id}." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Molim vas budite strpljivi. Završavanje u toku…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Neuspešno kreiranje direktorijuma." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Čuvanje konfiguracionog fajla…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Čuvanje dozvola…" #: common/snapshots.py:1377 #, fuzzy, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "Pronađen preostali snimak {snapshot_id} koji se može nastaviti." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Uklanjanje preostalog direktorijuma {snapshot_id} iz poslednjeg pokretanja" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Neuspešno uklanjanje direktorijuma" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "Uspelo" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Delimičan prenos zbog greške" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "" "Delimičan prenos zbog iščezlih izvornih fajlova (pogledajte 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' se završio sa izlaznim kodom {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Pogledaj 'man rsync' za više detalja" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negativni rsync izlazni kodovi su signalni brojevi, pogledajte 'kill -l' i " "'man kill'" #: common/snapshots.py:1566 #, fuzzy msgid "Nothing changed, no new backup necessary" msgstr "Nikakve promene, nepotreban novi snimak" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Neuspešno preimenovanje {new_path} u {path}." #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Primenite pravila za uklanjanje starih snimaka" #: common/snapshots.py:2031 #, fuzzy msgid "Applying retention policy" msgstr "Primenite smernice čuvanja" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Pokušavam da zadržim minimalno slobodnog prostora" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Pokušavam da zadržim minimalno {perc} slobodnih inode-ova" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Sada" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Nemoguće montirati {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent nije pronađen. Molim vas da se uverite da je instaliran." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Nije moguće otključati ssh privatni ključ. Pogrešna lozinka ili lozinka nije" " dostupna za cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Udaljena putanja postoji, ali nije direktorijum." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Udaljena putanja nije dostupan za pisanje." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Udaljena putanja nije izvršna." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Nije moguće kreirati udaljenu putanju." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Udaljena mašina {host} ne podržava {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Provera komandi na mašini {host} vratila je nepoznatu grešku" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Udaljena mašina {host} ne podržava tvrde veze" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Kopiraj javni ssh-ključ \"{pubkey}\" na udaljenoj mašini \"{host}\"." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Molim vas unesite lozinku za \"{user}\"." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Ciljni sistem datoteka za {path} je formatiran u NTFS, koji ima poznate " "nekompatibilnost sa sistemima datoteka sličnim Unix-u." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "Putanja {path} nije važeći direktorijum." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Kreiranje sledećeg direktorijuma je bilo neuspešno:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Pristup za pisanje je možda ograničen." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Ciljni sistema datoteka za {path} je formatiran sa FAT koji ne podržava " "čvrste veze. Molim Vas da koristite izvorne sistemske datoteke GNU/Linux-a." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Ciljni sistema datoteke za {path} je deljeno mesto preko SMB. Molim Vas da " "potvrdite da udaljeni SMB server podržava symlinks ili uključite {copyLinks}" " u {expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Kopiraj linkove (prati simbolične linkove)" #: common/tools.py:487 msgid "Expert Options" msgstr "Napredne Postavke" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Ciljni sistema datoteka za {path} je deljeno mesto preko SSHFS koji ne " "podržava čvrste veze. Molimo vas da koristite 'SSH' umesto toga." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Kreiranje datoteke u ovom direktorijumu nije uspelo:" #: qt/aboutdlg.py:51 #, fuzzy msgid "About Back In Time" msgstr "Back In &Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 #, fuzzy msgid "Authors:" msgstr "Autori" #: qt/aboutdlg.py:97 #, fuzzy msgid "Translators:" msgstr "Prevodi" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Mališa \"Maki711\" Jevremović" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Web stranica projekta" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Uputstvo za upotrebu" #: qt/aboutdlg.py:227 qt/app.py:562 #, fuzzy msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Otvorite uputstvo za upotrebu u pretraživaču (lokalno, ako je dostupno - " "inače onlajn)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Izgleda da se {app_name} pokreće prvi put pošto konfiguracija nije " "pronađena." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Uvezite postojeću konfiguraciju (iz direktorijuma sa rezervnim kopijama ili " "sa drugog računara)?" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Koristi vreme i veličinu za detekciju promene datoteka." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "Napravi snimak (checksum režim)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Koristi checksum-ove za detekciju promene datoteka." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "Pauziraj proces snimanja" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "Nastavi proces snimanja" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "Zaustavi proces snimanja" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "Osveži listu snimaka" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "Ukloni snimak" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "Prikaži poslednji izveštaj" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Najmanje jedan direktorijum za rezerne kopije mora biti izabran." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "Prikaži poslednji izveštaj" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "Upravljaj profilima…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Promeni user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Gašenje" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "Ugasi sistem nakon završetka snimka." #: qt/app.py:552 msgid "Setup language…" msgstr "Podesi jezik…" #: qt/app.py:556 msgid "Exit" msgstr "Izlaz" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "Man stranica: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "Prikaži man stranicu o Back In Time (backintime)" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "Man stranica: Konfiguracioni fajl profila" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Prikaži man stranicu o konfiguracionalnom fajlu za profile (backintime-" "config)" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "Otvori Back In Time web stranicu u pretraživaču" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Izveštaj promena" #: qt/app.py:586 #, fuzzy msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Otvorite uputstvo za upotrebu u pretraživaču (lokalno, ako je dostupno - " "inače onlajn)" #: qt/app.py:589 msgid "FAQ" msgstr "Česta pitanja (FAQ)" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Otvorite Često postavljana pitanja (FAQ) u pretraživaču" #: qt/app.py:593 msgid "Ask a question" msgstr "Postavi pitanje" #: qt/app.py:597 msgid "Report a bug" msgstr "Prijavi grešku" #: qt/app.py:600 msgid "Translation" msgstr "Prevod" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Ponovo prikaži poruku o učestvovanju u prevodu." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Prevod enkripcije (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Ponovo prikaži poruku o uklanjanju EncFS." #: qt/app.py:615 msgid "About" msgstr "O aplicaciji" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Povrati" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "" "Povrati odabrane datoteke ili direktorijume na njihovu prvobitno odredište." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Povrati na …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "Povrati odabrane datoteke ili direktorijume na novo odredište." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Povrati trenutno prikazan direktorijum i sav njegov sadržaj na prvobitno " "odredište." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Povrati trenutno prikazan direktorijum i sav njegov sadržaj na novo " "odredište." #: qt/app.py:640 msgid "Up" msgstr "Gore" #: qt/app.py:643 msgid "Show hidden files" msgstr "Prikaži skrivene datoteke" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "Uporedi snimke…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Kandidat za izdavanje" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Ponovo prikaži poruku o kandidatu za izdavanje." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Rezervna kopija" #: qt/app.py:733 msgid "&Restore" msgstr "&Povratak" #: qt/app.py:739 msgid "&Help" msgstr "P&omoć" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "Samo ikonice" #: qt/app.py:827 msgid "Text only" msgstr "Samo tekst" #: qt/app.py:830 msgid "Text below icons" msgstr "Tekst ispod ikonica" #: qt/app.py:833 msgid "Text beside icon" msgstr "Tekst pored ikonica" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Ovaj direktorijum ne postoji\n" "u aktuelnom snimku." #: qt/app.py:1005 msgid "Add to Include" msgstr "Dodaj u listu inkluzija" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Dodaj u listu ekskluzija" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Ako zatvorite ovaj prozor Back In Time neće moći da ugasi vaš sistem kada se" " snimak završi." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Završeno, sigurnosna kopija nike potrebna" #: qt/app.py:1285 msgid "Working:" msgstr "U obradi:" #: qt/app.py:1292 msgid "Working" msgstr "Obrada" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Greška" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Poslato:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Brzina:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "&Rezervna kopija" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Povrati {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Povrati {path} u …" # ignore-placeholder-compare #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Zdravo\n" "Koristili ste Back In Time na {language} jeziku već par puta.\n" "Prevod vaše instalirane verzije Back In Time-a u {language} je {perc} gotov. Bez obzira na vaše tehničko znanje, sami možete doprineti prevodu, a time i Back In Time-u.\n" "Molimo vas da posetite {translation_platform_url} ako želite da doprinesete. Za dalju pomoć i pitanja, posetite {back_in_time_project_website}\n" "Izvinjavamo se zbog ometanja. Ova poruka se više neće pojaviti, ali je dostupna u bilo kom trenutku iz menija Pomoć\n" "Vaš Back In Time tim" #: qt/app.py:1709 msgid "translation platform" msgstr "platforma za prevod" #: qt/app.py:1714 msgid "Website" msgstr "Veb stranica" #: qt/app.py:1728 msgid "Your translation" msgstr "Vaš prevod" #: qt/app.py:1765 #, fuzzy, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "U Fediverse na Mastodon-u: {link_and_label}" #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "Dopisna lista {link_and_label}" #: qt/app.py:1774 #, fuzzy, python-brace-format msgid "Mailing list {link_and_label}." msgstr "Dopisna lista {link_and_label}" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "{link_and_label} na web stranici projekta." #: qt/app.py:1781 msgid "Open an issue" msgstr "Otvorite problem" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Alternativno, možete koristiti drugi kanal po svom izboru." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Ova verzija Back In Time je kandidat za izdanje i prvenstveno je namenjena za testiranje stabilnosti u pripremi za sledeće zvanično izdanje.\n" "Korisnički podaci ili telemetrija se ne prikupljaju. Međutim, tim Back In Time je veoma zainteresovan da zna da li će kandidat za izdanje biti korišćen i da li je vredno nastaviti da nudi takve verzije pre izdanja.\n" "Stoga, tim ljubazno traži kratku povratnu informaciju o tome da li ste testirali ovu verziju, čak i ako niste naišli na probleme. Čak i kratko testiranje od samo nekoliko minuta bi nam mnogo pomoglo.\n" "Dostupne su sledeće opcije kontakta:\n" "{contact_list}\n" "U ovoj verziji, ova poruka se više neće prikazivati, ali joj se može pristupiti u bilo kom trenutku preko menija pomoći (Help).\n" "Hvala vam na podršci i što ste nam pomogli da poboljšamo Back In Time!\n" "Vaš Back In Time tim" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}Upozorenje{BOLDEND}: Brisanje datoteka u izvornom sistemu datoteka " "može uništiti vaš ceo sistem." #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "&Rezervna kopija" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" msgstr[1] "" msgstr[2] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Podešavanja jezika stupaju na snagu tek nakon ponovnog pokretanja Back In " "Time-a." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "Zadrži imenovane snimke." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Pitanje" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Napravite rezervne kopije sa pratećim {suffix}\n" "pre pisanja preko ili uklanjanja lokalnih elemenata." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Novije verzije datoteka će se preimenovati sa pretećim {suffix} pre " "vraćanja. Ako vam više nisu potrebne, možete ih ukloniti pomoću komande:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Povratite samo elemente koji nepostoje ili\n" "su noviji od onih u odredištu.\n" "Ovo koristi \"rsync --update\"." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Ukloni novije elemente u originalnom direktorijumu." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Povratite odabrane datoteke ili direktorijume na originalno odredište i " "izbrišite datoteke ili direktorijume koji se ne nalaze u snimku. Budite " "izuzetno oprezni jer će ovo obrisati datoteke i direktorijume koji su bili " "isključeni tokom pravljenja snimka." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Da li zaista želite da povratite ovaj element u novi direktorijum {path}?" msgstr[1] "" "Da li zaista želite da vratite ove elemente u novi direktorijum {path}?" msgstr[2] "" "Da li zaista želite da vratite ove elemente u novi direktorijum {path}?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Da li zaista želite da vratite ovaj element?" msgstr[1] "Da li zaista želite da vratite ove elemente?" msgstr[2] "Da li zaista želite da vratite ove elemente?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Inkludiraj datoteke i direktorijume" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Podesite jezik" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Prevedeno: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Standardne sistemske opcije" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "Koristi jezik operativnog sistema." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "Prikaz zadnjeg protokola" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Prikaz zadnjeg protokola" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 #, fuzzy msgid "Backups:" msgstr "&Rezervna kopija" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filter:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Greška, [I] Informacija, [C] Izmena" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "dekodiraj putanju" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Sve" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Izneme" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Greške" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Informacija" msgstr[1] "Informacije" msgstr[2] "Informacija" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "neuspešni rsync prenosi (eksperimentalno)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Upravljaj profilima" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Uredi" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Dodaj" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Ukloni" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "Opšt&e" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Inkludirano" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "I&zostavi" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Uklanjanje & Vremensko čuvanje" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Opcije" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "&Napredne opcije" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Povrati konfiguraciju" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Novi profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Preimenuj profil" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Da li ste sigurni da želite da uklonite profil \"{name}\" ?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Pauziraj proces snimanja" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Izostavi fajl" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Direktorijumi za rezervne kopije" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Neuspešno uklanjanje direktorijuma" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Prikaži skrivene datoteke" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Zaustavi proces snimanja" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Izostavi direktorijum" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "standardno" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Plan rada" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Dan:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Radni dan:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Vreme:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Sati:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "posle punog sata" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Minuti:" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Pokreni Back In Time čim se disk poveže (samo jednom svakih X dana). Od vas " "će biti traženo da unesete svoju sudo lozinku." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Pokretanje Back In Time uzastopno. Ovo je korisno ako se kompjuter ne " "koristi često." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Svakih:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Omogućite evidentiranje poruka o greškama" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "Zapiši poruke debug nivoa u sistemski protokol pomoću \"--debug\"." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Oprez: ovo koristite samo privremeno za dijagnostiku, jer generiše veliku " "količinu informacija." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Onemogućeno" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Pri svakom pokretanju računara/restartu" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Svakog {n} minuta" msgstr[1] "Svakih {n} minuta" msgstr[2] "Svakih {n} minuta" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Svakog {n} sata" msgstr[1] "Svakih {n} sata" msgstr[2] "Svakih {n} sati" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Prilagođeni sati" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Svakog dana" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Ponavljanje (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Kada se disk poveže (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Svake nedelje" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Svakog meseca" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Svake godine" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Sat(i)" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Dan(a)" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Nedelja/(e)" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Mesec(i)" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Prilagođeni sati mogu biti samo lista sati razdvojena zarezima (npr. " "8,12,18,23) ili */3 za periodične sigurnosne kopije svakih 3 sata." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Välj en befintlig privat nyckel-fil från annan plats." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Skapa en ny SSH-nykel utan lösenfras." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Fullständig genväg för säkerhetskopian: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Privat nyckel:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Använd systemets SSH-konfiguration" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Lämnar nyckel filen som ej vald. SSH anslutningarna kommer förlita sig på " "systemets befintliga klientkonfiguration (t.ex., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Proxy-server för SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Värd:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Port:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Användare:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Anslut till målvärden via den här proxyn (även känd som en hoppvärd). Se " "\"-J\" i kommandodokumentationen för \"ssh\", eller \"ProxyJump\" i manualen" " för \"ssh_config\", för detaljer." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Info{ENDBOLD}: I \"SSH-krypterat\" läge är endast enkla eller dubbla " "asterisker funktionella (t.ex. {example2}). Andra typer av jokertecken och " "mönster kommer att ignoreras (t.ex. {example1}) Filnamn är oförutsägbara i " "detta läge på grund av kryptering med EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Exkludera mönster, filer eller kataloger" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Lägg till mönster" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Lägg till filer" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Lägg till mappar" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Förslag" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "Välj bland vanliga objekt att lägga till i undantagslistan." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Exkludera filer större än:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Exkludera filer som är större än värdet i {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Med 'Fullständigt rsync-läge' inaktiverat så kommer den här inställningen " "enbart att påverka nya filer eftersom att rsync behandlar det här som ett " "överföringsalternativ istället för som ett undantagsalternativ. Följaktligen" " kommer stora filer som redan har säkerhetskopierats att finnas kvar i " "säkerhetskopiorna även om de ändras." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Exkludera mönster" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Ange ett exkluderings mönster:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "För hjälp, se rsync manual-sida-avsnittet {link}." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Öppna rsync manualsida" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Exkludera filer" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Exkludera mappar" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "" "Avstängt eftersom att det här mönstret inte är funktionellt i läget " "'Krypterad SSH'." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Dessa alternativ är för avancerade konfigurationer. Ändra endast om du är " "fullt medveten om deras konsekvenser." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Kör 'rsync' med '{cmd}':" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "som cronjobb" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "på fjärrvärd" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "när en manuell säkerhetskopiering görs" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Vänligen installera 'nocache' för att aktivera detta alternativ." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "på lokal maskin" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Omdirigera stdout till /dev/null i cronjobb." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Cron kommer automatiskt att skicka e-post med bifogad utmatning av cron-jobb" " om en MTA är installerad." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Omdirigera stderr till /dev/null i cronjobb." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Cron kommer automatiskt att skicka ett e-postmeddelande med bifogade fel i " "cron-jobb om en MTA är installerad." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/s" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Bandbreddsbegränsning för rsync:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Behåll ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Behåll utökade attribut (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Begränsa till ett filsystem" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Alternativ måste skrivas inom citationstecken t.ex. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Klistra in ytterligare alternativ till rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Prefix som ska köras före varje kommando på fjärrvärden." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Variabler måste avslutas med \\$FOO. Detta rör inte rsync. Så för att lägga " "till ett prefix för rsync använd \"{example_value}\" med " "{rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "standard" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Lägg till prefix till SSH-kommandon" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Kontrollera om fjärrvärd är uppkopplad" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Varning: Om det är inaktiverat och fjärrvärden inte är tillgänglig kan detta" " leda till konstiga fel." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Kontrollera om fjärrvärden stöder alla nödvändiga kommandon." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Varning: Om det är inaktiverad och fjärrvärden inte stöder alla nödvändiga " "kommandon kan detta leda till konstiga fel." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(standard: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "inaktiverad" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "aktiverad" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Läge:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Var säkerhetskopiorna ska sparas" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH-inställningar" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Sökväg:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Ny profil:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Lösenord" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Spara lösenord till nyckelring" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "" "Spara lösenordet i en cache för Cron (säkerhetsproblem: root kan läsa " "lösenordet)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Avancerat" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Fullständig genväg för säkerhetskopian:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Schemaläggning är inaktiverad eftersom ingen cron-installation hittades. " "Installera cron för att aktivera schemalagda säkerhetskopior." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Sökväg för säkerhetskopia får inte vara tom." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Krypteringslösenordet får inte vara tomt." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Ett fel inträffade vid försök att logga in till fjärrenheten. Följande " "felmeddelande returnerades:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "För att aktivera lösenordsfri inloggning kan den publika SSH-nyckeln " "kopieras till fjärrdatorn." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Fortsätt med att kopiera SSH-nyckel?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Den publika SSH nyckeln kunde inte kopieras. Detta kan bero på ett " "anslutnings eller behörighetsfel." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Autenticiteten för värd {host} kan inte fastställas." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} nyckelfingeravtryck är:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "" "Vänligen bekräfta det här fingeravtrycket. Lägg till det i din " "'known_hosts'-fil?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Verkligen ändra katalog för säkerhetskopiering?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Den valda säkerhetskopia destinationen är inte tom." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Den får inte vara tom för att använda kryptering." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Ogiltig fil: Inte en privat SSH-nyckel" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Den valda filen ({path}) är en publik SSH nyckel. Vänligen välj den " "motsvarande privata nyckeln istället (utan \".pub\")." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Filen {path} finns redan. Kan inte skapa en ny SSH nyckel med det namnet." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Misslyckades med att skapa ny SSH-nyckel i {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Inkludera filer och mappar" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "\"{path}\" är en sym-länk. Det länkade målet kommer inte att " "säkerhetskopieras förrns även det är inkluderat." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Inkludera symlänkens mål istället?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Inkludera filer" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Inkludera mappar" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Aktivera aviseringar" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Stäng av säkerhetskopieringar när batteriet används" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Strömstatus inte tillgängligt från system" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Kör enbart en säkerhetskopia i taget" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "De andra säkerhetskopieringarna kommer att blockeras tills den aktuella " "säkerhetskopieringen är klar. Det här är ett globalt alternativ vilket " "betyder att det kommer att drabba alla profiler för den här användaren. Det " "måste hur som helst aktiveras för alla andra användare." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Säkerhetskopiera ersatta filer vid återställning" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Fortsätt vid fel (behåll inte säkerhetskopior som inte är slutförda)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Använd checksummor för att detektera ändringar" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Skapa en ny säkerhetskopia oavsett om det fanns ändringar eller inte." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Varna om det lediga lagringsutrymmet underskrider" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Visa en varning när ledigt utrymme på lagringsenheten för säkerhetskopians " "destination är mindre än det specificerade värdet." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Om borttags- och behållandepolicyn är aktiverad och äldre säkerhetskopior " "blir borttagna baserat på tillgängligt fritt utrymme, kan detta värde inte " "vara lägre än värdet satt i den policyn." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Loggnivå:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Inga" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "användarmanual" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Följande regler bearbetas uppifrån och ner. Senare regler åsidosätter " "tidigare regler. Se {manual_link} för detaljer och exempel." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Öppna användarmanual i webbläsaren." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Behåll den mest senaste säkerhetskopian." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Den mest aktuella säkerhetskopian bevaras under alla omständigheter." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Det beteendet går inte att ändra på." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Behåll namngivna säkerhetskopior." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Säkerhetskopian som har fått ett namn, utöver den vanliga tidsstämpeln, " "kommer att behållas under alla omständigheter och kommer inte att tas bort." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "År" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Ta bort säkerhetskopior som är äldre än" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Hela dagar. Aktuell dag ignoreras." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "Kalenderveckor med måndag som första dag. Aktuell vecka ignoreras." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Tolvmånaders perioder. Nuvarande månad ignoreras." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Bevarandepolicy" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Kör i bakgrunden på fjärrvärden." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Bevaringspolicyn kommer att köras direkt på fjärrdatorn, inte lokalt. " "Kommandona \"bash\", \"screen\" och \"flock\" måste vara installerade och " "tillgängliga på fjärrdatorn." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Om det väljs kommer Back In Time först att testa fjärrmaskinen." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Dagarna räknas från och med idag." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Behåll alla säkerhetskopior för de senaste" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "dag(ar)." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Behåll den sista säkerhetskopian för varje dag till den sista" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Veckorna räknas från och med den aktuella löpveckan. En vecka börjar på " "måndag." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Behåll den sista säkerhetskopian för varje vecka till den sista" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "vecka/veckor." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Månaderna räknas som kalendermånader från och med nuvarande månad." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Behåll den sista säkerhetskopian för varje månad till den sista" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "månad(er)." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Åren räknas som kalenderår från och med det nuvarande året." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Spara den sista säkerhetskopior för varje år för" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "alla år." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… det lediga utrymmet är mindre än" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… de lediga inoderna är mindre än" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Ta bort gamla säkerhetskopior om …" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Autentisering krävs för att köra Back In Time som root." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Autentisering krävs för att ändra på schemalagda säkerhetskopieringar som " "triggas av att externa lagringsenheter ansluts." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Genvägar" #: qt/placeswidget.py:63 msgid "Places" msgstr "Platser" #: qt/placeswidget.py:64 msgid "File System" msgstr "Filsystem" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Mappar för säkerhetskopior" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Profil: \"{profile_name}\"" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Profil: \"{profile_name}\" (av användare \"{desktop_user}\")" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Visa senaste logg" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Starta {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Arbetar…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "manualsida: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Importera konfiguration" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Ingen katalog har valts" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Importera" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Söker…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Välj mappen för säkerhetskopian som konfigurationsfilen ska importeras " "ifrån. Genvägen kan se ut så här: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Om katalogen finns på en extern eller fjärrenhet måste den monteras manuellt" " i förväg." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Skanna igen" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Visa dolda mappar" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Visa/göm dolda mappar (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Ingen config hittades i den här katalogen" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Sökning slutförd." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Visa fullständig logg" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Nedräkning till avstängning" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Säkerhetskopieringen har slutförts." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Avbryt avstängning" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Stäng av nu" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Systemet kommer att stängas av om {n} sekund." msgstr[1] "Systemet kommer att stängas av om {n} sekunder." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Alternativ för att jämföra säkerhetskopior" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Kommando:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Parametrar:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Använd %1 och %2 för sökvägsparametrar" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Vänligen ställ in ett diff-kommando eller tryck på Avbryt." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Kommandot \"{cmd}\" kan inte hittas i ditt system. Vänligen prova något " "annat eller tryck på Avbryt." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Inga parametrar är inställda för diff-kommandot. Använder standardvärdet " "\"{params}\"." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Säkerhetskopior" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Endast avvikande säkerhetskopior" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Lista enbart säkerhetskopior som är lika med:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Djupkontroll (mer noggrann, men långsam)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Ta bort" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Välj alla" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Jämför" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Gå till" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Alternativ" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Det är inte möjligt att jämföra en säkerhetskopia med sig själv eftersom att" " jämförelsen skulle vara överflödig." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Verkligen ta bort {file_or_dir} i säkerhetskopian {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Vill du verkligen ta bort {file_or_dir} i {count} säkerhetskopior?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "VARNING: Det här kan inte ångras." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Exkludera {path} från framtida säkerhetskopior?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Root-läge" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "" "Back In Time körs för närvarande med root behörigheter (full åtkomst till " "systemet)" #: qt/timeline.py:69 msgid "Today" msgstr "Idag" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Igår" #: qt/timeline.py:87 msgid "This week" msgstr "Denna vecka" #: qt/timeline.py:95 msgid "Last week" msgstr "Förra veckan" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "" "Det här är INTE en säkerhetskopia utan en direktvisning av de lokala " "filerna." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Senaste kontroll {time}" backintime-1.6.1/common/po/tr.po000066400000000000000000002341001514264426600165320ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Onur Esat Karabacak # SPDX-FileCopyrightText: © Taner Orak # SPDX-FileCopyrightText: © Nuri Küçükler # SPDX-FileCopyrightText: © Baris Ozyurt # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-02-02 07:08+0000\n" "Last-Translator: barisozyurt \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "Bu projedeki bütün lisanslar {dir_link} dizininde konumlandırılmıştır. SPDX " "metaverisini kullanarak dosya bazında lisans ve telif bilgisini çözümlemek " "için şu linke başvurun: {readme_link}." #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Uyarı" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Ana profil" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Yerel (EncFS şifreli)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (EncFS şifreli)" #: common/config.py:237 msgid "Local" msgstr "Yerel" #: common/config.py:240 msgid "Local encrypted" msgstr "Yerel olarak şifrelenmiş" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Şifreleme" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH özel anahtar" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Profil: \"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "Yedek dizini geçersiz." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Yedek için en az bir klasör seçilmelidir." #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "{path} dizini" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "" "Bu dizin yedek dizininin bir parçası olduğundan yedeğe dahil edilemez." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" "\"Boş alan daha azsa en eski yedeklemeyi kaldır\" ({val_one}) değeri, \"Boş " "disk alanı altına düşerse uyar\" ({val_two}) eşiğinden küçük veya eşit " "olmalıdır." #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" "Lütfen yedekleme kaldırma sınırının uyarı sınırından yüksek olmaması için " "ayarları düzenleyin." #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Udev zamanlama kipi {mode} ile çalışmıyor" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Yeni crontab yazımı başarısız oldu." #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Crontab komutu mevcut olmasına rağmen Cron çalışmıyor. Planlanan yedekleme " "işleri çalışmayacak. Cron yüklü, ancak etkinleştirilmemiş olabilir. " "\"systemctl enable cron\" ve \"systemctl start cron\" komutlarını deneyin " "veya GNU Linux dağıtımınızın destek kanallarına başvurun." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Yapılandırma kaydedilemedi" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Yapılandırma yüklenemedi" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "\"{name}\" profili zaten var." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Son profil kaldırılamaz." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "'{command}' bağlanamıyor" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "Şifrelenmiş dizin için yapılandırma bulunamadı." #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "Yeni bir şifreli dizin oluşturulsun mu?" #: common/encfstools.py:204 msgid "Cancel" msgstr "İptal" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "Lütfen onaylamak için EncFS şifresini tekrar girin." #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS parolaları eşleşmiyor." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Yedek al" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "\"{command}\" şifrelenmiş yolunu başlatamadı" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "{mountprocess} , {mountpoint} den ayrılamıyor." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "{command} bulunamadı. Lütfen (örneğin {installcommand} komutunu kullanarak) " "yükleyin" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Bağlantı noktası {mntpoint} boş değil." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Şifrenizi {mode} \"{profile}\" profili için giriniz :" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "{profile_id} profili için Udev kuralı yüklenemedi. '{dbus_interface}' DBus " "Hizmeti kullanılabilir değildi." #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "{path} için UUID bulunamadı" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "BAŞARISIZ" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "İzinleri geri yükle" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Tamamlandı" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" "Ekleme listesindeki aşağıdaki kayıtların yedekleme kaynağında karşılık gelen" " bir dosyası veya dizini yoktur:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Pille çalışırken yedeklemeyi erteleme" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "Yedekleme klasörü bulunamadı." #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "Eğer bu bir çıkarılabilir sürücüde ise, lütfen sisteme takın." #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "{n} saniye bekleniyor." msgstr[1] "{n} saniye bekleniyor." #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "{snapshot_id} yedeği alınamadı." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "Lütfen sabırlı olun. Tamamlanıyor…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Dizin oluşturulamıyor." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Yapılandırma dosyası kaydediliyor…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "İzinler kaydediliyor…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "Devam edilebilecek tamamlanmamış {snapshot_id} yedeği bulundu." #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "" "Son çalıştırmadan kalan tamamlanmamış {snapshot_id} dizini kaldırılıyor" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "Dizin silinemiyor" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "Yedek oluşturuluyor" #: common/snapshots.py:1517 msgid "Success" msgstr "Başarılı" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Hata sebebiyle kısmen aktarıldı" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "Kaybolan kaynak dosyalar nedeniyle kısmi aktarım (bkz. 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' sonlandı, çıkış kodu: {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Daha fazla ayrıntı için bakınız; 'man rsync'" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "" "Negatif rsync çıkış kodları sinyal numaralarıdır, bkz. 'kill -l' ve 'man " "kill'" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "Hiçbir değişiklik yok, yeni yedek gerekmiyor" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "{new_path} yolu {path} olarak yeniden adlandırılamıyor." #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "Eski yedekleri kaldırmak için kurallar uygulanıyor" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "Saklama politikası kuralları uygulanıyor" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "En az boş alan korunmaya çalışılıyor" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "En az {perc} boş düğümü korumaya çalışıyor" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Şimdi" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "{sshfs} bağlanamadı" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "ssh-agent bulunamadı. Lütfen kurulu olduğundan emin olun." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Ssh özel anahtarının kilidi açılamadı. Parola yanlış ya da Cron için parola " "yok." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Uzak yol mevcut ancak bir dizin değil." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Uzak yol yazılabilir değil." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Uzak yol çalıştırılabilir değil." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Uzak yol oluşturulamadı." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Uzak bilgisayar {host} {command} komutunu desteklemiyor" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "" "{host} bilgisayarındaki komutlar kontrol edildiğinde bilinmeyen bir hata " "döndü" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Uzak sunucu {host} sabit bağlantıları desteklemiyor" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "" "\"{pubkey}\" genel SSH anahtarını uzak ana bilgisayar \"{host}\" üzerine " "kopyala." #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "\"{user}\" kullanıcısı için parola giriniz." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "{path} için girilen hedef dosya sistemi, Unix tipi dosya sistemleriyle " "uyumsuz NTFS ile biçimlendirilmiş." #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} geçerli bir dizin değil." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "Aşağıdaki dizin oluşturulamadı:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "Yazma erişimi kısıtlanmış olabilir." #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "{path} için girilen hedef dosya sistemi hard-link desteklemeyen FAT ile " "biçimlendirilmiş. Lütfen özgün bir Linux dosya sistemi kullanın." #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "{path} için girilen hedef dosya sistemi bir paylaşımlı SMB dizini. Lütfen " "SMB sunucunun sembolik bağları desteklediğini teyit edin ya da " "{expertOptions} bölümündeki {copyLinks} seçeneğini etkinleştirin." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Linkleri kopyala (sembolik bağlantıların referanslarını kaldırır)" #: common/tools.py:487 msgid "Expert Options" msgstr "Uzman Seçenekleri" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "{path} için hedef dosya sistemi sshfs ile bağlanılmış bir paylaşımdır. Sshfs" " sabit bağlantıları desteklemez. Lütfen 'SSH' modunu kullanın." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "Bu dizin içerisinde dosya oluşturulması sırasında hata:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Back In Time Hakkında" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "Telif hakkı:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "Yazarlar:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "Çevirmenler:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "" "Onur Esat Karabacak\n" "Taner Orak\n" "Nuri Küçükler \n" "Baris Ozyurt" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "Yürürlükteki dil için çevirmen belirtimleri mevcut değil." #: qt/aboutdlg.py:116 msgid "this link" msgstr "bu bağlantı" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" "Bütün dillerdeki çevirmen belirtimleri için bu linki takip edin {thislink}." #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "Proje Web Sitesi" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "Kullanım kılavuzu" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" "Kullanım kılavuzunu tarayıcıda açın (mevcutsa yerel, aksi takdirde " "çevrimiçi)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}Versiyon{BOLDEND}: {version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "{app_name} uygulaması, herhangi bir yapılandırma bulunmadığı için ilk kez " "çalıştırılıyor gibi görünüyor." #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "" "Yedekleme konumundan veya başka bir bilgisayardan mevcut bir yapılandırmayı " "içe aktarmak ister misiniz?" #: qt/app.py:395 msgid "Then press OK." msgstr "Daha sonra Tamam’a basın." #: qt/app.py:499 msgid "Create a backup" msgstr "Yedek oluştur" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "" "Dosya değişikliği tespiti için değişiklik zamanı ve boyutunu kullanın." #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "Yedek oluştur (sağlama toplamı kipi)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Dosya değişikliklerini algılamak için sağlama toplamlarını kullan." #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "Yedekleme sürecini duraklat" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "Yedekleme sürecini sürdür" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "Yedekleme sürecini durdur" #: qt/app.py:520 msgid "Refresh backup list" msgstr "Yedekleme listesini yenile" #: qt/app.py:524 msgid "Name backup" msgstr "Yedek isimlendir" #: qt/app.py:528 msgid "Remove backup" msgstr "Yedeği kaldır" #: qt/app.py:532 msgid "Open backup log" msgstr "Yedekleme günlüğünü görüntüle" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "Seçili yedeklemenin günlüğünü görüntüleyin." #: qt/app.py:536 msgid "Open last backup log" msgstr "En son yedekleme günlüğünü görüntüle" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "En son yedekleme günlüğünü görüntüle." #: qt/app.py:540 msgid "Manage profiles…" msgstr "Profilleri yönet…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Kullanıcı Geri Çağrısını Düzenle" #: qt/app.py:548 msgid "Shutdown" msgstr "Kapat" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "Yedekleme tamamlandığında sistemi kapat." #: qt/app.py:552 msgid "Setup language…" msgstr "Kurulum dili…" #: qt/app.py:556 msgid "Exit" msgstr "Çıkış" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "man sayfası: Back In Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "\"Back In Time\" hakkındaki man sayfasını göster" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "man sayfası: Profil yapılandırma dosyası" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" "Profil yapılandırma dosyası (backintime-config) hakkında man sayfasını " "görüntüler" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "\"Back In Time\" web sitesini aç" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Değişiklik Günlüğü" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" "Değişiklik günlüğünü açın (mümkünse yerel olarak, aksi takdirde çevrimiçi)" #: qt/app.py:589 msgid "FAQ" msgstr "SSS" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "Sıkça Sorulan Sorular'ı (SSS) tarayıcıda açın" #: qt/app.py:593 msgid "Ask a question" msgstr "Soru Sor" #: qt/app.py:597 msgid "Report a bug" msgstr "Hata Bildir" #: qt/app.py:600 msgid "Translation" msgstr "Çeviri" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Çeviriye katılım mesajını tekrar gösterir." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Şifreleme Geçişi (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "EncFS kaldırma mesajını tekrar gösterir." #: qt/app.py:615 msgid "About" msgstr "Hakkında" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Geri Yükle" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "Seçili dosyaları veya dizinleri orijinal konumlarına geri yükleyin." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Şuraya geri yükle …" #: qt/app.py:625 msgid "Restore the selected files or directories to a new location." msgstr "Seçili dosyaları veya dizinleri yeni bir konuma geri yükleyin." #: qt/app.py:631 msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Şu anda gösterilen dizini ve tüm içeriğini orijinal konumuna geri yükleyin." #: qt/app.py:637 msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "Şu anda gösterilen klasörü ve tüm içeriğini yeni hedefe geri yükle." #: qt/app.py:640 msgid "Up" msgstr "Yukarı" #: qt/app.py:643 msgid "Show hidden files" msgstr "Gizli dosyaları göster" #: qt/app.py:646 msgid "Compare backups…" msgstr "Yedekleri karşılaştır…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "Sürüm adayı" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "Bu Yayınlama Adayı hakkındaki mesajı tekrar gösterir." #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&Yedekle" #: qt/app.py:733 msgid "&Restore" msgstr "&Geri Yükle" #: qt/app.py:739 msgid "&Help" msgstr "Y&ardım" #: qt/app.py:790 msgid "Systray Icon" msgstr "Sistem Tepsisi Simgesi" #: qt/app.py:796 msgid "Automatic" msgstr "Otomatik" #: qt/app.py:800 msgid "Light icon" msgstr "Açık Renk Simge" #: qt/app.py:801 msgid "Dark icon" msgstr "Koyu Renk Simge" #: qt/app.py:824 msgid "Icons only" msgstr "Sadece simgeler" #: qt/app.py:827 msgid "Text only" msgstr "Sadece Metin" #: qt/app.py:830 msgid "Text below icons" msgstr "Metin ikonların altında" #: qt/app.py:833 msgid "Text beside icon" msgstr "Metin ikonların yanında" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Bu klasör,\n" "seçili yedekte yok." #: qt/app.py:1005 msgid "Add to Include" msgstr "Dahil Et'e Ekle" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Dışla'ya Ekle" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Eğer bu pencereyi kapatırsanız, Back In Time yedekleme işlemi " "tamamlandığında sisteminizi kapatamayacak." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "Yine de pencere kapansın mı?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Tamamlandı, yedekleme gerekmiyor" #: qt/app.py:1285 msgid "Working:" msgstr "Çalışıyor:" #: qt/app.py:1292 msgid "Working" msgstr "Çalışıyor" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Hata" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Gönderilen:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Hız:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "Tahmini Varış Süresi:" #: qt/app.py:1490 msgid "Backup:" msgstr "Yedek:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "{path} geri yükle" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "{path} geri yükle, hedef …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Merhaba\n" "Back In Time'ı an itibarıyla {language} dilinde bir süredir kullanmaktasınız.\n" "Yüklediğiniz Back In Time sürümünün {language} çevirisi henüz {perc} tamamlandı. Teknik uzmanlık seviyeniz ne olursa olsun çeviriye yardımcı olarak Back In Time'a katkıda bulunabilirsiniz.\n" "Çeviriye katkıda bulunmak için {translation_platform_url} adresini ziyaret edebilirsiniz. Daha çok yardım ve soru için {back_in_time_project_website} adresini ziyaret edebilirsiniz.\n" "Böldüğümüz için özür dileriz. Bu mesaj tekrar gösterilmeyecektir. Bu mesajı istediğiniz zaman yardım menüsünden görüntüleyebilirsiniz.\n" "Back In Time Ekibi" #: qt/app.py:1709 msgid "translation platform" msgstr "çeviri platformu" #: qt/app.py:1714 msgid "Website" msgstr "Web Sitesi" #: qt/app.py:1728 msgid "Your translation" msgstr "Sizin çeviriniz" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "Mastodon'daki Fediverse: {link_and_label}." #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "{link_and_label} adresine e-posta gönderin." #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "E-posta listesi {link_and_label}." #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "Proje web sitesinde {link_and_label}." #: qt/app.py:1781 msgid "Open an issue" msgstr "hata bildir" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "Alternatif olarak istediğiniz iletişim yolunu kullanabilirsiniz." #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "Back In Time'ın bu sürümü bir Sürüm Adayıdır ve öncelikli olarak bir sonraki resmi sürüme hazırlık olarak kararlılık testi için tasarlanmıştır..\n" "Hiçbir kullanıcı verisi veya telemetri toplanmaz. Ancak, Back In Time ekibi Sürüm Adayı'nın kullanılıp kullanılmadığını ve bu tür ön sürüm sürümlerini sağlamaya devam etmenin değerli olup olmadığını bilmekle çok ilgilenmektedir.\n" "Bu nedenle, ekip herhangi bir sorunla karşılaşmamış olsanız bile bu sürümü test edip etmediğinize dair kısa bir geri bildirim rica etmektedir. Birkaç dakikalık kısa bir test çalışması bile bize çok yardımcı olacaktır..\n" "Aşağıdaki iletişim seçenekleri mevcuttur:\n" "{contact_list}\n" "Bu sürümde, bu mesaj tekrar gösterilmeyecek ancak yardım menüsünden istediğiniz zaman erişilebilir.\n" "Desteğiniz ve Back In Time'ı geliştirmemize yardımcı olduğunuz için teşekkür ederiz!!\n" "\"Back In Time\" ekibi" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" "Hedefte yalnızca {free} boş alan mevcut ve bu alan tanımlanmış {threshold} " "sınırının altında." #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "Yedeklemeye devam edilsin mi?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "{path} yolundaki bütün yeni dosyalar kaldırılacak. Devam edilsin mi?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "Asıl dizindeki bütün yeni dosyalar kaldırılacak. Devam edilsin mi?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "{BOLD}UYARI{BOLDEND}: Dosyaları dosya sistemi kökünden silmek, sisteminizin " "tamamını bozabilir." #: qt/app.py:2167 msgid "Backup name" msgstr "Yedek adı" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "Bu yedek kaldırılsın mı?" msgstr[1] "Bu yedekler kaldırılsın mı?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Dil ayarları yalnızca Back In Time yeniden başlatıldıktan sonra etkili olur." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "Sürümlü Yedeklemeler (root)" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" "Disk kullanımını azaltan, sürümlü yedeklemeler için kullanıcı dostu grafik " "arayüzü (root modu)" #: qt/backintime-qt.desktop:14 msgid "Versioned Backups" msgstr "Sürümlü Yedeklemeler" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" "Disk kullanımını azaltan, sürümlü yedeklemeler için kullanıcı dostu grafik " "arayüzü" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Soru" #: qt/confirmrestoredialog.py:76 #, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Yerel öğelerin üzerine yazmadan veya kaldırmadan önce sonuna {suffix} " "ekleyerek yedek kopyalar oluşturun." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Daha yeni dosya sürümleri, geri yüklenmeden önce sonuna {suffix} eklenerek " "yeniden adlandırılacaktır. Artık onlara ihtiyacınız yoksa, aşağıdaki komutla" " silebilirsiniz:" #: qt/confirmrestoredialog.py:94 #, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Yalnızca var olmayan veya hedeftekilerden daha yeni olan öğeleri geri " "yükleyin. \"{rsync_example}\" seçeneğini kullanın." #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "Özgün klasördeki daha yeni ögeleri kaldır." #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Seçilen dosyaları veya klasörleri orijinal hedefe geri yükleyin ve yedekte " "bulunmayan dosya veya klasörleri silin. Çok dikkatli olun çünkü bu işlem, " "yedek alınırken hariç tutulan dosya ve klasörleri silecektir." #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Bu öğeyi gerçekten {path} yeni klasörüne geri yüklemek istiyor musunuz?" msgstr[1] "" "Bu öğeleri gerçekten {path} yeni klasörüne geri yüklemek istiyor musunuz?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Bu öğeyi gerçekten geri yüklemek istiyor musunuz?" msgstr[1] "Bu öğeleri gerçekten geri yüklemek istiyor musunuz?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "Kullanıcı geri araması: \"{filename}\"" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" "Kullanıcı geri çağırma betiğinin ilk satırında bir shebang bulunmalıdır " "(örn. {example})." #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Gizli dosyaları ve dizinleri göster/gizle (Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Kurulum dili" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Çevrilen: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Sistem öntanımlısı" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "İşletim sistemi dilini kullanın." #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "Yedekleme Günlük Görünümü" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Son Günlük Görünüm" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Profil:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "Yedekler:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "Filtrele:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Hata, [I] Bilgi, [C] Değiştir" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "kod çözümleme yolları" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Tümü" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Değişiklikler" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Hatalar" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "Bilgi" msgstr[1] "Bilgiler" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync aktarımı başarısızlıkları (deneysel)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Profilleri yönet" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Düzenle" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Ekle" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Kaldır" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Genel" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Dahil Et" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "Dışl&a" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "&Kaldırma & Saklama" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "&Seçenekler" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "&Uzman Seçenekleri" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Yapılandırma Geri Yükle" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Yeni profil" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Profili yeniden adlandır" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "\"{name}\" profili silinsin mi?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "Sembolik bağlantıları dosya gibi kopyala" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" "Yedekleekensembolik bağlantıları gerçek dosya veya dizin olarak kopyala. Tüm" " bağlantıların mı yoksa yalnızca kaynak dizinin dışına işaret eden " "bağlantıların mı kopyalanacağını seçiniz." #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "Bu seçenek yedekleme boyutunu artırabilir." #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "Varsayılan olarak devre dışı." #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" "Tüm sembolik bağlantılar, işaret ettikleri gerçek dosyalar veya dizinlerle " "değiştirilir. Bu işlem yedekleme boyutunu artırır ve aynı dosyaların birden " "fazla kez saklanmasına neden olabilir." #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "'rsync --copy-links' komutu kullanılır." #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "Sadece harici" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" "Yalnızca yedekleme kaynağının dışına işaret eden bağlantılar dosya olarak " "kopyalanır. Bu, yedekleme boyutunu artırır ve aynı dosyaların birden fazla " "kez saklanmasına neden olabilir." #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "'rsync --copy-unsafe-links' komutu kullanılır." #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "Editör ve geçici Ofis dosyaları" #: qt/manageprofiles/excludesuggestions.py:34 msgid "Emacs backup files" msgstr "Emacs yedekleme dosyaları" #: qt/manageprofiles/excludesuggestions.py:35 msgid "Emacs autosave files" msgstr "Emacs otomatik kaydetme dosyaları" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "Vim takas dosyaları" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "Microsoft Office geçici dosyaları" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "LibreOffice ve diğer OpenDocument düzenleyicileri dosyaları kilitler" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "Küçük Resimler ve Geçici Fotoğraflar" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" "GNU/Linux ve diğer Unix benzeri işletim sistemlerinde küçük resim önbelleği" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "Windows'ta küçük resim veritabanı" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "MacOS'ta meta veri dizini" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "Uygulamaya özel kilitler" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "Discord uygulama kilidi dosyası" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "Discord oturum kilitleme dosyası" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "Discord kayıt kilitleme dosyası" #: qt/manageprofiles/excludesuggestions.py:62 msgid "Caches & Temporary directories" msgstr "Önbellekler ve Geçici dizinler" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "Kullanıcı uygulama önbelleği" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 msgid "System temporary directory" msgstr "Sistem geçici dizini" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" "Debian (veya Debian tabanlı) GNU/Linux dağıtımları için paket önbelleği" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "Flatpak uygulaması ve çalışma zamanı deposu" #: qt/manageprofiles/excludesuggestions.py:81 msgid "System runtime directories" msgstr "Sistem çalışma zamanı dizinleri" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "Çekirdek ve işlem bilgileri" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "Aygıt ve diğer donanım bilgileri (sysfs arayüzü)" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "Aygıt düğümleri" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "Çalışma zamanı sistem dosyaları" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "Diğer kalıcı olmayanlar" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "Şu anda bağlı olan dosya sistemlerinin listesi" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "Sistem takas dosyası (sanal bellek)" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "GNOME sanal dosya sistemi bağlama noktası" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "Kurtarılan dosya sistemi nesneleri" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "Çeşitli" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "Microsoft Windows'da meta veri dizini" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "Kullanıcı geri dönüşüm kutusu" #: qt/manageprofiles/excludesuggestions.py:112 msgid "System backup files" msgstr "Sistem yedekleme dosyaları" #: qt/manageprofiles/excludesuggestions.py:139 msgid "Exclude Suggestions" msgstr "Önerileri Hariç Tut" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" "Yedekleme hariç tutma listesine eklemek için sık kullanılan öğeleri seçin." #: qt/manageprofiles/excludesuggestions.py:157 msgid "Default" msgstr "Varsayılan" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "Öntanımlı seçime sıfırla" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Zamanlama" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "Gün:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "Haftanın günü:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "Zaman:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "Saatler:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "bir saat sonra" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "Dakika:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Sürücü bağlanır bağlanmaz Back In Time'ı çalıştır (yalnızca X günde bir). " "Sizden sudo parolası istenecektir." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Back In Time'ı tekrarlayarak çalıştır. Bu, bilgisayar düzenli olarak " "çalışmıyorsa kullanışlıdır." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Her:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "Hata ayıklama mesajlarının kaydetmeyi etkinleştir" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" "Sorun giderme düzeyindeki iletileri '--debug' seçeneğiyle sistem günlüğüne " "yazar." #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" "Dikkat: Yüksek miktarda çıktı yaratacağından sadece geçici bir süreliğine " "tanılama yapmak için kullanın." #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Devre dışı" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Her Başlatıldığında/Yeniden Başlatıldığında" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Dakikada bir" msgstr[1] "Her {n} dakikada bir" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Her Saat" msgstr[1] "Her {n} saatte" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Özel saatler" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Her gün" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Tekrar tekrar (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Sürücü bağlandığında (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Her hafta" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Her ay" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Her yıl" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Saat" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Gün" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Hafta" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Ay" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Özel saatler yalnızca virgülle ayrılmış saat listesi (ör. 8,12,18, 23) ya da" " her 3 saatte bir düzenli yedekleme için */3 olabilir." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "<Вибрати інший файл…>" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "Вибрати існуючий файл приватного ключа з іншого місця." #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "<Створити нову пару ключів…>" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "Створити новий ключ SSH без парольної фрази." #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "Повний шлях: {path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "Приватний ключ:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "Використовувати системну конфігурацію SSH" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "" "Залишає файл ключа невибраним. Підключення по SSH залежатимуть від " "конфігурації клієнта системи (напр., ~/.ssh/config)." #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "Проксі-сервер SSH" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "Сервер:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "Порт:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "Користувач:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "Підключайтеся до цільового сервера через цей проксі (також відомий як " "проміжний сервер або jump host). Докладніше див. розділ «-J» у документації " "до команди «ssh» або розділ «ProxyJump» у посібнику «ssh_config»." #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}Підказка{ENDBOLD}: в режимі «SSH зашифрований» можна використовувати " "лише одну або дві зірочки (напр., {example2}). Інші символи підстановки і " "шаблони ігноруються (напр., {example1}). Імена файлів у цьому режимі " "непередбачувані через шифрування EncFS." #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "Виключити шаблони, файли або каталоги" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "Додати шаблон" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "Додати файли" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "Додати каталоги" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "Пропозиції" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "Додайте до списку виключень часто використовувані елементи." #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "Виключити файли більші, ніж:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "Виключити файли більші, ніж значення в {size_unit}." #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "Якщо «Full rsync mode» вимкнено, цей параметр вплине лише на новостворені " "файли, оскільки для rsync це опція перенесення, а не правило виключення. " "Тому великі файли, зарезервовані раніше, залишаться в резервних копіях, " "навіть якщо ці файли буде змінено." #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "Виключити за шаблоном" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "Уведіть шаблон виключення:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "Довідку див. у розділі {link} посібника rsync." #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "Відкриває посібник rsync" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "Виключити файли" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "Виключити каталоги" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "Вимкнено, оскільки цей шаблон не працює у режимі «SSH зашифрований»." #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "" "Це параметри для просунутого налаштування. Змінюйте їх, тільки якщо повністю" " усвідомлюєте їхню дію." #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "Запустити «rsync» з «{cmd}»:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "як cron job" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "на віддаленому сервері" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "під час резервування вручну" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "Встановіть «nocache», щоб увімкнути цей параметр." #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "на локальному комп’ютері" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "Перенаправити stdout на /dev/null в cronjobs." #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "" "Якщо встановлено MTA, Cron автоматично надішле електронного листа з " "прикріпленим виводом cronjobs." #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "Перенаправити stderr на /dev/null в cronjobs." #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "" "Якщо встановлено MTA, Cron автоматично надішле електронного листа з " "прикріпленими помилками cronjobs." #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "кбіт/с" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "Обмежити пропускну здатність:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "Зберігати ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "Зберігати додаткові атрибути (xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "Обмежити однією файловою системою" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "Параметри необхідно брати в лапки, напр. {example}." #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "Додаткові параметри для rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "Префікс для виконання перед кожною командою на віддаленому сервері." #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "Екрануйте змінні за допомогою \\$FOO. Це не стосується rsync. Щоб додати " "префікс для rsync, використовуйте «{example_value}» з {rsync_options_value}." #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "за замовчуванням" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "Додати префікс до команд SSH" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "Перевіряти, чи сервер онлайн" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "" "Увага: якщо вимкнено, а сервер недоступний, це може призвести до " "непередбачуваних помилок." #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "Перевіряти, чи підтримує сервер усі необхідні команди." #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "" "Увага: якщо вимкнено, а сервер не підтримує всіх необхідних команд, це може " "призвести до непередбачуваних помилок." #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(за замовчуванням: {})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "вимкнено" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "увімкнено" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "Режим:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "Де зберігати резервні копії" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "Налаштування SSH" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "Шлях:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "Файл ключа:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "Пароль" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "Зберегти пароль у зв’язці ключів" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "Кешувати пароль для Cron (Увага: root може читати пароль)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "Додатково" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "Повний шлях до копії:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "" "Планування вимкнено, оскільки не знайдено інсталяції cron. Встановіть cron, " "щоб увімкнути резервне копіювання за розкладом." #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "Шлях до місця призначення резервної копії не може бути порожнім." #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "Пароль шифрування не може бути порожнім." #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "" "Помилка під час спроби входу на віддалений сервер. Повідомлення про помилку:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "" "Щоб увімкнути безпарольний доступ, можна скопіювати публічний ключ SSH на " "віддалений сервер." #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "Продовжити копіювання ключа SSH?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "" "Не вдалося скопіювати публічний ключ SSH. Причиною може бути проблема з " "підключенням або правами доступу." #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "Автентичність сервера {host} не вдалося встановити." #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "Відбиток ключа {keytype}:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "Перевірте цей відбиток. Додати його до файлу «known_hosts»?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "Справді змінити каталог для резервних копій?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "Вибране місце призначення резервної копії не порожнє." #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "Щоб використовувати шифрування, воно повинно бути порожнім." #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "Недійсний файл: не приватний ключ SSH" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "" "Вибраний файл ({path}) є публічним ключем SSH. Будь ласка, виберіть " "відповідний файл приватного ключа (без «.pub»)." #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "" "Файл {path} вже існує. Неможливо створити новий ключ SSH з такою назвою." #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "Не вдалося створити новий ключ SSH у {path}." #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "Включити файли і каталоги" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "" "«{path}» — символьне посилання. Об’єкт, на який воно вказує, не буде " "зарезервовано, якщо його не включити." #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "Включити в резервну копію цільовий об’єкт символьного посилання?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "Включити файли" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "Включити каталоги" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "Увімкнути сповіщення" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "Вимкнути резервування при роботі від батареї" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "Статус живлення недоступний" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "Створювати лише одну резервну копію за раз" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "" "Інші резервні копії буде заблоковано, доки триває поточне резервування. Це " "глобальне налаштування, тобто воно вплине на всі профілі цього користувача. " "Однак для інших користувачів його потрібно вмикати окремо." #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "Під час відновлення зберігати копії переміщених файлів" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "Ігнорувати помилки (зберігати незавершені копії)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "Виявляти зміни за контрольними сумами" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "Резервувати незалежно від того, чи були зміни." #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "Попереджати, якщо вільного місця менше, ніж" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "" "Попереджає, коли вільного місця на диску призначення резервної копії менше " "за вказане значення." #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "" "Якщо ввімкнено політику Видалення і збереження і старі резервні копії " "видаляються на основі наявного вільного місця, це значення не може бути " "меншим за встановлене в політиці." #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "Рівень журналу:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "Нічого" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "iнструкції користувача" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "" "Наведені нижче правила обробляються зверху вниз. Пізніші правила мають " "перевагу над попередніми. Подробиці та приклади див. в {manual_link}." #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "Відкрити посібник користувача в браузері." #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "Не видаляти найновішу резервну копію." #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "Найновіша резервна копія зберігається за будь-яких обставин." #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "Цю поведінку неможливо змінити." #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "Не видаляти названі резервні копії." #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "" "Резервні копії, яким, окрім звичайної позначки часу, було присвоєно ім’я, " "будуть збережені за будь-яких обставин і не видалятимуться." #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "років" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "Видаляти копії, старіші за" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "Повні дні. Поточний день не враховується." #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "" "Календарні тижні, що починаються з понеділка. Поточний тиждень не " "враховується." #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "Періоди по 12 місяців. Поточний місяць не враховується." #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "Політика збереження" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "Виконувати у фоні на сервері." #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "" "Політика збереження виконуватиметься безпосередньо на віддаленому " "комп’ютері, а не локально. На віддаленому комп’ютері мають бути встановлені " "і доступні команди «bash», «screen» і «flock»." #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "Якщо вибрано, Back In Time спочатку протестує віддалений комп’ютер." #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "Відлік днів ведеться від сьогоднішнього дня." #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "Зберігати всі копії за останні" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "днів." #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "Зберігати останню копію за кожен день за останні" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "" "Відлік тижнів, починаючи з поточного. Тиждень починається з понеділка." #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "Зберігати останню копію за кожен тиждень за останні" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "тижнів." #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "Відлік календарних місяців, починаючи з поточного місяця." #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "Зберігати останню копію за кожен місяць за останні" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "місяців." #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "Відлік календарних років, починаючи з поточного року." #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "Зберігати останню копію за кожен рік за" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "всі роки." #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… вільного місця менше, ніж" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… вільних айнодів менше, ніж" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "Видаляти найстарішу копію, якщо…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "Для запуску Back In Time від імені root необхідна автентифікація." #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "" "Для зміни розкладів резервного копіювання, що запускаються підключенням " "зовнішнього сховища, потрібна автентифікація." #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "Скорочення" #: qt/placeswidget.py:63 msgid "Places" msgstr "Місця" #: qt/placeswidget.py:64 msgid "File System" msgstr "Файлова система" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "Каталоги резервних копій" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "Профіль: {profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "Профіль: {profile_name} (користувача «{desktop_user}»)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "Переглянути останній журнал" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "Запуск {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "Виконання…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "man page: {man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "Імпортувати конфігурацію" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "Не вибрано каталог" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "Імпорт" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "Пошук…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "" "Виберіть каталог резервних копій, з якого слід імпортувати файл " "конфігурації. Шлях може мати такий вигляд: {samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "" "Якщо це каталог на зовнішньому або віддаленому диску, його потрібно " "попередньо змонтувати вручну." #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "Сканувати ще раз" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "Показати приховані каталоги" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "Показати/сховати приховані каталоги (Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "Не знайдено конфігурації в цьому каталозі" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "Пошук завершено." #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "Показати повний журнал" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "Відлік до вимкнення" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "Резервування завершено." #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "Скасувати вимкнення" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "Вимкнути зараз" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "Система завершить роботу через {n} секунду." msgstr[1] "Система завершить роботу через {n} секунди." msgstr[2] "Система завершить роботу через {n} секунд." #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "Параметри порівняння резервних копій" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "Команда:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "Параметри:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "Використовуйте %1 та %2 як параметри шляху" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "Задайте команду diff або натисніть «Скасувати»." #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "" "Не вдається знайти команду «{cmd}» у цій системі. Будь ласка, спробуйте щось" " інше або натисніть «Скасувати»." #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "" "Для команди diff не задано жодних параметрів. Використовується значення за " "замовчуванням «{params}»." #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "Резервні копії" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "Тільки копії, що відрізняються" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "Показати лише копії, однакові з:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "Глибока перевірка (точніша, але повільна)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "Видалити" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "Вибрати все" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "Порівняти" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "Перейти до" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "Налаштування" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "" "Неможливо порівняти резервну копію саму з собою, таке порівняння було б " "зайвим." #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "Справді видалити {file_or_dir} з резервної копії {backup_id}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "Справді видалити {file_or_dir} з {count} резервних копій?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "УВАГА: це не можна буде скасувати." #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "Виключити {path} з майбутніх резервних копій?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "Режим root" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "Back In Time наразі працює з правами root (повний доступ до системи)" #: qt/timeline.py:69 msgid "Today" msgstr "Сьогодні" #: qt/timeline.py:77 msgid "Yesterday" msgstr "Вчора" #: qt/timeline.py:87 msgid "This week" msgstr "Цього тижня" #: qt/timeline.py:95 msgid "Last week" msgstr "Попереднього тижня" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "Це НЕ резервна копія, а Ваші файли на комп’ютері." #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "Остання перевірка {time}" backintime-1.6.1/common/po/vi.po000066400000000000000000002141051514264426600165260ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Hai Nam # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2025-04-10 10:35+0000\n" "Last-Translator: buhtz \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.10.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "Cảnh báo" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "Hồ sơ chính" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "Cục bộ (được mã hóa bằng EncFS)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH (được mã hóa EncFS)" #: common/config.py:237 msgid "Local" msgstr "Cục bộ" #: common/config.py:240 msgid "Local encrypted" msgstr "Mã hóa cục bộ" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "Mã hóa" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "Khóa SSH riêng" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "Hồ sơ: “{name}”" #: common/config.py:301 #, fuzzy msgid "Backup directory is not valid." msgstr "Thư mục snapshot không hợp lệ." #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "Phải chọn ít nhất một thư mục để sao lưu." #: common/config.py:331 common/config.py:346 #, fuzzy, python-brace-format msgid "Directory: {path}" msgstr "Khôi phục {path}" #: common/config.py:332 common/config.py:347 #, fuzzy msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "Thư mục con sao lưu không thể được thêm vào." #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "" #: common/config.py:1515 #, fuzzy, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "Lịch trình theo udev không hoạt động trong chế độ {mode}" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "Ghi crontab mới thất bại." #: common/config.py:1577 #, fuzzy msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "Cron không hoạt động mặc dù lệnh crontab có sẵn. Các công việc sao lưu đã " "lên lịch sẽ không chạy. Có thể cron đã được cài đặt nhưng chưa được kích " "hoạt. Hãy thử lệnh \"systemctl enable cron\" hoặc tham khảo các kênh hỗ trợ " "của bản phân phối GNU Linux của bạn." #: common/configfile.py:101 msgid "Failed to save config" msgstr "Lưu cấu hình thất bại" #: common/configfile.py:137 msgid "Failed to load config" msgstr "Nạp cấu hình thất bại" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "Hồ sơ \"{name}\" đã tồn tại." #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "Hồ sơ cuối cùng không thể bị xóa bỏ." #: common/encfstools.py:129 common/gocryptfstools.py:84 #, fuzzy, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "Không thể mount '{command}'" #: common/encfstools.py:190 #, fuzzy msgid "Configuration for the encrypted directory not found." msgstr "Không tìm thấy cấu hình cho thư mục đã mã hóa." #: common/encfstools.py:197 #, fuzzy msgid "Create a new encrypted directory?" msgstr "Tạo một thư mục được mã hóa mới?" #: common/encfstools.py:204 msgid "Cancel" msgstr "Hủy" #: common/encfstools.py:209 #, fuzzy msgid "Please re-enter the EncFS password to confirm." msgstr "Vui lòng nhập mật khẩu cho “{user}”." #: common/encfstools.py:215 #, fuzzy msgid "The EncFS passwords do not match." msgstr "Mật khẩu không trùng khớp." #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "Chụp snapshot" #: common/gocryptfstools.py:133 #, fuzzy, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "Không thể mount '{command}'" #: common/mount.py:663 #, fuzzy, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "Không thể unmount {mountprocess} từ {mountpoint}." #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "" "Không tìm thấy {command}. Xin hãy cài đặt (ví dụ: thông qua " "{installcommand})" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "Vị trí mount {mntpoint} không trống." #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "Nhập mật khẩu cho hồ sơ {mode} \"{profile}\":" #: common/schedule.py:238 #, fuzzy, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "" "Không thể cài đặt lệnh Udev cho hồ sơ {profile_id} vì Dịch vụ DBus " "“{dbus_interface}” không khả dụng" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "Không tìm thấy UUID cho {path}" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "THẤT BẠI" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "Khôi phục quyền hạn" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "Xong" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "Trì hoãn sao lưu khi đang sử dụng pin" #: common/snapshots.py:931 qt/app.py:393 #, fuzzy msgid "Can't find backup directory." msgstr "Không tạo được thư mục" #: common/snapshots.py:935 qt/app.py:394 #, fuzzy msgid "If it is on a removable drive, please plug it in." msgstr "" "Không thể tìm thấy thư mục snapshots.\n" "Nếu nó nằm trên ổ cứng có thể tháo rời thì vui lòng cắm vào máy rồi ấn nút OK." #: common/snapshots.py:938 #, fuzzy, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "Đang chờ %s giây." #: common/snapshots.py:1005 #, fuzzy, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "Chụp snapshot {snapshot_id} thất bại." #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "Không tạo được thư mục." #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "Đang lưu tập tin cấu hình…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "Đang lưu quyền hạn…" #: common/snapshots.py:1377 #, fuzzy, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "Tìm thấy {snapshot_id} đang dang dở và có thể tiếp tục." #: common/snapshots.py:1401 #, fuzzy, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "Đang xóa thư mục {snapshot_id} dang dở từ lần chạy trước" #: common/snapshots.py:1412 #, fuzzy msgid "Can't remove directory" msgstr "Không thể xóa thư mục" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "" #: common/snapshots.py:1517 msgid "Success" msgstr "Thành công" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "Truyền một phần do lỗi" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "Truyền một phần do file nguồn biến mất (xem 'man rsync')" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "'rsync' kết thúc với mã kết thúc {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "Xem 'man rsync' để biết nhiều chi tiết hơn" #: common/snapshots.py:1545 #, fuzzy msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "Mã kết thúc rsync âm là số chỉ thị, xem 'kill -l' và 'man kill'" #: common/snapshots.py:1566 #, fuzzy msgid "Nothing changed, no new backup necessary" msgstr "Không có gì thay đổi, không cần snapshot mới" #: common/snapshots.py:1611 #, fuzzy, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "Không thể đổi tên {new_path} thành {path}" #: common/snapshots.py:1998 #, fuzzy msgid "Applying rules to remove old backups" msgstr "Đang xóa các snapshot cũ" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "Đang cố gắng giữ dung lượng trống tối thiểu" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "Đang cố gắng giữ tổi thiểu {perc} inode trống" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "Vừa mới đây" #: common/sshtools.py:233 #, fuzzy, python-brace-format msgid "Unable to mount {sshfs}" msgstr "Không thể mount {sshfs}" #: common/sshtools.py:306 #, fuzzy msgid "ssh-agent not found. Please ensure it is installed." msgstr "Không tìm thấy ssh-agent. Đảm bảo rằng nó đã được cài." #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "" "Không thể mở khóa SSH riêng. Mật khẩu bị sai hay không thể truy cập bởi " "cron." #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "Đường dẫn từ xa tồn tại nhưng không phải là một thư mục." #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "Đường dẫn từ xa không thể được viết vào." #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "Đường dẫn từ xa không thể được thực thi." #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "Không tạo được đường dẫn từ xa." #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "Máy từ xa {host} không hỗ trợ {command}" #: common/sshtools.py:1026 #, fuzzy, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "Lệnh kiểm tra trên máy khách {host} trả về lỗi không xác định" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "Máy ở xa {host} không hỗ trợ harklink" #: common/sshtools.py:1206 #, fuzzy, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "Sao chép khóa ssh công khai \"{pubkey}\" đến máy chủ từ xa \"{host}\"" #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "Vui lòng nhập mật khẩu cho “{user}”." #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "" "Hệ thống tập tin đích cho “{path}” được định dạng bằng chuẩn NTFS, chuẩn này" " không hỗ trợ liên kết cứng. Vui lòng dùng một hệ thống tập tin được Linux " "hỗ trợ." #: common/tools.py:414 #, fuzzy, python-brace-format msgid "{path} is not a valid directory." msgstr "Đường dẫn {path} không phải là một thư mục." #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "" #: common/tools.py:471 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "" "Hệ thống tập tin đích cho “{path}” được định dạng bằng chuẩn FAT, chuẩn này " "không hỗ trợ liên kết cứng. Vui lòng dùng một hệ thống tập tin được Linux hỗ" " trợ." #: common/tools.py:482 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "Hệ thống tập tin đích cho {path} là một phần gắn kết SMB. Vui lòng đảm bảo " "máy chủ SMB từ xa hỗ trợ liên kết tượng trưng hoặc kích hoạt {copyLinks} " "trong {expertOptions}." #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "Sao chép liên kết (truy cập liên kết tượng trưng)" #: common/tools.py:487 msgid "Expert Options" msgstr "Tùy chọn dành cho chuyên gia" #: common/tools.py:491 #, fuzzy, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "" "Hệ thống tập tin đích cho {path} là một phần gắn kết sshfs. Sshfs không hỗ " "trợ liên kết cứng. Vui lòng sử dụng chế độ 'SSH'." #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "" #: qt/aboutdlg.py:93 #, fuzzy msgid "Authors:" msgstr "Tác giả" #: qt/aboutdlg.py:97 #, fuzzy msgid "Translators:" msgstr "Phiên dịch" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Hai Nam" #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "" #: qt/aboutdlg.py:116 msgid "this link" msgstr "" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "" #: qt/app.py:348 #, fuzzy, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "" "Có vẻ như {app_name} đang chạy lần đầu tiên vì không tìm thấy cấu hình nào." #: qt/app.py:353 #, fuzzy msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "Nhập cấu hình hiện có (từ thư mục sao lưu hoặc từ máy tính khác)?" #: qt/app.py:395 msgid "Then press OK." msgstr "" #: qt/app.py:499 msgid "Create a backup" msgstr "" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "Dùng thời gian thay đổi & kích cỡ để dò sự thay đổi của file." #: qt/app.py:504 #, fuzzy msgid "Create a backup (checksum mode)" msgstr "Chụp snapshot với checksum" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "Dùng checksum để phát hiện sự thay đổi của file." #: qt/app.py:508 qt/qtsystrayicon.py:125 #, fuzzy msgid "Pause backup process" msgstr "Tạm dừng quá trình chụp snapshot" #: qt/app.py:512 qt/qtsystrayicon.py:130 #, fuzzy msgid "Resume backup process" msgstr "Tiếp tục quá trình chụp snapshot" #: qt/app.py:516 qt/qtsystrayicon.py:135 #, fuzzy msgid "Stop backup process" msgstr "Dừng hẳn quá trình chụp snapshot" #: qt/app.py:520 #, fuzzy msgid "Refresh backup list" msgstr "Tải lại danh sách snapshot" #: qt/app.py:524 msgid "Name backup" msgstr "" #: qt/app.py:528 #, fuzzy msgid "Remove backup" msgstr "Xóa snapshot" #: qt/app.py:532 #, fuzzy msgid "Open backup log" msgstr "Xem nhật ký cuối cùng" #: qt/app.py:534 #, fuzzy msgid "View log of the selected backup." msgstr "Phải chọn ít nhất một thư mục để sao lưu." #: qt/app.py:536 #, fuzzy msgid "Open last backup log" msgstr "Xem nhật ký cuối cùng" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "" #: qt/app.py:540 msgid "Manage profiles…" msgstr "Quản lý hồ sơ…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "Sửa user-callback" #: qt/app.py:548 msgid "Shutdown" msgstr "Tắt máy" #: qt/app.py:550 #, fuzzy msgid "Shut down system after backup has finished." msgstr "Tắt máy sau khi chụp snapshot hoàn tất." #: qt/app.py:552 msgid "Setup language…" msgstr "Cài đặt ngôn ngữ…" #: qt/app.py:556 msgid "Exit" msgstr "Thoát" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "" #: qt/app.py:571 #, fuzzy msgid "man page: Profiles config file" msgstr "Tập tin cấu hình hồ sơ" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "Nhật ký thay đổi" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "" #: qt/app.py:589 msgid "FAQ" msgstr "Câu hỏi thường gặp" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "" #: qt/app.py:593 msgid "Ask a question" msgstr "Đặt câu hỏi" #: qt/app.py:597 msgid "Report a bug" msgstr "Báo lỗi" #: qt/app.py:600 msgid "Translation" msgstr "Phiên dịch" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "Hiển thị lại thông báo về việc tham gia dịch thuật." #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "Chuyển đổi mã hóa (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "Hiển thị lại thông báo về việc gỡ bỏ EncFS." #: qt/app.py:615 msgid "About" msgstr "Giới thiệu" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "Khôi phục" #: qt/app.py:620 #, fuzzy msgid "Restore the selected files or directories to the original location." msgstr "Khôi phục các tập tin và thư mục được chọn về vị trí ban đầu." #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "Khôi phục đến …" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "Khôi phục các tập tin và thư mục được chọn đến vị trí mới." #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "" "Khôi phục thư mục hiện tại và tất cả nội dung bên trong nó về vị trí ban " "đầu." #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "" "Khôi phục thư mục hiện tại và tất cả nội dung bên trong nó đến vị trí mới." #: qt/app.py:640 msgid "Up" msgstr "Lên" #: qt/app.py:643 msgid "Show hidden files" msgstr "Hiện tập tin ẩn" #: qt/app.py:646 #, fuzzy msgid "Compare backups…" msgstr "Chụp snapshot…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "" #: qt/app.py:679 #, fuzzy msgid "Shows the message about this Release Candidate again." msgstr "Hiển thị lại thông báo về việc gỡ bỏ EncFS." #: qt/app.py:716 msgid "Back In &Time" msgstr "" #: qt/app.py:721 msgid "&Backup" msgstr "&Sao lưu" #: qt/app.py:733 msgid "&Restore" msgstr "&Khôi phục" #: qt/app.py:739 msgid "&Help" msgstr "T&rợ giúp" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "" #: qt/app.py:827 msgid "Text only" msgstr "" #: qt/app.py:830 msgid "Text below icons" msgstr "" #: qt/app.py:833 msgid "Text beside icon" msgstr "" #: qt/app.py:944 #, fuzzy msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "Thư mục này không tồn tại\n" "trong bản snapshot đang được chọn." #: qt/app.py:1005 msgid "Add to Include" msgstr "Thêm vào Bao gồm" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "Thêm vào Loại trừ" #: qt/app.py:1020 #, fuzzy msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "" "Nếu bạn đóng cửa sổ này, Back In Time sẽ không thể tắt máy của bạn khi quá " "trình chụp snapshot hoàn tất." #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "Xong, không cần sao lưu" #: qt/app.py:1285 msgid "Working:" msgstr "Đang chạy:" #: qt/app.py:1292 msgid "Working" msgstr "Đang chạy" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "Lỗi" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "Đã gửi:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "Tốc độ:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "&Sao lưu" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "Khôi phục {path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "Khôi phục {path} đến …" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "Xin chào\n" "Bạn cũng đã sử dụng Back In Time bằng {language} được vài lần rồi.\n" "Bản dịch sang {language} của phiên bản Back In Time mà bạn cài đặt đã {perc} hoàn thành. Dù với bất cứ trình độ hiểu biết công nghệ nào, bạn cũng có thể đóng góp bản dịch và cũng là đóng góp cho chính Back In Time.\n" "Xin hãy ghé thăm {translation_platform_url} nếu bạn muốn đóng góp. Về trợ giúp và giải đáp thắc mặc, xin hãy truy cập {back_in_time_project_website}.\n" "Chúng tôi xin thứ lỗi về sự gián đoạn này, và thông báo này sẽ không xuất hiện nữa. Hộp thoại này lúc nào cũng có thể được tìm thấy trong menu trợ giúp.\n" "Nhóm phát triển Back In Time" #: qt/app.py:1709 msgid "translation platform" msgstr "nền tảng phiên dịch" #: qt/app.py:1714 msgid "Website" msgstr "Trang web" #: qt/app.py:1728 msgid "Your translation" msgstr "Bản dịch của bạn" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "" #: qt/app.py:1770 #, python-brace-format msgid "Email to {link_and_label}." msgstr "" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "" #: qt/app.py:1781 msgid "Open an issue" msgstr "" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "" #: qt/app.py:1931 #, fuzzy, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "" "CẢNH BÁO: Xóa các tập tin trong thư mục root của hệ thống tập tin có thể làm" " hỏng hệ thống của bạn!" #: qt/app.py:2167 #, fuzzy msgid "Backup name" msgstr "&Sao lưu" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "" "Thiết đặt ngôn ngữ chỉ có tác dụng sau khi khởi động lại Back In Time." #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "Đừng xóa các bản snapshot đã được đổi tên." #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "Thắc mắc" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "Tạo thêm bản sao lưu với {suffix} ở cuối tên\n" "trước khi ghi đè hoặc xóa các phần tử cục bộ." #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, fuzzy, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "" "Những phiên bản mới hơn của các tập tin sẽ được đổi tên với {suffix} ở cuối " "tên trước khi khôi phục. Nếu bạn không cần chúng nữa, bạn có thể xóa chúng " "với {command}:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "Chỉ khôi phục những tập tin không tồn tại hoặc\n" "có phiên bản mới hơn so với trong thư mục đích.\n" "Sử dụng lệnh \"rsync --update\"." #: qt/confirmrestoredialog.py:133 #, fuzzy msgid "Remove newer elements in original directory." msgstr "Xóa các tập tin có phiên bản mới hơn trong thư mục gốc." #: qt/confirmrestoredialog.py:135 #, fuzzy msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "" "Khôi phục các tập tin hay thư mục được chọn đến thư mục đích và\n" "xóa các tập tin hay thư mục không có trong snapshot.\n" "Hãy cực kỳ cẩn thận bởi vì việc này sẽ \n" "xóa bỏ các tệp tin và thư mục \n" "đã bị loại trừ trong khi chụp snapshot." #: qt/confirmrestoredialog.py:147 #, fuzzy msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "" "Bạn có thật sự muốn khôi phục các phần tử này vào thư mục mới\n" " {path}?" #: qt/confirmrestoredialog.py:157 #, fuzzy msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "Bạn có thật sự muốn khôi phục các phần tử này?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "" #: qt/filedialog.py:87 #, fuzzy msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "Bao gồm các tập tin và thư mục" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "Thiết đặt ngôn ngữ" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "Đã dịch: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "Mặc định hệ thống" #: qt/languagedialog.py:142 #, fuzzy msgid "Use operating system's language." msgstr "Dùng ngôn ngữ của hệ điều hành." #: qt/logviewdialog.py:63 #, fuzzy msgid "Backup Log View" msgstr "Xem nhật ký được lưu lần cuối cùng" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "Xem nhật ký được lưu lần cuối cùng" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "Hồ sơ:" #: qt/logviewdialog.py:86 #, fuzzy msgid "Backups:" msgstr "&Sao lưu" #: qt/logviewdialog.py:93 #, fuzzy msgid "Filter:" msgstr "Bộ lọc" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] Lỗi, [I] Thông tin, [C] Thay đổi" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "giải mã đường dẫn" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "Tất cả" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "Có thay đổi" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "Có lỗi" #: qt/logviewdialog.py:133 qt/messagebox.py:75 #, fuzzy msgid "Information" msgid_plural "Information" msgstr[0] "Thông tin" #: qt/logviewdialog.py:135 #, fuzzy msgid "rsync transfer failures (experimental)" msgstr "Truyền rsync thất bại (thử nghiệm)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "Quản lý hồ sơ" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "Sửa" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "Thêm" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "Gỡ bỏ" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&Tổng quan" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "&Bao gồm" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&Ngoại trừ" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "Tùy &chọn" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "Tùy chọn chuyên &gia" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "Khôi phục cấu hình" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "Hồ sơ mới" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "Đổi tên hồ sơ" #: qt/manageprofiles/__init__.py:215 #, fuzzy, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "Bạn có chắc chắn muốn xóa hồ sơ \"{name}\" ?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "Tạm dừng quá trình chụp snapshot" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "Loại trừ tập tin" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "Các thư mục sao lưu" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "Không thể xóa thư mục" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "Hiện tập tin ẩn" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "Dừng hẳn quá trình chụp snapshot" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "Loại trừ thư mục" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "mặc định" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "Lịch trình" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "ngày thường:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "giờ:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "" #: qt/manageprofiles/schedulewidget.py:93 #, fuzzy msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "" "Chạy Back In Time ngay khi ổ cứng được kết nối (chỉ một lần mỗi X ngày).\n" "Bạn sẽ bị yêu cầu nhập mật khẩu sudo." #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "" "Chạy Back In Time theo định kỳ. Lựa chọn này hữu ích khi máy tính không được" " mở thường xuyên." #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "Mỗi:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "" #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "" #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "Đang tắt" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "Mỗi lần khởi động máy" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, fuzzy, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "Mỗi {n} phút" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, fuzzy, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "Mỗi giờ" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "Theo giờ tùy chỉnh" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "Hàng ngày" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "Theo định kỳ (anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "Khi ổ cứng kết nối thành công (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "Hàng tuần" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "Hàng tháng" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "Hàng năm" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "Giờ" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "Ngày" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "Tuần" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "Tháng" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "" "Giờ tùy chỉnh phải là các số giờ được ngăn cách bởi dấu phẩy (vd: " "8,12,18,23) hoặc theo định dạng */3 để sao lưu sau mỗi 3 tiếng." #: qt/manageprofiles/sshkeyselector.py:64 msgid "" msgstr "<选择另一个文件...>" #: qt/manageprofiles/sshkeyselector.py:65 msgid "Choose an existing private key file from somewhere else." msgstr "从其他位置选择现有的私钥文件。" #: qt/manageprofiles/sshkeyselector.py:71 msgid "" msgstr "<生成新的密钥对...>" #: qt/manageprofiles/sshkeyselector.py:72 msgid "Create a new SSH key without passphrase." msgstr "创建一个没有密码的新 SSH 密钥。" #: qt/manageprofiles/sshkeyselector.py:92 #, python-brace-format msgid "Full path: {path}" msgstr "完整路径:{path}" #: qt/manageprofiles/sshkeyselector.py:205 msgid "Private key:" msgstr "私钥:" #: qt/manageprofiles/sshkeyselector.py:210 msgid "Use system SSH configuration" msgstr "使用系统 SSH 配置" #: qt/manageprofiles/sshkeyselector.py:212 msgid "" "Leaves the key file unselected. SSH connections will rely on the system’s " "existing client configuration (e.g., ~/.ssh/config)." msgstr "保留密钥文件未选中状态。SSH 连接将依赖于系统现有的客户端配置(例如 ~/.ssh/config)。" #: qt/manageprofiles/sshproxywidget.py:47 msgid "SSH Proxy" msgstr "SSH 代理" #: qt/manageprofiles/sshproxywidget.py:54 qt/manageprofiles/tab_general.py:117 #: qt/manageprofiles/tab_general.py:238 msgid "Host:" msgstr "主机:" #: qt/manageprofiles/sshproxywidget.py:58 qt/manageprofiles/tab_general.py:122 msgid "Port:" msgstr "端口:" #: qt/manageprofiles/sshproxywidget.py:62 qt/manageprofiles/tab_general.py:127 #: qt/manageprofiles/tab_general.py:244 msgid "User:" msgstr "用户:" #: qt/manageprofiles/sshproxywidget.py:71 msgid "" "Connect to the target host via this proxy (also known as a jump host). See " "\"-J\" in the \"ssh\" command documentation or \"ProxyJump\" in " "\"ssh_config\" man page for details." msgstr "" "通过此代理(又称跳转主机)连接到目标主机。详情请参阅“ssh”命令文档中的“-J”或“ssh_config”手册页中的“ProxyJump”。" #: qt/manageprofiles/tab_exclude.py:62 #, python-brace-format msgid "" "{BOLD}Info{ENDBOLD}: In 'SSH encrypted' mode, only single or double " "asterisks are functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are unpredictable in " "this mode due to encryption by EncFS." msgstr "" "{BOLD}信息{ENDBOLD}:在“SSH 加密”模式下,只有单星号或双星号有效(例如 {example2})。其他类型的通配符和模式将被忽略(例如" " {example1})。由于 EncFS 加密,此模式下文件名不可预测。" #: qt/manageprofiles/tab_exclude.py:85 msgid "Exclude patterns, files or directories" msgstr "排除模式、文件或目录" #: qt/manageprofiles/tab_exclude.py:102 msgid "Add pattern" msgstr "添加模式" #: qt/manageprofiles/tab_exclude.py:107 qt/manageprofiles/tab_include.py:68 msgid "Add files" msgstr "添加文件" #: qt/manageprofiles/tab_exclude.py:112 qt/manageprofiles/tab_include.py:73 msgid "Add directories" msgstr "添加目录" #: qt/manageprofiles/tab_exclude.py:118 msgid "Suggestions" msgstr "建议" #: qt/manageprofiles/tab_exclude.py:120 msgid "Select from common used items to add to exclude list." msgstr "从常用项目中选择添加到排除列表中。" #: qt/manageprofiles/tab_exclude.py:134 msgid "Exclude files bigger than:" msgstr "排除大于设定值的文件:" #: qt/manageprofiles/tab_exclude.py:138 #, python-brace-format msgid "Exclude files bigger than value in {size_unit}." msgstr "排除大于设定值的文件,单位 {size_unit}。" #: qt/manageprofiles/tab_exclude.py:140 msgid "" "With 'Full rsync mode' disabled, this setting affects only newly created " "files, as rsync treats it as transfer option rather than an exclusion rule. " "Consequently, large files that have already been backed up will remain in " "backups even if they are modified." msgstr "" "禁用“完全 rsync 模式”后,此设置仅影响新创建的文件,因为 rsync " "将其视为传输选项而非排除规则。因此,已备份的大文件即使被修改,也会保留在备份中。" #: qt/manageprofiles/tab_exclude.py:265 msgid "Exclude pattern" msgstr "排除模式" #: qt/manageprofiles/tab_exclude.py:267 msgid "Enter an exclude pattern:" msgstr "输入排除模式:" #: qt/manageprofiles/tab_exclude.py:272 #, python-brace-format msgid "For help, see the rsync man page section {link}." msgstr "如需帮助,请参阅 rsync 手册页的 {link} 部分。" #: qt/manageprofiles/tab_exclude.py:275 msgid "Open rsync man page" msgstr "打开 rsync 手册页" #: qt/manageprofiles/tab_exclude.py:303 msgid "Exclude files" msgstr "排除文件" #: qt/manageprofiles/tab_exclude.py:316 msgid "Exclude directories" msgstr "排除目录" #: qt/manageprofiles/tab_exclude.py:401 msgid "" "Disabled because this pattern is not functional in mode 'SSH encrypted'." msgstr "已禁用,因为此模式在“SSH 加密”模式下不起作用。" #: qt/manageprofiles/tab_expert_options.py:45 msgid "" "These options are for advanced configurations. Modify only if fully aware of" " their implications." msgstr "这些选项适用于高级配置。只有完全意识到其影响的情况下才修改。" #: qt/manageprofiles/tab_expert_options.py:54 #: qt/manageprofiles/tab_expert_options.py:74 #: qt/manageprofiles/tab_expert_options.py:99 #, python-brace-format msgid "Run 'rsync' with '{cmd}':" msgstr "使用“{cmd}”运行“rsync”:" #: qt/manageprofiles/tab_expert_options.py:61 #: qt/manageprofiles/tab_expert_options.py:80 msgid "as cron job" msgstr "作为 cron 作业" #: qt/manageprofiles/tab_expert_options.py:67 #: qt/manageprofiles/tab_expert_options.py:92 #: qt/manageprofiles/tab_expert_options.py:123 msgid "on remote host" msgstr "在远程主机上" #: qt/manageprofiles/tab_expert_options.py:86 msgid "when taking a manual backup" msgstr "进行手动备份时" #: qt/manageprofiles/tab_expert_options.py:110 msgid "Please install 'nocache' to enable this option." msgstr "请安装“nocache”以启用此选项。" #: qt/manageprofiles/tab_expert_options.py:116 msgid "on local machine" msgstr "在本地机器上" #: qt/manageprofiles/tab_expert_options.py:130 msgid "Redirect stdout to /dev/null in cronjobs." msgstr "在定时任务中将标准输出重定向到 /dev/null。" #: qt/manageprofiles/tab_expert_options.py:136 msgid "" "Cron will automatically send an email with attached output of cronjobs if an" " MTA is installed." msgstr "如果安装了 MTA,Cron 将自动发送一封附有 cronjobs 输出的电子邮件。" #: qt/manageprofiles/tab_expert_options.py:142 msgid "Redirect stderr to /dev/null in cronjobs." msgstr "在定时任务中将标准错误重定向到 /dev/null。" #: qt/manageprofiles/tab_expert_options.py:148 msgid "" "Cron will automatically send an email with attached errors of cronjobs if an" " MTA is installed." msgstr "如果安装了 MTA,Cron 将自动发送一封附有 cronjobs 错误的电子邮件。" #: qt/manageprofiles/tab_expert_options.py:158 msgid "KB/sec" msgstr "KB/秒" #: qt/manageprofiles/tab_expert_options.py:163 msgid "Limit rsync bandwidth usage:" msgstr "限制 rsync 带宽使用:" #: qt/manageprofiles/tab_expert_options.py:204 msgid "Preserve ACL" msgstr "保留 ACL" #: qt/manageprofiles/tab_expert_options.py:222 msgid "Preserve extended attributes (xattr)" msgstr "保留扩展属性(xattr)" #: qt/manageprofiles/tab_expert_options.py:249 msgid "Restrict to one file system" msgstr "限制为一个文件系统" #: qt/manageprofiles/tab_expert_options.py:267 #, python-brace-format msgid "Options must be quoted e.g. {example}." msgstr "选项必须使用引号,例如:{example}。" #: qt/manageprofiles/tab_expert_options.py:276 msgid "Paste additional options to rsync" msgstr "粘贴附加选项到 rsync" #: qt/manageprofiles/tab_expert_options.py:286 msgid "Prefix to run before every command on remote host." msgstr "在远程主机上每个命令之前运行的前缀。" #: qt/manageprofiles/tab_expert_options.py:287 #, python-brace-format msgid "" "Variables need to be escaped with \\$FOO. This doesn't touch rsync. So to " "add a prefix for rsync use \"{example_value}\" with {rsync_options_value}." msgstr "" "变量需要使用 \\$FOO 进行转义。因为这不涉及 rsync,所以要为 rsync " "添加前缀请使用{example_value}和{rsync_options_value}。" #: qt/manageprofiles/tab_expert_options.py:293 msgid "default" msgstr "默认" #: qt/manageprofiles/tab_expert_options.py:298 msgid "Add prefix to SSH commands" msgstr "为 SSH 命令添加前缀" #: qt/manageprofiles/tab_expert_options.py:308 msgid "Check if remote host is online" msgstr "检查远程主机是否在线" #: qt/manageprofiles/tab_expert_options.py:311 msgid "" "Warning: If disabled and the remote host is not available, this could lead " "to some weird errors." msgstr "警告:如果禁用且远程主机不可用,这可能会导致一些奇怪的错误。" #: qt/manageprofiles/tab_expert_options.py:315 msgid "Check if remote host supports all necessary commands." msgstr "检查远程主机是否支持所有必要的命令。" #: qt/manageprofiles/tab_expert_options.py:318 msgid "" "Warning: If disabled and the remote host does not support all necessary " "commands, this could lead to some weird errors." msgstr "警告:如果禁用且远程主机不支持所有必要的命令,这可能会导致一些奇怪的错误。" #: qt/manageprofiles/tab_expert_options.py:332 msgid "(default: {})" msgstr "(默认:{})" #: qt/manageprofiles/tab_expert_options.py:333 msgid "disabled" msgstr "已禁用" #: qt/manageprofiles/tab_expert_options.py:333 msgid "enabled" msgstr "已启用" #: qt/manageprofiles/tab_general.py:67 qt/restoreconfigdialog.py:345 msgid "Mode:" msgstr "模式:" #: qt/manageprofiles/tab_general.py:79 qt/manageprofiles/tab_general.py:394 #: qt/manageprofiles/tab_general.py:686 msgid "Where to save backups" msgstr "保存备份的路径" #: qt/manageprofiles/tab_general.py:105 msgid "SSH Settings" msgstr "SSH 设置" #: qt/manageprofiles/tab_general.py:132 msgid "Path:" msgstr "路径:" #: qt/manageprofiles/tab_general.py:139 msgid "Key file:" msgstr "密钥文件:" #: qt/manageprofiles/tab_general.py:176 qt/manageprofiles/tab_general.py:184 #: qt/manageprofiles/tab_general.py:189 msgid "Password" msgstr "密码" #: qt/manageprofiles/tab_general.py:206 msgid "Save Password to Keyring" msgstr "保存密码至密钥环" #: qt/manageprofiles/tab_general.py:210 msgid "Cache Password for Cron (Security issue: root can read password)" msgstr "Cron 的缓存密码(安全问题:root 可以读取密码)" #: qt/manageprofiles/tab_general.py:226 msgid "Advanced" msgstr "高级" #: qt/manageprofiles/tab_general.py:256 qt/manageprofiles/tab_general.py:803 msgid "Full backup path:" msgstr "完整备份路径:" #: qt/manageprofiles/tab_general.py:264 msgid "" "Scheduling is disabled because no cron installation was found. Please " "install cron to enable scheduled backups." msgstr "由于未找到 cron 安装,因此已禁用计划任务功能。请安装 cron 以启用计划备份。" #: qt/manageprofiles/tab_general.py:393 msgid "The backup destination path cannot be empty." msgstr "备份目标路径不能为空。" #: qt/manageprofiles/tab_general.py:404 msgid "The encryption password cannot be empty." msgstr "加密密码不能为空。" #: qt/manageprofiles/tab_general.py:553 msgid "" "An error occurred while attempting to log in to the remote host. The " "following error message was returned:" msgstr "尝试登录到远程主机时出错。返回以下错误消息:" #: qt/manageprofiles/tab_general.py:557 msgid "" "To enable password-less login, the public SSH key can be copied to the " "remote host." msgstr "要启用免密码登录,可以将 SSH 公钥复制到远程主机。" #: qt/manageprofiles/tab_general.py:560 msgid "Proceed with copying the SSH key?" msgstr "是否继续复制 SSH 密钥?" #: qt/manageprofiles/tab_general.py:585 msgid "" "The public SSH key could not be copied. This may be due to a connection or " "permission issue." msgstr "无法复制 SSH 公钥。这可能是由于连接或权限问题。" #: qt/manageprofiles/tab_general.py:606 #, python-brace-format msgid "The authenticity of host {host} can't be established." msgstr "无法确定主机 {host} 的真实性。" #: qt/manageprofiles/tab_general.py:609 #, python-brace-format msgid "{keytype} key fingerprint is:" msgstr "{keytype} 密钥指纹为:" #: qt/manageprofiles/tab_general.py:613 msgid "Please verify this fingerprint. Add it to the \"known_hosts\" file?" msgstr "请验证此指纹。是否将其添加到“known_hosts”文件中?" #: qt/manageprofiles/tab_general.py:709 msgid "Really change the backup directory?" msgstr "是否确定要更改备份目录?" #: qt/manageprofiles/tab_general.py:725 msgid "The selected backup destination is not empty." msgstr "所选备份目标不为空。" #: qt/manageprofiles/tab_general.py:727 msgid "It must be empty to use encryption." msgstr "使用加密时必须为空。" #: qt/manageprofiles/tab_general.py:756 msgid "Invalid file: Not a private SSH key" msgstr "文件无效:不是 SSH 私钥" #: qt/manageprofiles/tab_general.py:757 #, python-brace-format msgid "" "The selected file ({path}) is a public SSH key. Please choose the " "corresponding private key file instead (without \".pub\")." msgstr "所选文件({path})是 SSH 公钥。请选择相应的私钥文件(不含“.pub”扩展名)。" #: qt/manageprofiles/tab_general.py:781 #, python-brace-format msgid "" "The file {path} already exists. Cannot create a new SSH key with that name." msgstr "文件 {path} 已存在。无法使用该名称创建新的 SSH 密钥。" #: qt/manageprofiles/tab_general.py:791 #, python-brace-format msgid "Failed to create new SSH key in {path}." msgstr "无法在 {path} 创建新 SSH 密钥。" #: qt/manageprofiles/tab_include.py:48 msgid "Include files and directories" msgstr "包括文件和目录" #: qt/manageprofiles/tab_include.py:168 #, python-brace-format msgid "" "\"{path}\" is a symlink. The linked target will not be backed up until it is" " included, too." msgstr "“{path}”是符号链接,链接的目标也要包括在内才会备份。" #: qt/manageprofiles/tab_include.py:172 msgid "Include the symlink's target instead?" msgstr "是否改为包括符号链接目标?" #: qt/manageprofiles/tab_include.py:180 msgid "Include files" msgstr "包括文件" #: qt/manageprofiles/tab_include.py:199 msgid "Include directories" msgstr "包括目录" #: qt/manageprofiles/tab_options.py:39 msgid "Enable notifications" msgstr "启用通知" #: qt/manageprofiles/tab_options.py:43 msgid "Disable backups when on battery" msgstr "电池供电时禁用备份" #: qt/manageprofiles/tab_options.py:49 msgid "Power status not available from system" msgstr "无法从系统中获取电源状态" #: qt/manageprofiles/tab_options.py:52 msgid "Run only one backup at a time" msgstr "一次仅运行一个备份" #: qt/manageprofiles/tab_options.py:56 msgid "" "Other backups will be blocked until the current backup is completed. This is" " a global setting, meaning it will affect all profiles for this user. " "However, it must also be activated for all other users." msgstr "在当前备份完成前会阻止其他备份。这是全局设置,意味着将影响此用户的所有配置。但是,还必须为所有其他用户启用该设置。" #: qt/manageprofiles/tab_options.py:63 msgid "Backup replaced files on restore" msgstr "恢复时备份替换的文件" #: qt/manageprofiles/tab_options.py:78 msgid "Continue on errors (keep incomplete backups)" msgstr "出错时继续(保留不完整的备份)" #: qt/manageprofiles/tab_options.py:82 msgid "Use checksum to detect changes" msgstr "使用校验和检测更改" #: qt/manageprofiles/tab_options.py:86 msgid "Create a new backup whether there were changes or not." msgstr "无论是否有更改,都创建新备份。" #: qt/manageprofiles/tab_options.py:95 msgid "Warn if the free disk space falls below" msgstr "发出警告,当可用磁盘空间低于" #: qt/manageprofiles/tab_options.py:101 msgid "" "Shows a warning when free space on the backup destination disk is less than " "the specified value." msgstr "当备份目标磁盘上的可用空间小于指定值时显示警告。" #: qt/manageprofiles/tab_options.py:103 msgid "" "If the Remove & Retention policy is enabled and old backups are removed " "based on available free space, this value cannot be lower than the value set" " in the policy." msgstr "如果启用了“移除和保留”策略,并根据可用空间移除旧备份,则此值不能低于策略中设置的值。" #: qt/manageprofiles/tab_options.py:122 msgid "Log Level:" msgstr "日志级别:" #: qt/manageprofiles/tab_options.py:185 msgid "None" msgstr "无" #: qt/manageprofiles/tab_remove_retention.py:206 msgid "user manual" msgstr "用户手册" #: qt/manageprofiles/tab_remove_retention.py:208 #, python-brace-format msgid "" "The following rules are processed from top to bottom. Later rules override " "earlier ones. See the {manual_link} for details and examples." msgstr "以下规则按从上到下的顺序处理。后出现的规则会覆盖先前的规则。详情及示例请参阅{manual_link}。" #: qt/manageprofiles/tab_remove_retention.py:223 msgid "Open user manual in browser." msgstr "在浏览器中打开用户手册。" #: qt/manageprofiles/tab_remove_retention.py:237 msgid "Keep the most recent backup." msgstr "保留最新备份。" #: qt/manageprofiles/tab_remove_retention.py:241 msgid "The most up-to-date backup is kept under all circumstances." msgstr "在任何情况下都会保留最新的备份。" #: qt/manageprofiles/tab_remove_retention.py:243 msgid "That behavior cannot be changed." msgstr "这种行为无法更改。" #: qt/manageprofiles/tab_remove_retention.py:255 msgid "Keep named backups." msgstr "保留已命名的备份。" #: qt/manageprofiles/tab_remove_retention.py:258 msgid "" "Backups that have been given a name, in addition to the usual timestamp, " "will be retained under all circumstances and will not be removed." msgstr "除了通常的时间戳外,已命名的备份在任何情况下都将保留,不会被移除。" #: qt/manageprofiles/tab_remove_retention.py:273 msgid "Year(s)" msgstr "年" #: qt/manageprofiles/tab_remove_retention.py:278 msgid "Remove backups older than" msgstr "移除多久前的备份" #: qt/manageprofiles/tab_remove_retention.py:284 msgid "Full days. Current day is ignored." msgstr "整天数,当日忽略不计。" #: qt/manageprofiles/tab_remove_retention.py:286 msgid "Calendar weeks with Monday as first day. Current week is ignored." msgstr "星期一作为第一天的日历周,当前周忽略不计。" #: qt/manageprofiles/tab_remove_retention.py:289 msgid "12 months periods. Current month is ignored." msgstr "12 个月的周期,当前月份忽略不计。" #: qt/manageprofiles/tab_remove_retention.py:305 msgid "Retention policy" msgstr "保留策略" #: qt/manageprofiles/tab_remove_retention.py:310 msgid "Run in background on remote host." msgstr "在远程主机后台运行。" #: qt/manageprofiles/tab_remove_retention.py:313 msgid "" "The retention policy will be executed directly on the remote machine, not " "locally. The commands \"bash\", \"screen\", and \"flock\" must be installed " "and available on that remote machine." msgstr "保留策略将直接在远程机器上执行,而非本地执行。远程机器上必须安装并可用“bash”、“screen”和“flock”命令。" #: qt/manageprofiles/tab_remove_retention.py:317 msgid "If selected, Back In Time will first test the remote machine." msgstr "如果选择,Back In Time 将首先测试远程机器。" #: qt/manageprofiles/tab_remove_retention.py:321 msgid "The days are counted starting from today." msgstr "从今天开始计算天数。" #: qt/manageprofiles/tab_remove_retention.py:322 msgid "Keep all backups for the last" msgstr "保留所有备份" #: qt/manageprofiles/tab_remove_retention.py:327 #: qt/manageprofiles/tab_remove_retention.py:339 msgid "day(s)." msgstr "天。" #: qt/manageprofiles/tab_remove_retention.py:334 msgid "Keep the last backup for each day for the last" msgstr "保留每天的最后备份" #: qt/manageprofiles/tab_remove_retention.py:344 msgid "" "The weeks are counted starting from the current running week. A week starts " "on Monday." msgstr "周数从当前周开始计算,一周从星期一开始。" #: qt/manageprofiles/tab_remove_retention.py:347 msgid "Keep the last backup for each week for the last" msgstr "保留每周的最后备份" #: qt/manageprofiles/tab_remove_retention.py:352 msgid "week(s)." msgstr "周。" #: qt/manageprofiles/tab_remove_retention.py:357 msgid "" "The months are counted as calendar months starting with the current month." msgstr "月份从当前月份开始,按日历月份计算。" #: qt/manageprofiles/tab_remove_retention.py:360 msgid "Keep the last backup for each month for the last" msgstr "保留每月的最后备份" #: qt/manageprofiles/tab_remove_retention.py:365 msgid "month(s)." msgstr "月。" #: qt/manageprofiles/tab_remove_retention.py:370 msgid "" "The years are counted as calendar years starting with the current year." msgstr "年份从当前年份开始,按日历年份计算。" #: qt/manageprofiles/tab_remove_retention.py:372 msgid "Keep the last backup for each year for" msgstr "保留每年的最后备份" #: qt/manageprofiles/tab_remove_retention.py:374 msgid "all years." msgstr "所有年份。" #: qt/manageprofiles/tab_remove_retention.py:389 msgid "… the free space is less than" msgstr "… 可用空间小于" #: qt/manageprofiles/tab_remove_retention.py:394 msgid "… the free inodes are less than" msgstr "… 可用索引节点少于" #: qt/manageprofiles/tab_remove_retention.py:403 msgid "Remove oldest backup if …" msgstr "移除最旧备份,当…" #: qt/net.launchpad.backintime.policy:21 msgid "Authentication is required to run Back In Time as root." msgstr "需要进行身份验证才能以 root 运行 Back In Time。" #: qt/net.launchpad.backintime.policy:33 qt/net.launchpad.backintime.policy:43 msgid "" "Authentication is required to change backup schedules triggered by external " "storage device connections." msgstr "需要进行身份验证才能更改由外部存储设备连接触发的备份计划。" #: qt/placeswidget.py:49 msgid "Shortcuts" msgstr "快捷方式" #: qt/placeswidget.py:63 msgid "Places" msgstr "位置" #: qt/placeswidget.py:64 msgid "File System" msgstr "文件系统" #: qt/placeswidget.py:106 msgid "Backup directories" msgstr "备份目录" #: qt/qtsystrayicon.py:109 #, python-brace-format msgid "Profile: {profile_name}" msgstr "配置:{profile_name}" #: qt/qtsystrayicon.py:112 #, python-brace-format msgid "Profile: {profile_name} (by user \"{desktop_user}\")" msgstr "配置:{profile_name}(用户“{desktop_user}”)" #: qt/qtsystrayicon.py:155 msgid "View Last Log" msgstr "查看最新日志" #: qt/qtsystrayicon.py:161 #, python-brace-format msgid "Start {appname}" msgstr "启动 {appname}" #: qt/qtsystrayicon.py:253 msgid "Working…" msgstr "运行中…" #: qt/qttools.py:503 #, python-brace-format msgid "man page: {man_page_name}" msgstr "手册页:{man_page_name}" #: qt/restoreconfigdialog.py:74 msgid "Import configuration" msgstr "导入配置" #: qt/restoreconfigdialog.py:105 msgid "No directory selected" msgstr "未选择目录" #: qt/restoreconfigdialog.py:134 msgid "Import" msgstr "导入" #: qt/restoreconfigdialog.py:154 qt/restoreconfigdialog.py:234 msgid "Searching…" msgstr "正在搜索…" #: qt/restoreconfigdialog.py:211 #, python-brace-format msgid "" "Select the backup directory from which the configuration file should be " "imported. The path may look like: {samplePath}" msgstr "选择应从中导入配置文件的备份目录。示例路径:{samplePath}" #: qt/restoreconfigdialog.py:216 msgid "" "If the directory is located on an external or remote drive, it must be " "manually mounted beforehand." msgstr "如果该目录位于外部或远程驱动器上,则必须事先手动挂载。" #: qt/restoreconfigdialog.py:237 msgid "Scan again" msgstr "再次扫描" #: qt/restoreconfigdialog.py:256 msgid "Show hidden directories" msgstr "显示隐藏目录" #: qt/restoreconfigdialog.py:258 msgid "Show/hide hidden directories (Ctrl+H)" msgstr "显示/隐藏隐藏目录(Ctrl+H)" #: qt/restoreconfigdialog.py:305 msgid "No config found in this directory" msgstr "此目录中未找到配置" #: qt/restoreconfigdialog.py:366 msgid "Search complete." msgstr "搜索完成。" #: qt/restoredialog.py:58 msgid "Show full Log" msgstr "显示完整日志" #: qt/shutdowndlg.py:28 msgid "Countdown to Shutdown" msgstr "关机倒计时" #: qt/shutdowndlg.py:29 msgid "The backup has finished." msgstr "备份已完成。" #: qt/shutdowndlg.py:36 msgid "Cancel Shutdown" msgstr "取消关机" #: qt/shutdowndlg.py:37 msgid "Shutdown Now" msgstr "立即关机" #: qt/shutdowndlg.py:69 #, python-brace-format msgid "The system will shut down in {n} second." msgid_plural "The system will shut down in {n} seconds." msgstr[0] "系统将在 {n} 秒后关闭。" #: qt/snapshotsdialog.py:63 msgid "Options about comparing backups" msgstr "关于比较备份的选项" #: qt/snapshotsdialog.py:70 msgid "Command:" msgstr "命令:" #: qt/snapshotsdialog.py:74 msgid "Parameters:" msgstr "参数:" #: qt/snapshotsdialog.py:79 msgid "Use %1 and %2 for path parameters" msgstr "用 %1 和 %2 作为路径参数" #: qt/snapshotsdialog.py:96 msgid "Please set a diff command or press Cancel." msgstr "请设置 diff 命令或按取消。" #: qt/snapshotsdialog.py:102 #, python-brace-format msgid "" "The command \"{cmd}\" cannot be found on this system. Please try something " "else or press Cancel." msgstr "此系统上找不到命令“{cmd}”。请尝试其他命令或按“取消”。" #: qt/snapshotsdialog.py:110 #, python-brace-format msgid "No parameters set for the diff command. Using default value \"{params}\"." msgstr "diff 命令未设置参数。使用默认值“{params}”。" #: qt/snapshotsdialog.py:141 qt/timeline.py:44 msgid "Backups" msgstr "备份" #: qt/snapshotsdialog.py:152 msgid "Differing backups only" msgstr "仅差异备份" #: qt/snapshotsdialog.py:161 msgid "List only backups that are equal to:" msgstr "仅列出与之匹配的备份:" #: qt/snapshotsdialog.py:173 msgid "Deep check (more accurate, but slow)" msgstr "深度检查(更准确,但较慢)" #: qt/snapshotsdialog.py:194 msgid "Delete" msgstr "删除" #: qt/snapshotsdialog.py:199 msgid "Select All" msgstr "全选" #: qt/snapshotsdialog.py:212 msgid "Compare" msgstr "比较" #: qt/snapshotsdialog.py:227 msgid "Go To" msgstr "转到" #: qt/snapshotsdialog.py:229 msgid "Options" msgstr "选项" #: qt/snapshotsdialog.py:394 msgid "" "It is not possible to compare a backup to itself, as the comparison would be" " redundant." msgstr "无法将备份与其自身进行比较,因为比较是多余的。" #: qt/snapshotsdialog.py:440 #, python-brace-format msgid "Really delete {file_or_dir} in backup {backup_id}?" msgstr "是否确定要删除备份 {backup_id} 中 {file_or_dir}?" #: qt/snapshotsdialog.py:445 #, python-brace-format msgid "Really delete {file_or_dir} in {count} backups?" msgstr "是否确定要删除 {count} 个备份中的 {file_or_dir}?" #: qt/snapshotsdialog.py:448 msgid "WARNING: This cannot be revoked." msgstr "警告:此操作无法撤销。" #: qt/snapshotsdialog.py:465 #, python-brace-format msgid "Exclude {path} from future backups?" msgstr "是否从未来的备份中排除 {path}?" #: qt/statusbar.py:85 msgid "Root mode" msgstr "root 模式" #: qt/statusbar.py:87 msgid "" "Back In Time is currently running with root privileges (full system access)" msgstr "Back In Time 当前正在以 root 权限(完整系统访问权限)运行" #: qt/timeline.py:69 msgid "Today" msgstr "今天" #: qt/timeline.py:77 msgid "Yesterday" msgstr "昨天" #: qt/timeline.py:87 msgid "This week" msgstr "本周" #: qt/timeline.py:95 msgid "Last week" msgstr "上周" #: qt/timeline.py:270 msgid "This is NOT a backup but a live view of the local files." msgstr "这不是备份,而是本地文件的实时视图。" #: qt/timeline.py:275 #, python-brace-format msgid "Last check {time}" msgstr "上次检查 {time}" backintime-1.6.1/common/po/zh_TW.po000066400000000000000000002133131514264426600171430ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008 Back In Time Team # SPDX-FileCopyrightText: © Kuntao Zhao # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Strict and accurate recording of translators' names began around 2022. As # the project started in 2008, some earlier translators' names may not have # been documented and could be lost. msgid "" msgstr "" "Project-Id-Version: Back In Time 1.6.1\n" "Report-Msgid-Bugs-To: https://github.com/bit-team/backintime\n" "POT-Creation-Date: 2026-02-10 15:49+0100\n" "PO-Revision-Date: 2026-01-31 12:36+0000\n" "Last-Translator: ktzhao \n" "Language-Team: Chinese (Traditional Han script) \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.15.2\n" #: common/bitlicense.py:43 #, python-brace-format msgid "" "All licenses used in this project are located in the {dir_link} directory. " "To extract per-file license and copyright information using SPDX metadata, " "refer to {readme_link}." msgstr "" "本項目所使用的所有授權都位於 {dir_link} 目錄中。若要使用 SPDX 元資料提取每個檔案的許可證和版權信息,請參閱 " "{readme_link}。" #: common/config.py:37 common/tools.py:87 qt/encfsmsgbox.py:25 #: qt/messagebox.py:99 msgid "Warning" msgstr "警告" #: common/config.py:109 common/config.py:219 msgid "Main profile" msgstr "主要設定檔" #: common/config.py:225 msgid "Local (EncFS encrypted)" msgstr "本地(EncFS 加密)" #: common/config.py:226 msgid "SSH (EncFS encrypted)" msgstr "SSH(EncFS 加密)" #: common/config.py:237 msgid "Local" msgstr "本地端" #: common/config.py:240 msgid "Local encrypted" msgstr "本地加密的" #: common/config.py:241 common/config.py:249 common/config.py:256 #: qt/manageprofiles/tab_general.py:405 msgid "Encryption" msgstr "加密" #: common/config.py:245 msgid "SSH" msgstr "SSH" #: common/config.py:245 common/config.py:255 #: qt/manageprofiles/tab_general.py:744 msgid "SSH private key" msgstr "SSH 私鑰" #: common/config.py:300 common/config.py:312 common/config.py:330 #: common/config.py:344 common/config.py:365 #, python-brace-format msgid "Profile: \"{name}\"" msgstr "設定檔:\"{name}\"" #: common/config.py:301 msgid "Backup directory is not valid." msgstr "備份目錄不合規定。" #: common/config.py:313 msgid "At least one directory must be selected for backup." msgstr "至少必須選擇一個目錄進行備份。" #: common/config.py:331 common/config.py:346 #, python-brace-format msgid "Directory: {path}" msgstr "目錄: {path}" #: common/config.py:332 common/config.py:347 msgid "" "This directory cannot be included in the backup as it is part of the backup " "destination itself." msgstr "該目錄不能包含在備份中,因為它是備份目標本身的一部分。" #: common/config.py:366 #, python-brace-format msgid "" "The value for \"Remove oldest backup if the free space is less than\" " "({val_one}) must be less than or equal the threshold for \"Warn if free disk" " space falls below\" ({val_two})." msgstr "「如果可用空間小於」的值「刪除最舊的備份」({val_one})必須小於或等於「如果可用磁碟空間低於」的閾值({val_two})。" #: common/config.py:371 msgid "" "Please adjust the settings so that the backup removal limit is not higher " "than the warning limit." msgstr "請調整設置,使備份刪除限制不高於警告限制。" #: common/config.py:1515 #, python-brace-format msgid "Udev schedule doesn't work with mode {mode}" msgstr "udev 定期排程不適用於 {mode} 模式" #: common/config.py:1569 msgid "Failed to write new crontab." msgstr "無法寫入新的 crontab。" #: common/config.py:1577 msgid "" "Cron is not running, even though the crontab command is available. Scheduled" " backup jobs will not run. Cron might be installed but not enabled. Try " "running the two commands \"systemctl enable cron\" and \"systemctl start " "cron\", or consult the support channels of the currently used GNU/Linux " "distribution for assistance." msgstr "" "儘管 crontab 命令可用,但 Cron 並未運行。已排程的備份作業將不會運作。 Cron 可能已安裝但未啟用。嘗試命令「systemctl " "enable cron」或諮詢您的 GNU Linux 發行版的支援服務商。" #: common/configfile.py:101 msgid "Failed to save config" msgstr "儲存設定失敗" #: common/configfile.py:137 msgid "Failed to load config" msgstr "載入設定失敗" #: common/configfile.py:679 common/configfile.py:779 #, python-brace-format msgid "Profile \"{name}\" already exists." msgstr "\"{name}\" 設定檔已存在。" #: common/configfile.py:725 msgid "The last profile cannot be removed." msgstr "無法刪除最後一個設定檔。" #: common/encfstools.py:129 common/gocryptfstools.py:84 #, python-brace-format msgid "Unable to mount \"{command}\"" msgstr "無法掛載 “{command}”" #: common/encfstools.py:190 msgid "Configuration for the encrypted directory not found." msgstr "找不到加密目錄的設定。" #: common/encfstools.py:197 msgid "Create a new encrypted directory?" msgstr "建立一個新的加密目錄?" #: common/encfstools.py:204 msgid "Cancel" msgstr "取消" #: common/encfstools.py:209 msgid "Please re-enter the EncFS password to confirm." msgstr "請重新輸入 EncFS 密碼進行確認。" #: common/encfstools.py:215 msgid "The EncFS passwords do not match." msgstr "EncFS 密碼不符。" #: common/encfstools.py:659 common/snapshots.py:1128 msgid "Take snapshot" msgstr "進行快照" #: common/gocryptfstools.py:133 #, python-brace-format msgid "Unable to init encrypted path \"{command}\"" msgstr "無法初始化加密路徑“{command}”" #: common/mount.py:663 #, python-brace-format msgid "Unable to unmount {mountprocess} from {mountpoint}." msgstr "無法從 {mountpoint} 卸載 {mountprocess}。" #: common/mount.py:750 #, python-brace-format msgid "{command} not found. Please install it (e.g. via \"{installcommand}\")" msgstr "找不到指令{command}。請安裝它(例如透過“{installcommand}”)" #: common/mount.py:774 #, python-brace-format msgid "Mountpoint {mntpoint} not empty." msgstr "掛載點 {mntpoint} 不為空。" #: common/password.py:306 #, python-brace-format msgid "Enter password for {mode} profile \"{profile}\":" msgstr "輸入 {mode} 設定檔「{profile}」的密碼:" #: common/schedule.py:238 #, python-brace-format msgid "" "Could not install Udev rule for profile {profile_id}. DBus Service " "'{dbus_interface}' wasn't available." msgstr "無法為設定檔 {profile_id} 安裝 Udev 規則。 DBus 服務「{dbus_interface}」不可用" #: common/schedule.py:251 #, python-brace-format msgid "Couldn't find UUID for {path}" msgstr "找不到 {path} 的 UUID" #: common/snapshots.py:378 common/snapshots.py:656 msgid "FAILED" msgstr "失敗" #: common/snapshots.py:579 common/snapshots.py:652 msgid "Restore permissions" msgstr "回復權限" #: common/snapshots.py:656 qt/app.py:240 qt/app.py:1195 qt/app.py:1211 #: qt/qtsystrayicon.py:118 msgid "Done" msgstr "完成" #: common/snapshots.py:749 msgid "" "The following entries from the include list have no corresponding file or " "directory in the backup source:" msgstr "包含清單中的下列項目在備份來源中沒有對應的檔案或目錄:" #: common/snapshots.py:812 msgid "Deferring backup while on battery" msgstr "使用電池時延遲備份" #: common/snapshots.py:931 qt/app.py:393 msgid "Can't find backup directory." msgstr "找不到快照目錄。" #: common/snapshots.py:935 qt/app.py:394 msgid "If it is on a removable drive, please plug it in." msgstr "如果它在可移動磁碟中,請插入。" #: common/snapshots.py:938 #, python-brace-format msgid "Waiting {n} second." msgid_plural "Waiting {n} seconds." msgstr[0] "等待{n} 秒。" #: common/snapshots.py:1005 #, python-brace-format msgid "Failed to create backup {snapshot_id}." msgstr "建立快照 {snapshot_id} 失敗。" #: common/snapshots.py:1037 msgid "Please be patient. Finalizing…" msgstr "請耐心等待。正在完成中…" #: common/snapshots.py:1163 msgid "Can't create directory." msgstr "無法创建目錄。" #: common/snapshots.py:1180 msgid "Saving config file…" msgstr "正在儲存設定檔…" #: common/snapshots.py:1261 msgid "Saving permissions…" msgstr "正在儲存權限設定…" #: common/snapshots.py:1377 #, python-brace-format msgid "Found incomplete backup {snapshot_id} that can be continued." msgstr "發現尚未完成的快照 {snapshot_id} 可繼續處理。" #: common/snapshots.py:1401 #, python-brace-format msgid "Removing incomplete {snapshot_id} directory from last run" msgstr "正在從上次執行中移除不完整的 {snapshot_id} 目錄" #: common/snapshots.py:1412 msgid "Can't remove directory" msgstr "無法刪除目錄" #: common/snapshots.py:1466 msgid "Creating backup" msgstr "建立備份" #: common/snapshots.py:1517 msgid "Success" msgstr "成功" #: common/snapshots.py:1520 msgid "Partial transfer due to error" msgstr "由於錯誤只轉移部分" #: common/snapshots.py:1521 msgid "Partial transfer due to vanished source files (see 'man rsync')" msgstr "由於來源檔消失而導致只傳輸部分(請見“man rsync”)" #: common/snapshots.py:1525 #, python-brace-format msgid "'rsync' ended with exit code {exit_code}" msgstr "“rsync”已終止退出代碼 {exit_code}" #: common/snapshots.py:1538 msgid "See 'man rsync' for more details" msgstr "有關更多詳細信息,請參閱“man rsync”" #: common/snapshots.py:1545 msgid "" "Negative rsync exit codes are signal numbers, see 'kill -l' and 'man kill'" msgstr "rsync 異常終止,請參閱 “kill -l” 和 “man Kill”" #: common/snapshots.py:1566 msgid "Nothing changed, no new backup necessary" msgstr "沒有任何變化,無需新的備份" #: common/snapshots.py:1611 #, python-brace-format msgid "Unable to rename {new_path} to {path}." msgstr "無法將 {new_path} 重新命名為 {path}。" #: common/snapshots.py:1998 msgid "Applying rules to remove old backups" msgstr "應用程式規則刪除舊備份" #: common/snapshots.py:2031 msgid "Applying retention policy" msgstr "正在應用保留策略" #: common/snapshots.py:2041 msgid "Trying to keep min free space" msgstr "嘗試保留最小剩餘空間" #: common/snapshots.py:2079 #, python-brace-format msgid "Trying to keep min {perc} free inodes" msgstr "嘗試保留最小 {perc} 可用 inode" #: common/snapshots.py:3211 qt/app.py:1482 msgid "Now" msgstr "現在" #: common/sshtools.py:233 #, python-brace-format msgid "Unable to mount {sshfs}" msgstr "無法掛載 {sshfs}" #: common/sshtools.py:306 msgid "ssh-agent not found. Please ensure it is installed." msgstr "未找到ssh-agent。 請確保它已安裝。" #: common/sshtools.py:489 msgid "" "Could not unlock ssh private key. Wrong password or password not available " "for cron." msgstr "無法解鎖 ssh 私鑰。 密碼錯誤或密碼不可用於 cron。" #: common/sshtools.py:721 msgid "Remote path exists but is not a directory." msgstr "遠端路徑存在但不是目錄。" #: common/sshtools.py:726 msgid "Remote path is not writable." msgstr "遠端路徑不可寫入。" #: common/sshtools.py:731 msgid "Remote path is not executable." msgstr "遠端路徑不可執行。" #: common/sshtools.py:736 msgid "Couldn't create remote path." msgstr "無法建立遠端路徑。" #: common/sshtools.py:1022 #, python-brace-format msgid "Remote host {host} doesn't support {command}" msgstr "遠端主機 {host} 不支援 {command}" #: common/sshtools.py:1026 #, python-brace-format msgid "Checking commands on host {host} returned unknown error" msgstr "檢查主機 {host} 上的指令回傳未知錯誤" #: common/sshtools.py:1044 #, python-brace-format msgid "Remote host {host} doesn't support hardlinks" msgstr "遠端主機 {host} 不支援硬連結(Hard links)" #: common/sshtools.py:1206 #, python-brace-format msgid "Copy public ssh-key \"{pubkey}\" to remote host \"{host}\"." msgstr "將ssh公鑰“{pubkey}”複製到遠端主機“{host}”。" #: common/sshtools.py:1208 #, python-brace-format msgid "Please enter a password for \"{user}\"." msgstr "請輸入「{user}」的密碼。" #: common/tools.py:382 #, python-brace-format msgid "" "The destination filesystem for {path} is formatted with NTFS, which has " "known incompatibilities with Unix-style filesystems." msgstr "{path} 的目標檔案系統採用 NTFS 格式,已知其與 Unix 風格的檔案系統不相容。" #: common/tools.py:414 #, python-brace-format msgid "{path} is not a valid directory." msgstr "{path} 不是有效的目錄。" #: common/tools.py:428 msgid "Creation of following directory failed:" msgstr "建立以下目錄失敗:" #: common/tools.py:430 common/tools.py:527 msgid "Write access may be restricted." msgstr "寫入權限可能受到限制。" #: common/tools.py:471 #, python-brace-format msgid "" "Destination filesystem for {path} is formatted with FAT which doesn't " "support hard-links. Please use a native GNU/Linux filesystem." msgstr "{path} 的檔案系統採用 FAT 格式,不支援硬連結。 請使用原生 Linux 檔案系統。" #: common/tools.py:482 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via SMB. Please make " "sure the remote SMB server supports symlinks or activate \"{copyLinks}\" in " "\"{expertOptions}\"." msgstr "" "{path} 的目標檔案系統是透過 SMB 掛載共用。請確保遠端 SMB " "伺服器支援符號連結或在「{expertOptions}」中啟動「{copyLinks}」。" #: common/tools.py:486 msgid "Copy links (dereference symbolic links)" msgstr "複製鏈結 (dereference symbolic links)" #: common/tools.py:487 msgid "Expert Options" msgstr "進階選項" #: common/tools.py:491 #, python-brace-format msgid "" "Destination filesystem for {path} is a share mounted via sshfs. Sshfs " "doesn't support hard-links. Please use mode \"SSH\" instead." msgstr "{path} 的目標檔案系統是透過 sshfs 掛載的共用。 sshfs 不支援硬連結。請改用模式“SSH”。" #: common/tools.py:525 msgid "File creation failed in this directory:" msgstr "在此目錄中建立檔案失敗:" #: qt/aboutdlg.py:51 msgid "About Back In Time" msgstr "Back In Time" #: qt/aboutdlg.py:89 msgid "Copyright:" msgstr "版權:" #: qt/aboutdlg.py:93 msgid "Authors:" msgstr "作者:" #: qt/aboutdlg.py:97 msgid "Translators:" msgstr "譯者:" #: qt/aboutdlg.py:100 msgid "translator-credits-placeholder" msgstr "Kuntao Zhao " #: qt/aboutdlg.py:107 msgid "Translator credits not available for current language." msgstr "‌當前語言沒有列出翻譯人員資訊。" #: qt/aboutdlg.py:116 msgid "this link" msgstr "此連結" #: qt/aboutdlg.py:118 #, python-brace-format msgid "Follow {thislink} to get translator credits for all languages." msgstr "依照{thislink}取得所有語言的翻譯資訊。" #: qt/aboutdlg.py:220 qt/app.py:578 msgid "Project website" msgstr "專案網站" #: qt/aboutdlg.py:225 qt/app.py:560 msgid "User manual" msgstr "使用者手冊" #: qt/aboutdlg.py:227 qt/app.py:562 msgid "Open user manual in browser (local if available, otherwise online)" msgstr "在瀏覽器中開啟使用者手冊(如果是本機文件則打開,否則線上開啟)" #: qt/aboutdlg.py:277 #, python-brace-format msgid "{BOLD}Version{BOLDEND}: {version}" msgstr "{BOLD}版本{BOLDEND}:{version}" #: qt/app.py:348 #, python-brace-format msgid "" "{app_name} appears to be running for the first time because no configuration" " is found." msgstr "{app_name} 似乎是第一次運行,因為找不到任何配置。" #: qt/app.py:353 msgid "" "Import an existing configuration from a backup location or another computer?" msgstr "從備份位置或其他電腦匯入現有配置?" #: qt/app.py:395 msgid "Then press OK." msgstr "然後按“確定”。" #: qt/app.py:499 msgid "Create a backup" msgstr "建立備份" #: qt/app.py:501 msgid "Use modification time & size for file change detection." msgstr "使用修改時間和大小來檢測檔案變更。" #: qt/app.py:504 msgid "Create a backup (checksum mode)" msgstr "建立快照(校驗模式)" #: qt/app.py:506 msgid "Use checksums for file change detection." msgstr "使用校驗和(checksums)來檢測檔案變更。" #: qt/app.py:508 qt/qtsystrayicon.py:125 msgid "Pause backup process" msgstr "暫停快照處理" #: qt/app.py:512 qt/qtsystrayicon.py:130 msgid "Resume backup process" msgstr "恢復快照處理" #: qt/app.py:516 qt/qtsystrayicon.py:135 msgid "Stop backup process" msgstr "停止快照處理" #: qt/app.py:520 msgid "Refresh backup list" msgstr "重新整理快照列表" #: qt/app.py:524 msgid "Name backup" msgstr "命名備份" #: qt/app.py:528 msgid "Remove backup" msgstr "刪除快照" #: qt/app.py:532 msgid "Open backup log" msgstr "開啟備份日誌" #: qt/app.py:534 msgid "View log of the selected backup." msgstr "查看所選備份的日誌。" #: qt/app.py:536 msgid "Open last backup log" msgstr "查看最後的記錄" #: qt/app.py:538 msgid "View log of the latest backup." msgstr "查看最新備份的日誌。" #: qt/app.py:540 msgid "Manage profiles…" msgstr "管理設定檔…" #: qt/app.py:544 msgid "Edit user-callback" msgstr "編輯用戶回調" #: qt/app.py:548 msgid "Shutdown" msgstr "關閉" #: qt/app.py:550 msgid "Shut down system after backup has finished." msgstr "快照完成後關閉系統。" #: qt/app.py:552 msgid "Setup language…" msgstr "設定語言…" #: qt/app.py:556 msgid "Exit" msgstr "離開" #: qt/app.py:566 msgid "man page: Back In Time" msgstr "手冊頁:Back In &Time" #: qt/app.py:568 msgid "Displays man page about Back In Time (backintime)" msgstr "顯示有關 Back In Time(backintime)的手冊頁" #: qt/app.py:571 msgid "man page: Profiles config file" msgstr "手冊頁:設定檔" #: qt/app.py:574 msgid "Displays man page about profiles config file (backintime-config)" msgstr "顯示有關設定檔 (backintime-config) 的手冊頁" #: qt/app.py:581 msgid "Open Back In Time website in browser" msgstr "在瀏覽器中開啟 Back In Time 網站" #: qt/app.py:583 qt/app.py:2301 msgid "Changelog" msgstr "變更日誌" #: qt/app.py:586 msgid "Open changelog (locally if available, otherwise from the web)" msgstr "開啟變更日誌(如果本機有則打開,否則從網路開啟)" #: qt/app.py:589 msgid "FAQ" msgstr "常見問題" #: qt/app.py:591 msgid "Open Frequently Asked Questions (FAQ) in browser" msgstr "在瀏覽器中開啟常見問題 (FAQ)" #: qt/app.py:593 msgid "Ask a question" msgstr "提出問題" #: qt/app.py:597 msgid "Report a bug" msgstr "報告錯誤" #: qt/app.py:600 msgid "Translation" msgstr "翻譯" #: qt/app.py:602 msgid "Shows the message about participation in translation again." msgstr "再次顯示參與翻譯的訊息。" #: qt/app.py:606 msgid "Encryption Transition (EncFS)" msgstr "加密轉換 (EncFS)" #: qt/app.py:608 msgid "Shows the message about EncFS removal again." msgstr "再次顯示有關 EncFS 刪除的訊息。" #: qt/app.py:615 msgid "About" msgstr "關於" #: qt/app.py:618 qt/restoredialog.py:46 qt/snapshotsdialog.py:184 #: qt/snapshotsdialog.py:189 msgid "Restore" msgstr "還原" #: qt/app.py:620 msgid "Restore the selected files or directories to the original location." msgstr "將選定的檔案或目錄還原到原始位置。" #: qt/app.py:623 qt/app.py:1942 qt/snapshotsdialog.py:186 msgid "Restore to …" msgstr "還原至…" #: qt/app.py:625 #, fuzzy msgid "Restore the selected files or directories to a new location." msgstr "將選定的檔案或目錄還原到新的目的地。" #: qt/app.py:631 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to the original " "location." msgstr "將目前顯示的目錄及其所有內容還原至原始目標。" #: qt/app.py:637 #, fuzzy msgid "" "Restore the currently shown directory and all its contents to a new " "location." msgstr "將目前顯示的目錄及其所有內容還原至新目的地。" #: qt/app.py:640 msgid "Up" msgstr "回到上一層" #: qt/app.py:643 msgid "Show hidden files" msgstr "顯示隱藏檔案" #: qt/app.py:646 msgid "Compare backups…" msgstr "比較快照…" #: qt/app.py:676 qt/app.py:1815 msgid "Release Candidate" msgstr "候選版本(Release Candidate)" #: qt/app.py:679 msgid "Shows the message about this Release Candidate again." msgstr "再次顯示有關此候選版本的消息。" #: qt/app.py:716 msgid "Back In &Time" msgstr "Back In &Time" #: qt/app.py:721 msgid "&Backup" msgstr "&備份" #: qt/app.py:733 msgid "&Restore" msgstr "&還原" #: qt/app.py:739 msgid "&Help" msgstr "&幫助" #: qt/app.py:790 msgid "Systray Icon" msgstr "" #: qt/app.py:796 msgid "Automatic" msgstr "" #: qt/app.py:800 msgid "Light icon" msgstr "" #: qt/app.py:801 msgid "Dark icon" msgstr "" #: qt/app.py:824 msgid "Icons only" msgstr "僅限圖示" #: qt/app.py:827 msgid "Text only" msgstr "限文字" #: qt/app.py:830 msgid "Text below icons" msgstr "圖示下方的文字" #: qt/app.py:833 msgid "Text beside icon" msgstr "圖示旁邊的文字" #: qt/app.py:944 msgid "" "This directory doesn't exist\n" "in the current selected backup." msgstr "" "在目前選定的快照中\n" "不存在該目錄。" #: qt/app.py:1005 msgid "Add to Include" msgstr "加入包含項目" #: qt/app.py:1006 msgid "Add to Exclude" msgstr "加入排除項目" #: qt/app.py:1020 msgid "" "If this window is closed, Back In Time will not be able to shut down your " "system when the backup is finished." msgstr "如果您關閉此窗口,Back In Time 將無法在快照完成後關閉您的系統。" #: qt/app.py:1023 msgid "Close the window anyway?" msgstr "仍要關閉視窗?" #: qt/app.py:1214 msgid "Done, no backup needed" msgstr "已完成,不需要進行備份" #: qt/app.py:1285 msgid "Working:" msgstr "運作中 :" #: qt/app.py:1292 msgid "Working" msgstr "運作中" #: qt/app.py:1298 qt/messagebox.py:136 msgid "Error" msgstr "錯誤" #: qt/app.py:1339 qt/qtsystrayicon.py:295 msgid "Sent:" msgstr "傳送:" #: qt/app.py:1340 qt/qtsystrayicon.py:296 msgid "Speed:" msgstr "速度:" #: qt/app.py:1341 qt/qtsystrayicon.py:297 msgid "ETA:" msgstr "ETA:" #: qt/app.py:1490 #, fuzzy msgid "Backup:" msgstr "備份:" #: qt/app.py:1530 #, python-brace-format msgid "Restore {path}" msgstr "還原{path}" #: qt/app.py:1532 #, python-brace-format msgid "Restore {path} to …" msgstr "還原{path}到…" #: qt/app.py:1680 #, python-brace-format msgid "" "Hello\n" "You have used Back In Time in the {language} language a few times by now.\n" "The translation of your installed version of Back In Time into {language} is {perc} complete. Regardless of your level of technical expertise, you can contribute to the translation and thus Back In Time itself.\n" "Please visit the {translation_platform_url} if you wish to contribute. For further assistance and questions, please visit the {back_in_time_project_website}.\n" "We apologize for the interruption, and this message will not be shown again. This dialog is available at any time via the help menu.\n" "Your Back In Time Team" msgstr "" "您好,\n" "您已經多次以 {language} 使用 Back In Time 了。\n" "當前安裝的 Back In Time 所使用的 {language} 翻譯完成了 {perc}。無論您技術能力如何,都可以向 Back In Time 貢獻翻譯。\n" "若您希望參與翻譯,請訪問 {translation_platform_url}。如需協助或瞭解詳情,請訪問 {back_in_time_project_website}。\n" "非常抱歉打斷您的使用,本訊息今後不會再顯示。此對話框可以隨時在「幫助」菜單內呼出。\n" "Back In Time 團隊" #: qt/app.py:1709 msgid "translation platform" msgstr "翻譯平台" #: qt/app.py:1714 msgid "Website" msgstr "網站" #: qt/app.py:1728 msgid "Your translation" msgstr "您的翻譯" #: qt/app.py:1765 #, python-brace-format msgid "In the Fediverse at Mastodon: {link_and_label}." msgstr "在聯邦宇宙 Mastodon:{link_and_label}" #: qt/app.py:1770 #, fuzzy, python-brace-format msgid "Email to {link_and_label}." msgstr "郵件清單 {link_and_label}" #: qt/app.py:1774 #, python-brace-format msgid "Mailing list {link_and_label}." msgstr "郵件清單 {link_and_label}" #: qt/app.py:1778 #, python-brace-format msgid "{link_and_label} on the project website." msgstr "項目網站上的 {link_and_label}。" #: qt/app.py:1781 msgid "Open an issue" msgstr "打開問題" #: qt/app.py:1782 msgid "Alternatively, you can use another channel of your choice." msgstr "或者,您也可以使用您選擇的其他管道。" #: qt/app.py:1787 #, python-brace-format msgid "" "This version of Back In Time is a Release Candidate and is primarily intended for stability testing in preparation for the next official release.\n" "No user data or telemetry is collected. However, the Back In Time team is very interested in knowing if the Release Candidate is being used and if it is worth continuing to provide such pre-release versions.\n" "Therefore, the team kindly asks for a short feedback on whether you have tested this version, even if you didn’t encounter any issues. Even a quick test run of a few minutes would help us a lot.\n" "The following contact options are available:\n" "{contact_list}\n" "In this version, this message won't be shown again but can be accessed anytime through the help menu.\n" "Thank you for your support and for helping us improve Back In Time!\n" "Your Back In Time Team" msgstr "" "此版本的“Back In Time”為候選版本,主要用於穩定性測試,為下一個正式版本做準備。\n" "不收集任何用戶資料或遙測資料。然而,Back In Time 團隊非常有興趣了解候選版本是否正在使用,以及是否值得繼續提供這樣的預發布版本。\n" "因此,即使您沒有遇到任何問題,團隊仍懇請您簡短回饋是否已經測試過此版本。即使只是幾分鐘的快速測試運行也會對我們有很大幫助。\n" "可用的聯絡方式如下:\n" "{contact_list}\n" "在此版本中,此訊息不會再次顯示,但可以隨時透過說明選單存取。\n" "感謝您的支持並幫助我們改進“Back In Time”!\n" "您的 Back In Time團隊" #: qt/app.py:1892 #, python-brace-format msgid "" "Only {free} free space available on the destination, which is below the " "configured threshold of {threshold}." msgstr "目標上僅有 {free} 可用空間,低於配置的閾值 {threshold}。" #: qt/app.py:1897 msgid "Proceed with the backup?" msgstr "是否繼續備份?" #: qt/app.py:1922 #, python-brace-format msgid "All newer files in {path} will be removed. Proceed?" msgstr "{path} 中所有較新的檔案都將被刪除。是否繼續?" #: qt/app.py:1925 msgid "All newer files in the original directory will be removed. Proceed?" msgstr "原始目錄中所有較新的檔案都將被刪除。是否繼續?" #: qt/app.py:1931 #, python-brace-format msgid "" "{BOLD}Warning{BOLDEND}: Deleting files in the filesystem root could break " "the entire system." msgstr "{BOLD}警告{BOLDEND}:刪除檔案系統根目錄中的檔案可能會破壞整個系統。" #: qt/app.py:2167 msgid "Backup name" msgstr "備份" #: qt/app.py:2198 msgid "Remove this backup?" msgid_plural "Remove these backups?" msgstr[0] "刪除此備份嗎?" #: qt/app.py:2261 msgid "The language settings take effect only after restarting Back In Time." msgstr "語言設定僅在重新啟動 Back In Time 後生效。" #: qt/backintime-qt-root.desktop:14 msgid "Versioned Backups (root)" msgstr "" #: qt/backintime-qt-root.desktop:23 msgid "" "User-friendly GUI for versioned backups that reduces disk usage (root mode)" msgstr "" #: qt/backintime-qt.desktop:14 #, fuzzy msgid "Versioned Backups" msgstr "保留命名的快照。" #: qt/backintime-qt.desktop:23 msgid "User-friendly GUI for versioned backups that reduces disk usage" msgstr "" #: qt/confirmrestoredialog.py:35 qt/messagebox.py:123 msgid "Question" msgstr "問題" #: qt/confirmrestoredialog.py:76 #, fuzzy, python-brace-format msgid "" "Create backup copies with trailing {suffix} before overwriting or removing " "local elements." msgstr "" "建立帶有尾隨 {suffix} 的備份副本\n" "在覆蓋或刪除本地元素之前。" #: qt/confirmrestoredialog.py:81 qt/manageprofiles/tab_options.py:69 #, python-brace-format msgid "" "Before restoring, newer versions of files will be renamed with the appended " "{suffix}. These files can be removed with the following command:" msgstr "在復原之前,較新版本的檔案將使用尾隨 {suffix} 進行重新命名。如果您不再需要它們,可以使用以下命令刪除它們:" #: qt/confirmrestoredialog.py:94 #, fuzzy, python-brace-format msgid "" "Only restore elements which do not exist or are newer than those in " "destination. Using \"{rsync_example}\" option." msgstr "" "只恢復不存在或\n" "比目的地新的元素。\n" "使用“rsync --update”選項。" #: qt/confirmrestoredialog.py:133 msgid "Remove newer elements in original directory." msgstr "刪除原始資料夾中較新的元素。" #: qt/confirmrestoredialog.py:135 msgid "" "Restore selected files or directories to the original destination and delete" " files or directories which are not in the backup. Be extremely careful " "because this will delete files and directories which were excluded during " "the creation of the backup." msgstr "將選定的檔案或目錄還原到原始目標,並刪除快照中不存在的檔案或目錄。請務必小心,因為這將刪除在拍攝快照時排除的檔案和目錄。" #: qt/confirmrestoredialog.py:147 msgid "Really restore this element into the new directory?" msgid_plural "Really restore these elements into the new directory?" msgstr[0] "真的要將該元素還原到新目錄中嗎?" #: qt/confirmrestoredialog.py:157 msgid "Really restore this element?" msgid_plural "Really restore these elements?" msgstr[0] "是否確定要恢復所選元素?" #: qt/editusercallback.py:43 #, python-brace-format msgid "User-callback: \"{filename}\"" msgstr "使用者回呼:“{filename}”" #: qt/editusercallback.py:105 #, python-brace-format msgid "" "The user-callback script must include a shebang on the first line (e.g. " "{example})." msgstr "使用者回呼腳本必須在第一行包含一個 shebang(例如 {example})。" #: qt/filedialog.py:87 msgid "Show/hide hidden files and directories (Ctrl+H)" msgstr "顯示/隱藏檔案和目錄(Ctrl+H)" #: qt/languagedialog.py:36 msgid "Setup language" msgstr "設定語言" #: qt/languagedialog.py:120 #, python-brace-format msgid "Translated: {percent}" msgstr "已翻譯: {percent}" #: qt/languagedialog.py:132 msgid "System default" msgstr "系統預設" #: qt/languagedialog.py:142 msgid "Use operating system's language." msgstr "使用作業系統語言。" #: qt/logviewdialog.py:63 msgid "Backup Log View" msgstr "備份日誌視圖" #: qt/logviewdialog.py:63 msgid "Last Log View" msgstr "最後一次日誌查看" #: qt/logviewdialog.py:71 qt/manageprofiles/__init__.py:72 #: qt/manageprofiles/tab_general.py:250 qt/restoreconfigdialog.py:343 msgid "Profile:" msgstr "設定:" #: qt/logviewdialog.py:86 msgid "Backups:" msgstr "備份:" #: qt/logviewdialog.py:93 msgid "Filter:" msgstr "篩選:" #: qt/logviewdialog.py:100 msgid "[E] Error, [I] Information, [C] Change" msgstr "[E] 錯誤,[I] 訊息,[C] 更改" #: qt/logviewdialog.py:103 qt/qtsystrayicon.py:148 msgid "decode paths" msgstr "解碼路徑" #: qt/logviewdialog.py:122 qt/manageprofiles/copylinkswidget.py:56 #: qt/manageprofiles/tab_options.py:188 msgid "All" msgstr "全部" #: qt/logviewdialog.py:128 qt/logviewdialog.py:132 #: qt/manageprofiles/tab_options.py:187 msgid "Changes" msgstr "變化" #: qt/logviewdialog.py:128 qt/logviewdialog.py:131 #: qt/manageprofiles/tab_options.py:186 qt/manageprofiles/tab_options.py:187 msgid "Errors" msgstr "錯誤" #: qt/logviewdialog.py:133 qt/messagebox.py:75 msgid "Information" msgid_plural "Information" msgstr[0] "資訊" #: qt/logviewdialog.py:135 msgid "rsync transfer failures (experimental)" msgstr "rsync 傳輸失敗(實驗性)" #: qt/manageprofiles/__init__.py:64 msgid "Manage profiles" msgstr "管理設定檔" #: qt/manageprofiles/__init__.py:83 msgid "Edit" msgstr "編輯" #: qt/manageprofiles/__init__.py:87 msgid "Add" msgstr "添加" #: qt/manageprofiles/__init__.py:91 qt/manageprofiles/tab_exclude.py:125 #: qt/manageprofiles/tab_include.py:79 msgid "Remove" msgstr "消除" #: qt/manageprofiles/__init__.py:112 msgid "&General" msgstr "&一般的" #: qt/manageprofiles/__init__.py:116 msgid "&Include" msgstr "包含" #: qt/manageprofiles/__init__.py:120 msgid "&Exclude" msgstr "&排除" #: qt/manageprofiles/__init__.py:135 msgid "&Remove & Retention" msgstr "移除 & 保留" #: qt/manageprofiles/__init__.py:139 msgid "&Options" msgstr "選項" #: qt/manageprofiles/__init__.py:143 msgid "E&xpert Options" msgstr "專家選項" #: qt/manageprofiles/__init__.py:151 msgid "Restore Config" msgstr "恢復配置" #: qt/manageprofiles/__init__.py:182 msgid "New profile" msgstr "新增設定檔" #: qt/manageprofiles/__init__.py:199 msgid "Rename profile" msgstr "重新命名設定檔" #: qt/manageprofiles/__init__.py:215 #, python-brace-format msgid "Delete the profile \"{name}\"?" msgstr "確認刪除設定檔\"{name}\"?" #: qt/manageprofiles/copylinkswidget.py:38 msgid "Copy symbolic links as files" msgstr "" #: qt/manageprofiles/copylinkswidget.py:43 msgid "" "Copy symbolic links as real files or directories in the backup. Select " "whether all links or only those pointing outside the source are copied." msgstr "" #: qt/manageprofiles/copylinkswidget.py:46 msgid "This option may increase backup size." msgstr "" #: qt/manageprofiles/copylinkswidget.py:47 msgid "Disabled by default." msgstr "" #: qt/manageprofiles/copylinkswidget.py:60 msgid "" "All symbolic links are replaced with real files or directories they point " "to. This increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:63 msgid "Uses 'rsync --copy-links'." msgstr "" #: qt/manageprofiles/copylinkswidget.py:68 msgid "Only external" msgstr "" #: qt/manageprofiles/copylinkswidget.py:72 msgid "" "Only links pointing outside the backup source are copied as files. This " "increases backup size and may store the same files multiple times." msgstr "" #: qt/manageprofiles/copylinkswidget.py:75 msgid "Uses 'rsync --copy-unsafe-links'." msgstr "" #: qt/manageprofiles/excludesuggestions.py:33 msgid "Editor & Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:34 #, fuzzy msgid "Emacs backup files" msgstr "暫停快照處理" #: qt/manageprofiles/excludesuggestions.py:35 #, fuzzy msgid "Emacs autosave files" msgstr "排除檔案" #: qt/manageprofiles/excludesuggestions.py:36 msgid "Vim swap files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:37 msgid "Microsoft Office temporary files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:40 msgid "LibreOffice & other OpenDocument Editors lock files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:44 msgid "Thumbnails & Temporary Pictures" msgstr "" #: qt/manageprofiles/excludesuggestions.py:47 msgid "Thumbnail cache on GNU/Linux and other unixoid OS'es" msgstr "" #: qt/manageprofiles/excludesuggestions.py:50 msgid "Thumbnail database on Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:51 msgid "Metadata directory on MacOS" msgstr "" #: qt/manageprofiles/excludesuggestions.py:53 msgid "Application-specific locks" msgstr "" #: qt/manageprofiles/excludesuggestions.py:56 msgid "Discord application lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:57 msgid "Discord session lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:60 msgid "Mozilla Firefox & Thunderbird lock file" msgstr "" #: qt/manageprofiles/excludesuggestions.py:62 #, fuzzy msgid "Caches & Temporary directories" msgstr "備份目錄" #: qt/manageprofiles/excludesuggestions.py:63 msgid "User application cache" msgstr "" #: qt/manageprofiles/excludesuggestions.py:64 #: qt/manageprofiles/excludesuggestions.py:67 #, fuzzy msgid "System temporary directory" msgstr "無法刪除目錄" #: qt/manageprofiles/excludesuggestions.py:72 msgid "Package cache for Debian(-based) GNU/Linux distributions" msgstr "" #: qt/manageprofiles/excludesuggestions.py:77 msgid "Flatpak app and runtime repository" msgstr "" #: qt/manageprofiles/excludesuggestions.py:81 #, fuzzy msgid "System runtime directories" msgstr "顯示隱藏檔案" #: qt/manageprofiles/excludesuggestions.py:84 msgid "Kernel and process information" msgstr "" #: qt/manageprofiles/excludesuggestions.py:89 msgid "Device and other hardware information (sysfs interface)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:92 msgid "Device nodes" msgstr "" #: qt/manageprofiles/excludesuggestions.py:93 msgid "Runtime system files" msgstr "" #: qt/manageprofiles/excludesuggestions.py:95 msgid "Other non-persistent" msgstr "" #: qt/manageprofiles/excludesuggestions.py:98 msgid "List of currently mounted filesystems" msgstr "" #: qt/manageprofiles/excludesuggestions.py:101 msgid "System swap file (virtual memory)" msgstr "" #: qt/manageprofiles/excludesuggestions.py:102 msgid "GNOME virtual file system mount point" msgstr "" #: qt/manageprofiles/excludesuggestions.py:103 msgid "Recovered filesystem objects" msgstr "" #: qt/manageprofiles/excludesuggestions.py:105 msgid "Miscellaneous" msgstr "" #: qt/manageprofiles/excludesuggestions.py:108 msgid "Metadata directory on Microsoft Windows" msgstr "" #: qt/manageprofiles/excludesuggestions.py:111 msgid "User recycle bin" msgstr "" #: qt/manageprofiles/excludesuggestions.py:112 #, fuzzy msgid "System backup files" msgstr "停止快照處理" #: qt/manageprofiles/excludesuggestions.py:139 #, fuzzy msgid "Exclude Suggestions" msgstr "排除目錄" #: qt/manageprofiles/excludesuggestions.py:144 msgid "Select commonly used items to add to backup exclusions." msgstr "" #: qt/manageprofiles/excludesuggestions.py:157 #, fuzzy msgid "Default" msgstr "預設" #: qt/manageprofiles/excludesuggestions.py:158 msgid "Reset to predefined selection" msgstr "" #: qt/manageprofiles/schedulewidget.py:38 msgid "Schedule" msgstr "排程" #: qt/manageprofiles/schedulewidget.py:64 msgid "Day:" msgstr "天:" #: qt/manageprofiles/schedulewidget.py:69 msgid "Weekday:" msgstr "工作日:" #: qt/manageprofiles/schedulewidget.py:74 msgid "Time:" msgstr "時間:" #: qt/manageprofiles/schedulewidget.py:79 msgid "Hours:" msgstr "時:" #: qt/manageprofiles/schedulewidget.py:87 msgid "after the hour" msgstr "小時後" #: qt/manageprofiles/schedulewidget.py:89 msgid "Minutes:" msgstr "分鐘:" #: qt/manageprofiles/schedulewidget.py:93 msgid "" "Run Back In Time as soon as the drive is connected (only once every X days)." " A sudo password prompt will appear." msgstr "一旦驅動器連接,立即運行 Back In Time(每 X 天僅一次)。系統將提示您輸入 sudo 密碼。" #: qt/manageprofiles/schedulewidget.py:98 msgid "" "Run Back In Time repeatedly. This is useful if the computer is not running " "regularly." msgstr "反覆運行Back In Time。 如果計算機沒有正常運行,這非常有用。" #: qt/manageprofiles/schedulewidget.py:110 msgid "Every:" msgstr "每天:" #: qt/manageprofiles/schedulewidget.py:114 msgid "Enable logging of debug messages" msgstr "啟用偵錯訊息的日誌記錄" #: qt/manageprofiles/schedulewidget.py:118 msgid "Writes debug-level messages into the system log via \"--debug\"." msgstr "透過“--debug”將偵錯等級訊息寫入系統日誌。" #: qt/manageprofiles/schedulewidget.py:120 msgid "" "Caution: Only use this temporarily for diagnostics, as it generates a large " "amount of output." msgstr "注意:僅臨時使用它進行診斷,因為它會產生大量輸出。" #: qt/manageprofiles/schedulewidget.py:145 msgid "Disabled" msgstr "關閉" #: qt/manageprofiles/schedulewidget.py:146 msgid "At every boot/reboot" msgstr "每次啟動/重新啟動時" #: qt/manageprofiles/schedulewidget.py:148 #: qt/manageprofiles/schedulewidget.py:150 #: qt/manageprofiles/schedulewidget.py:152 #, python-brace-format msgid "Every minute" msgid_plural "Every {n} minutes" msgstr[0] "每{n}分鐘" #: qt/manageprofiles/schedulewidget.py:154 #: qt/manageprofiles/schedulewidget.py:156 #: qt/manageprofiles/schedulewidget.py:158 #: qt/manageprofiles/schedulewidget.py:160 #: qt/manageprofiles/schedulewidget.py:162 #, python-brace-format msgid "Every hour" msgid_plural "Every {n} hours" msgstr[0] "每隔{n}小時" #: qt/manageprofiles/schedulewidget.py:163 msgid "Custom hours" msgstr "客製化時間" #: qt/manageprofiles/schedulewidget.py:164 msgid "Every day" msgstr "每天" #: qt/manageprofiles/schedulewidget.py:165 msgid "Repeatedly (anacron)" msgstr "重複(anacron)" #: qt/manageprofiles/schedulewidget.py:166 msgid "When drive gets connected (udev)" msgstr "當驅動器連接 (udev)" #: qt/manageprofiles/schedulewidget.py:167 msgid "Every week" msgstr "每週" #: qt/manageprofiles/schedulewidget.py:168 msgid "Every month" msgstr "每月" #: qt/manageprofiles/schedulewidget.py:169 msgid "Every year" msgstr "每年" #: qt/manageprofiles/schedulewidget.py:228 msgid "Hour(s)" msgstr "小時" #: qt/manageprofiles/schedulewidget.py:229 #: qt/manageprofiles/tab_remove_retention.py:271 msgid "Day(s)" msgstr "天" #: qt/manageprofiles/schedulewidget.py:230 #: qt/manageprofiles/tab_remove_retention.py:272 msgid "Week(s)" msgstr "週" #: qt/manageprofiles/schedulewidget.py:231 msgid "Month(s)" msgstr "月" #: qt/manageprofiles/schedulewidget.py:326 msgid "" "Custom hours can only be a comma separated list of hours (e.g. 8,12,18,23) " "or */3 for periodic backups every 3 hours." msgstr "自訂時間只能是逗號分隔的時間清單(例如 8,12,18,23)或 */3(每 3 小時定期備份一次)。" #: qt/manageprofiles/sshkeyselector.py:64 msgid "'), _('Choose an existing private key file from somewhere else.'), icon.FOLDER ) # generate key files content_dict[self.ACT_ID_GENERATE_PAIR] = ( _(''), _('Create a new SSH key without passphrase.'), icon.ADD ) super().__init__( parent=parent, content_dict=content_dict ) self._handlers = { self.ACT_ID_SELECT_FILE: select_key_handler, self.ACT_ID_GENERATE_PAIR: generate_pair_handler } self.currentIndexChanged.connect(self._on_selection_changed) self._original_style = None @staticmethod def _key_tooltip(path: Path) -> str: return _('Full path: {path}').format(path=str(path)) def _on_selection_changed(self, _idx): data = self.current_data try: handler = self._handlers[data] except KeyError: return handler() def add_and_select(self, key_path: Path, is_invalid: bool = False): """Add a new entry and select it after that.""" with qttools.block_signals(self): if self.has_data(key_path): self.select_by_data(key_path) else: if is_invalid: self._add_on_top( key_path, 'Invalid or missing: ', 'The key file is missing or somehow invalid.\n' ) else: self._add_on_top(key_path) self.setCurrentIndex(0) self._fade_background() def _add_on_top(self, key_path: Path, prefix: str = '', tooltip_prefix: str = ''): # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 self.insertItem( 0, icon.SSH_KEY_INVALID if prefix else icon.ENCRYPT, f'{prefix}{key_path.name}', userData=key_path ) self.setItemData( 0, SshKeyCombo._key_tooltip(f'{tooltip_prefix}{key_path}'), Qt.ItemDataRole.ToolTipRole ) def _fade_background(self, duration_ms=1200, steps=30): palette = self.palette() high = palette.color(QPalette.ColorRole.Highlight) base = palette.color(QPalette.ColorRole.Base) # Helper vars for color interpolation diff_r = high.red() - base.red() diff_g = high.green() - base.green() diff_b = high.blue() - base.blue() colors = [] # base -> high for curr_step in range(steps//2): colors.append(QColor( base.red() + diff_r * curr_step // steps, base.green() + diff_g * curr_step // steps, base.blue() + diff_b * curr_step // steps)) # Helper vars for color interpolation diff_r = base.red() - high.red() diff_g = base.green() - high.green() diff_b = base.blue() - high.blue() # high -> base for curr_step in range(steps//2, steps): colors.append(QColor( high.red() + diff_r * curr_step // steps, high.green() + diff_g * curr_step // steps, high.blue() + diff_b * curr_step // steps)) colors.append(None) colors = deque(colors) interval = duration_ms // steps self._original_style = self.styleSheet() def update_color(col): if col is None: self.setStyleSheet(self._original_style) return self.setStyleSheet( f'QComboBox {{ background-color: {col.name()}; }}') QTimer.singleShot( interval, partial(update_color, colors.popleft())) update_color(colors.popleft()) class SshKeySelector(QWidget): """Main widget for selecting or generating key files""" def __init__(self, parent: QWidget, select_key_handler: Callable, generate_pair_handler: Callable): super().__init__(parent=parent) # radio: key selector self.radio_key = QRadioButton(_('Private key:')) self.selector = SshKeyCombo( self, select_key_handler, generate_pair_handler) # radio: no key self.radio_no = QRadioButton(_('Use system SSH configuration')) tooltip = _( 'Leaves the key file unselected. SSH connections will rely ' 'on the system’s existing client configuration ' '(e.g., ~/.ssh/config).') qttools.set_wrapped_tooltip(self.radio_no, tooltip) # button group self.btn_group = QButtonGroup(self) self.btn_group.addButton(self.radio_no) self.btn_group.addButton(self.radio_key) # layout row_key = QHBoxLayout() row_key.addWidget(self.radio_key, stretch=0) row_key.addWidget(self.selector, stretch=1) row_no = QHBoxLayout() row_no.addWidget(self.radio_no) layout = QVBoxLayout() layout.addLayout(row_no) layout.addLayout(row_key) # zero margins layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # events self.btn_group.buttonClicked.connect(self._slot_clicked) # default state self.radio_no.setChecked(True) self._slot_clicked(self.radio_no) def _slot_clicked(self, button): self.selector.setEnabled(button == self.radio_key) def add_and_select_key(self, key_path: Path): """Enable the drop down widget and add and select a new entry to it.""" self.selector.add_and_select(key_path) self.radio_key.setChecked(True) def set_key(self, key_path: Path | None) -> None: """Select an existing key based on its path. If not enabled this will also enable the drop down. If path is ``None`` the drop down widget is disabled. """ if key_path: try: self.selector.select_by_data(key_path) except ValueError: # Edge case that should not happen if key_path.exists(): logger.critical( 'Undefined situation: Key path exists but is not ' 'present in the key select widget. ' f'{key_path=}' ) # Add this entry but mark it es invalid self.selector.add_and_select(key_path, True) self.radio_key.setChecked(True) self.btn_group.buttonClicked.emit(self.radio_key) else: self.radio_no.setChecked(True) self.btn_group.buttonClicked.emit(self.radio_no) def get_key(self) -> Path | None: """Return the path of the current selected key or ``None`` if the drop down widget is disabled.""" if self.radio_no.isChecked(): return None if isinstance(self.selector.current_data, Path): return self.selector.current_data return None backintime-1.6.1/qt/manageprofiles/sshproxywidget.py000066400000000000000000000070461514264426600227430ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See file/folder LICENSE or go to # . """A widget to setup an SSH proxy.""" import getpass from PyQt6.QtWidgets import (QVBoxLayout, QHBoxLayout, QWidget, QLabel, QLineEdit, QCheckBox) from PyQt6.QtCore import Qt import qttools class SshProxyWidget(QWidget): """Used in SSH snapshot profiles on the General tab. Dev note by buhtz (2024-04): Just a quick n dirty solution until the re-design and re-factoring of the whole dialog. """ def __init__(self, parent, host, port, user): super().__init__(parent) if host == '': port = '' user = '' elif isinstance(port, int): port = str(port) vlayout = QVBoxLayout(self) # zero margins vlayout.setContentsMargins(0, 0, 0, 0) self._checkbox = QCheckBox(_('SSH Proxy'), self) vlayout.addWidget(self._checkbox) self._checkbox.stateChanged.connect(self._slot_checkbox_changed) hlayout = QHBoxLayout() vlayout.addLayout(hlayout) hlayout.addWidget(QLabel(_('Host:'), self)) self.host_edit = QLineEdit(host, self) hlayout.addWidget(self.host_edit) hlayout.addWidget(QLabel(_('Port:'), self)) self.port_edit = QLineEdit(port, self) hlayout.addWidget(self.port_edit) hlayout.addWidget(QLabel(_('User:'), self)) self.user_edit = QLineEdit(user, self) hlayout.addWidget(self.user_edit) if host == '': self._disable() qttools.set_wrapped_tooltip( self, _('Connect to the target host via this proxy (also known as a ' 'jump host). See "-J" in the "ssh" command documentation or ' '"ProxyJump" in "ssh_config" man page for details.') ) def _slot_checkbox_changed(self, state): if Qt.CheckState(state) == Qt.CheckState.Checked: self._enable() else: self._disable() def _set_default(self): """Set GUI elements back to default.""" self.host_edit.setText('') self.port_edit.setText('22') self.user_edit.setText(getpass.getuser()) def _disable(self): self._set_default() self._enable(False) def _enable(self, enable=True): # QEdit and QLabel's lay = self.layout().itemAt(1) for idx in range(lay.count()): lay.itemAt(idx).widget().setEnabled(enable) def values(self) -> dict[str, str, str]: """The widgets values as a dict. Returns: dict: A 3-item dict with keys "host", "port" and "user". """ if self._checkbox.isChecked(): return { 'host': self.host_edit.text(), 'port': self.port_edit.text(), 'user': self.user_edit.text(), } return { 'host': '', 'port': '', 'user': '', } backintime-1.6.1/qt/manageprofiles/statebindcheckbox.py000066400000000000000000000032031514264426600233130ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module with an improved check box widget.""" from PyQt6.QtWidgets import QCheckBox, QWidget class StateBindCheckBox(QCheckBox): """A check box binding other widgets enabled states to its own check state. If the check box is checked all bound widgets are enabled. If the box is not checked all bound widgets are disabled. """ def __init__(self, text: str, parent: QWidget, bind: QWidget = None): """ Args: text: Label for this check box. parent: The parent widget. bind: One or a list of widgets to bind. """ super().__init__(text=text, parent=parent) self._widgets = [] if bind: self.bind(bind) self.stateChanged.connect(self._slot_state_changed) def bind(self, widget: QWidget) -> None: """The enabled state of `widget` is bound to the check state of the check box. Args: widget: The widget to bind. """ self._widgets.append(widget) self._slot_state_changed(self.isChecked()) def _slot_state_changed(self, state) -> None: """Set the enabled state of each bound widget based on the check state of the box.""" for wdg in self._widgets: wdg.setEnabled(state) backintime-1.6.1/qt/manageprofiles/storagesizewidget.py000066400000000000000000000044231514264426600233770ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See file/folder LICENSE or go to # . """Module with a widget combining a spinbox and a combobox.""" from PyQt6.QtWidgets import QWidget from event import Event from storagesize import StorageSize, SizeUnit from manageprofiles.spinboxunit import SpinBoxWithUnit class StorageSizeWidget(SpinBoxWithUnit): """A combined widget for selected storage size values and their unit. """ def __init__(self, parent: QWidget, range_min_max: tuple[int, int], value: StorageSize = StorageSize(0, SizeUnit.MIB)): content_dict = {unit: str(unit) for unit in SizeUnit} del content_dict[SizeUnit.B] # exclude Bytes super().__init__( parent=parent, range_min_max=range_min_max, content_dict=content_dict, ) self._value = None self.set_storagesize(value) self._combo.currentIndexChanged.connect(self._on_unit_changed) self._spin.valueChanged.connect(self._on_spin_changed) self.event_value_changed = Event() def get_storagesize(self) -> StorageSize: """Current value as StorageSize object.""" val, unit = self.data_and_unit return StorageSize(val, unit) def set_storagesize(self, value: StorageSize, dont_touch_unit: bool = False): """Set value using a StorageSize object.""" if dont_touch_unit: # copy value = StorageSize(value.value(), value.unit) # Use widgets unit value.unit = self.unit() self.set_value(value.value()) self.select_unit(value.unit) self._value = value def _on_spin_changed(self, val): self._value.set_value(val) # Notify observers self.event_value_changed.notify(self._value) def _on_unit_changed(self, _idx): with self.event_value_changed.keep_silent(): self._value.unit = self.unit() self.set_value(self._value.value()) backintime-1.6.1/qt/manageprofiles/tab_exclude.py000066400000000000000000000375611514264426600221240ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # SPDX-FileCopyrightText: © 2025 Devin Black # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about the Exclude tab""" import copy from PyQt6.QtWidgets import (QAbstractItemView, QCheckBox, QDialog, QDialogButtonBox, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QPushButton, QSpinBox, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget) from PyQt6.QtCore import Qt from PyQt6.QtGui import QPalette, QBrush import tools import qttools from qttools import custom_sort_order from filedialog import FileDialog from bitwidgets import HypertextLabel from manageprofiles.excludesuggestions import (ExcludeSuggestionsDialog, EXCLUDE_SUGGESTIONS, get_default_excludes) MATCH_FLAGS = Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive class ExcludeTab(QWidget): """Create the 'Exclude' tab.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): # noqa: PLR0915 # pylint: disable=too-many-statements super().__init__(parent=parent) self._parent_dialog = parent self.icon = parent.icon self.config = parent.config # Snapshot mode self.mode = None layout = QVBoxLayout(self) self.lbl_ssh_encfs_exclude_warning = QLabel(_( "{BOLD}Info{ENDBOLD}: " "In 'SSH encrypted' mode, only single or double asterisks are " "functional (e.g. {example2}). Other types of wildcards and " "patterns will be ignored (e.g. {example1}). Filenames are " "unpredictable in this mode due to encryption by EncFS.").format( BOLD='', ENDBOLD='', example1="'foo*', " "'[fF]oo', " "'fo?'", example2="'foo/*', " "'foo/**/bar'" ), self ) self.lbl_ssh_encfs_exclude_warning.setWordWrap(True) layout.addWidget(self.lbl_ssh_encfs_exclude_warning) self.list_exclude = QTreeWidget(self) self.list_exclude.setSelectionMode( QAbstractItemView.SelectionMode.ExtendedSelection) self.list_exclude.setRootIsDecorated(False) self.list_exclude.setHeaderLabels( [_('Exclude patterns, files or directories'), 'Count']) self.list_exclude.header().setSectionResizeMode( 0, QHeaderView.ResizeMode.Stretch) self.list_exclude.header().setSectionsClickable(True) self.list_exclude.header().setSortIndicatorShown(True) self.list_exclude.header().setSectionHidden(1, True) self.list_exclude_sort_loop = False self.list_exclude.header().sortIndicatorChanged \ .connect(self._exclude_custom_sort_order) layout.addWidget(self.list_exclude) buttons_layout = QHBoxLayout() layout.addLayout(buttons_layout) self.btn_exclude_add = QPushButton( self.icon.ADD, _('Add pattern'), self) buttons_layout.addWidget(self.btn_exclude_add) self.btn_exclude_add.clicked.connect(self.btn_exclude_add_clicked) self.btn_exclude_file = QPushButton( self.icon.ADD, _('Add files'), self) buttons_layout.addWidget(self.btn_exclude_file) self.btn_exclude_file.clicked.connect(self.btn_exclude_file_clicked) self.btn_exclude_folder = QPushButton( self.icon.ADD, _('Add directories'), self) buttons_layout.addWidget(self.btn_exclude_folder) self.btn_exclude_folder.clicked.connect( self.btn_exclude_folder_clicked) self.btn_suggestions = QPushButton( self.icon.DEFAULT_EXCLUDE, _('Suggestions'), self) self.btn_suggestions.setToolTip(_( 'Select from common used items to add to exclude list.')) buttons_layout.addWidget(self.btn_suggestions) self.btn_suggestions.clicked.connect(self.btn_suggestions_clicked) self.btn_exclude_remove = QPushButton( self.icon.REMOVE, _('Remove'), self) buttons_layout.addWidget(self.btn_exclude_remove) self.btn_exclude_remove.clicked.connect( self.btn_exclude_remove_clicked) # exclude files by size hlayout = QHBoxLayout() layout.addLayout(hlayout) self.cb_exclude_by_size = QCheckBox( _('Exclude files bigger than:'), self) qttools.set_wrapped_tooltip( self.cb_exclude_by_size, [ _('Exclude files bigger than value in {size_unit}.') .format(size_unit='MiB'), _("With 'Full rsync mode' disabled, this setting affects only " "newly created files, as rsync treats it as transfer option " "rather than an exclusion rule. Consequently, large files " "that have already been backed up will remain in backups " "even if they are modified.") ] ) hlayout.addWidget(self.cb_exclude_by_size) self.spb_exclude_by_size = QSpinBox(self) self.spb_exclude_by_size.setSuffix(' MiB') self.spb_exclude_by_size.setRange(0, 100000000) hlayout.addWidget(self.spb_exclude_by_size) hlayout.addStretch() # pylint: disable-next=unnecessary-lambda-assignment,unnecessary-lambda enabled = lambda state: \ self.spb_exclude_by_size.setEnabled(state) # noqa enabled(False) self.cb_exclude_by_size.stateChanged.connect(enabled) def load_values(self, profile_state): """Load config values into the GUI""" self.list_exclude.clear() for exclude in self.config.exclude(): self._add_exclude_pattern(exclude) # add defaults if it is a fresh profile if self.config.is_current_profile_unsaved(): for exclude in get_default_excludes(): self._add_exclude_pattern(exclude) self.cb_exclude_by_size.setChecked(self.config.excludeBySizeEnabled()) self.spb_exclude_by_size.setValue(self.config.excludeBySize()) try: excl_sort = profile_state.exclude_sorting self.list_exclude.sortItems( excl_sort[0], Qt.SortOrder(excl_sort[1]) ) except KeyError: pass def store_values(self, profile_state): """Store values from GUI into the config""" # exclude patterns profile_state.exclude_sorting = ( self.list_exclude.header().sortIndicatorSection(), self.list_exclude.header().sortIndicatorOrder().value ) # Sort (optional: replicates original behavior) self.list_exclude.sortItems(1, Qt.SortOrder.AscendingOrder) # Store exclude list exclude_list = [] for index in range(self.list_exclude.topLevelItemCount()): item = self.list_exclude.topLevelItem(index) exclude_list.append(item.text(0)) self.config.setExclude(exclude_list) # Store "exclude by size" settings self.config.setExcludeBySize( self.cb_exclude_by_size.isChecked(), self.spb_exclude_by_size.value() ) return True def _add_exclude_pattern(self, pattern): item = QTreeWidgetItem() item.setText(0, pattern) item.setData(0, Qt.ItemDataRole.UserRole, pattern) self._format_exclude_item(item) # Add item to the widget self.list_exclude.addTopLevelItem(item) return item def btn_exclude_remove_clicked(self): """Handle button click""" for item in self.list_exclude.selectedItems(): index = self.list_exclude.indexOfTopLevelItem(item) if index < 0: continue # means removing item at this index self.list_exclude.takeTopLevelItem(index) if self.list_exclude.topLevelItemCount() > 0: self.list_exclude.setCurrentItem(self.list_exclude.topLevelItem(0)) def add_exclude(self, pattern): """Initiate adding a new exclude pattern to the list widget. See `_add_exclude_pattern()` also. """ if not pattern: return # Duplicate? duplicates = self.list_exclude.findItems(pattern, MATCH_FLAGS) if duplicates: self.list_exclude.setCurrentItem(duplicates[0]) return # Create new entry and add it to the list widget. item = self._add_exclude_pattern(pattern) # Select/highlight that entry. self.list_exclude.setCurrentItem(item) def btn_exclude_add_clicked(self): """Handle button click Dev note (buhtz, 2025-10): Feature idea for later versions. Use rsync --dry-run with --debug=FILTER to see include/exclude decisions. Show them life as preview in the pattern input dialog, for a specific file. Extend this feature to show all include and exclude matches (#734). """ dlg = QDialog(self) dlg.setWindowTitle(_('Exclude pattern')) layout = QVBoxLayout(dlg) layout.addWidget(QLabel(_('Enter an exclude pattern:'))) line_edit = QLineEdit() layout.addWidget(line_edit) label_help = HypertextLabel( label=_( 'For help, see the rsync man page section {link}.' ).format(link='PATTERN MATCHING RULES'), link_slot=self._slot_rsync_pattern_match_link, link_tooltip=_('Open rsync man page') ) layout.addWidget(label_help) buttons = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) buttons.accepted.connect(dlg.accept) buttons.rejected.connect(dlg.reject) layout.addWidget(buttons) if not dlg.exec(): return pattern = line_edit.text().strip() if not pattern: return self.add_exclude(pattern) def _slot_rsync_pattern_match_link(self): qttools.open_man_page('rsync', section='PATTERN MATCHING RULES') def btn_exclude_file_clicked(self): """Handle button click""" dlg = FileDialog( parent=self, title=_('Exclude files'), show_hidden=True, allow_multiselection=True, dirs_only=False) for path in dlg.result(): self.add_exclude(str(path)) def btn_exclude_folder_clicked(self): """Handle button click""" # pylint: disable=duplicate-code dlg = FileDialog(parent=self, title=_('Exclude directories'), show_hidden=True, allow_multiselection=True, dirs_only=True) dirs = dlg.result() for path in dirs: self.add_exclude(str(path)) def _sync_suggestions_check_state(self): """Sync the check state of the suggestions list with the current exclude liste. The check state of suggested exclude items is modified based on the content of the exclude list. Items still in the exclude list are checked and all other are not. """ content = copy.deepcopy(EXCLUDE_SUGGESTIONS) # dict # flat list of suggestions suggestions = [ first_item for group in content.values() for first_item, *_ in group ] # remove suggestions not existent in current exclude list for entry in suggestions[:]: if not self.list_exclude.findItems(entry, MATCH_FLAGS): suggestions.remove(entry) # Modify check state of suggested includes for group, entries in content.items(): for idx, entry in enumerate(entries): check = entry[0] in suggestions content[group][idx][-1] = check return content def btn_suggestions_clicked(self): """Handle button click""" content = self._sync_suggestions_check_state() dlg = ExcludeSuggestionsDialog(self, content) answer = dlg.exec() if answer == QDialog.DialogCode.Rejected: return checked, unchecked = dlg.get_checked_and_unchecked() for entry in checked: self.add_exclude(entry) self._remove_entries(unchecked) def _remove_entries(self, entries: list[str]) -> None: """Remove entries from the exlucde list if existent.""" for entry in entries: # find item items = self.list_exclude.findItems(entry, MATCH_FLAGS) if items: # remove it idx = self.list_exclude.indexOfTopLevelItem(items[0]) self.list_exclude.takeTopLevelItem(idx) def update_exclude_items(self): """Used by parent dialog when profile mode was changed.""" for index in range(self.list_exclude.topLevelItemCount()): item = self.list_exclude.topLevelItem(index) self._format_exclude_item(item) def _format_exclude_item_encfs_invalid(self, item): """Modify visual appearance of an item in the exclude list widget to express that the item is invalid. See :py:func:`_format_exclude_item` for details. """ # Icon item.setIcon(0, self.icon.INVALID_EXCLUDE) # ToolTip item.setData( 0, Qt.ItemDataRole.ToolTipRole, _("Disabled because this pattern is not functional in " "mode 'SSH encrypted'.") ) # Fore- and Backgroundcolor (as disabled) item.setBackground(0, QPalette().brush(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Window)) item.setForeground(0, QPalette().brush(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text)) def _format_exclude_item(self, item): """Modify visual appearance of an item in the exclude list widget. Dev note (2025-12, buhtz): Why not using simple file/dir icons? """ if (self.mode == 'ssh_encfs' and tools.patternHasNotEncryptableWildcard(item.text(0))): # Invalid item (because of encfs restrictions) self._format_exclude_item_encfs_invalid(item) else: # default background color item.setBackground(0, QBrush()) item.setForeground(0, QBrush()) # Remove items tooltip item.setData(0, Qt.ItemDataRole.ToolTipRole, None) # # Icon: default exclude item # if item.text(0) in self.config.DEFAULT_EXCLUDE: # item.setIcon(0, self.icon.DEFAULT_EXCLUDE) # else: # Icon: user defined item.setIcon(0, self.icon.EXCLUDE) def _exclude_custom_sort_order(self, *args): self.list_exclude_sort_loop = custom_sort_order( self.list_exclude.header(), self.list_exclude_sort_loop, *args) backintime-1.6.1/qt/manageprofiles/tab_expert_options.py000066400000000000000000000451421514264426600235470ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """About Export Options tab""" from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QSpinBox, QLineEdit, QCheckBox) import tools from config import Config import qttools import messagebox from manageprofiles.statebindcheckbox import StateBindCheckBox from manageprofiles.copylinkswidget import CopySymlinksWidget from bitwidgets import HLineWidget class ExpertOptionsTab(QDialog): """The 'Expert Options' tab in the Manage Profiles dialog.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): # noqa: PLR0915 # pylint: disable=too-many-statements super().__init__(parent=parent) self._parent_dialog = parent tab_layout = QVBoxLayout(self) # --- initial warning --- txt = _( 'These options are for advanced configurations. Modify ' 'only if fully aware of their implications.' ) label = qttools.create_warning_label(txt) tab_layout.addWidget(label) tab_layout.addWidget(HLineWidget()) # --- rsync with nice --- tab_layout.addWidget(QLabel( _("Run 'rsync' with '{cmd}':").format(cmd='nice'))) grid = QGridLayout() grid.setColumnMinimumWidth(0, 20) # left indent tab_layout.addLayout(grid) self._cb_nice_on_cron = QCheckBox( _('as cron job') + self._default_string(self.config.DEFAULT_RUN_NICE_FROM_CRON), self) grid.addWidget(self._cb_nice_on_cron, 0, 1) self._cb_nice_on_remote = QCheckBox( _('on remote host') + self._default_string(self.config.DEFAULT_RUN_NICE_ON_REMOTE), self) grid.addWidget(self._cb_nice_on_remote, 1, 1) # --- rsync with ionice --- tab_layout.addWidget(QLabel( _("Run 'rsync' with '{cmd}':").format(cmd='ionice'))) grid = QGridLayout() grid.setColumnMinimumWidth(0, 20) tab_layout.addLayout(grid) self._cb_ionice_on_cron = QCheckBox( _('as cron job') + self._default_string(self.config.DEFAULT_RUN_IONICE_FROM_CRON), self) grid.addWidget(self._cb_ionice_on_cron, 0, 1) self._cb_ionice_on_user = QCheckBox( _('when taking a manual backup') + self._default_string(self.config.DEFAULT_RUN_IONICE_FROM_USER), self) grid.addWidget(self._cb_ionice_on_user, 1, 1) self._cb_ionice_on_remote = QCheckBox( _('on remote host') + self._default_string(self.config.DEFAULT_RUN_IONICE_ON_REMOTE), self) grid.addWidget(self._cb_ionice_on_remote, 2, 1) # --- rsync with nocache --- tab_layout.addWidget(QLabel( _("Run 'rsync' with '{cmd}':").format(cmd='nocache'))) grid = QGridLayout() grid.setColumnMinimumWidth(0, 20) tab_layout.addLayout(grid) nocache_available = tools.checkCommand('nocache') if not nocache_available: grid.addWidget( QLabel( '' + _("Please install 'nocache' to enable this option.") + ''), 0, 1) self._cb_nocache_on_local = QCheckBox( _('on local machine') + self._default_string(self.config.DEFAULT_RUN_NOCACHE_ON_LOCAL), self) grid.addWidget(self._cb_nocache_on_local, 1, 1) self._cb_nocache_on_local.setEnabled(nocache_available) self._cb_nocache_on_remote = QCheckBox( _('on remote host') + self._default_string(self.config.DEFAULT_RUN_NOCACHE_ON_REMOTE), self) grid.addWidget(self._cb_nocache_on_remote, 2, 1) # --- redirect output --- self._cb_redirect_stdout_cron = QCheckBox( _('Redirect stdout to /dev/null in cronjobs.') + self._default_string( self.config.DEFAULT_REDIRECT_STDOUT_IN_CRON), self) qttools.set_wrapped_tooltip( self._cb_redirect_stdout_cron, _('Cron will automatically send an email with attached output ' 'of cronjobs if an MTA is installed.') ) tab_layout.addWidget(self._cb_redirect_stdout_cron) self._cb_redirect_stderr_cron = QCheckBox( _('Redirect stderr to /dev/null in cronjobs.') + self._default_string( self.config.DEFAULT_REDIRECT_STDERR_IN_CRON), self) qttools.set_wrapped_tooltip( self._cb_redirect_stderr_cron, _('Cron will automatically send an email with attached errors ' 'of cronjobs if an MTA is installed.') ) tab_layout.addWidget(self._cb_redirect_stderr_cron) # bandwidth limit hlayout = QHBoxLayout() tab_layout.addLayout(hlayout) self._spb_bwlimit = QSpinBox(self) self._spb_bwlimit.setSuffix(' ' + _('KB/sec')) self._spb_bwlimit.setSingleStep(100) self._spb_bwlimit.setRange(0, 1000000) self._cb_bwlimit = StateBindCheckBox( _('Limit rsync bandwidth usage:'), self, self._spb_bwlimit) hlayout.addWidget(self._cb_bwlimit) hlayout.addWidget(self._spb_bwlimit) hlayout.addStretch() qttools.set_wrapped_tooltip( self._cb_bwlimit, [ "Uses 'rsync --bwlimit=RATE'. From 'man rsync':", 'This option allows you to specify the maximum transfer rate ' 'for the data sent over the socket, specified in units per ' 'second. The RATE value can be suffixed with a string to ' 'indicate a size multiplier, and may be a fractional value ' '(e.g. "--bwlimit=1.5m").', 'If no suffix is specified, the value will be assumed to be ' 'in units of 1024 bytes (as if "K" or "KiB" had been ' 'appended).', 'See the --max-size option for a description of all the ' 'available suffixes. A value of zero specifies no limit.' '', 'For backward-compatibility reasons, the rate limit will be ' 'rounded to the nearest KiB unit, so no rate smaller than ' '1024 bytes per second is possible.', '', 'Rsync writes data over the socket in blocks, and this option ' 'both limits the size of the blocks that rsync writes, and ' 'tries to keep the average transfer rate at the requested ' 'limit. Some "burstiness" may be seen where rsync writes out ' 'a block of data and then sleeps to bring the average rate ' 'into compliance.', '', 'Due to the internal buffering of data, the --progress ' 'option may not be an accurate reflection on how fast the ' 'data is being sent. This is because some files can show up ' 'as being rapidly sent when the data is quickly buffered, ' 'while other can show up as very slow when the flushing of ' 'the output buffer occurs. This may be fixed in a future ' 'version.' ] ) self._cb_preserve_acl = QCheckBox(_('Preserve ACL'), self) qttools.set_wrapped_tooltip( self._cb_preserve_acl, [ "Uses 'rsync -A'. From 'man rsync':", 'This option causes rsync to update the destination ACLs to ' 'be the same as the source ACLs. The option also implies ' '--perms.', '', 'The source and destination systems must have compatible ACL ' 'entries for this option to work properly. See the ' '--fake-super option for a way to backup and restore ACLs ' 'that are not compatible.' ] ) tab_layout.addWidget(self._cb_preserve_acl) self._cb_preserve_xattr = QCheckBox( _('Preserve extended attributes (xattr)'), self) qttools.set_wrapped_tooltip( self._cb_preserve_xattr, [ "Uses 'rsync -X'. From 'man rsync':", 'This option causes rsync to update the destination extended ' 'attributes to be the same as the source ones.', '', 'For systems that support extended-attribute namespaces, a ' 'copy being done by a super-user copies all namespaces ' 'except system.*. A normal user only copies the user.* ' 'namespace. To be able to backup and restore non-user ' 'namespaces as a normal user, see the --fake-super option.', '', 'Note that this option does not copy rsyncs special xattr ' 'values (e.g. those used by --fake-super) unless you repeat ' 'the option (e.g. -XX). This "copy all xattrs" mode cannot be ' 'used with --fake-super.' ] ) tab_layout.addWidget(self._cb_preserve_xattr) self._wdg_copy_links = CopySymlinksWidget(self) tab_layout.addWidget(self._wdg_copy_links) # one file system option self._cb_one_filesystem = QCheckBox( _('Restrict to one file system'), self) qttools.set_wrapped_tooltip( self._cb_one_filesystem, [ "Uses 'rsync --one-file-system'. From 'man rsync':", 'This tells rsync to avoid crossing a filesystem boundary ' 'when recursing. This does not limit the user\'s ability ' 'to specify items to copy from multiple filesystems, just ' 'rsync\'s recursion through the hierarchy of each directory ' 'that the user specified, and also the analogous recursion ' 'on the receiving side during deletion. Also keep in mind ' 'that rsync treats a "bind" mount to the same device as ' 'being on the same filesystem.' ] ) tab_layout.addWidget(self._cb_one_filesystem) # additional rsync options tooltip = _('Options must be quoted e.g. {example}.').format( example='--exclude-from="/path/to/my exclude file"') self._txt_rsync_options = QLineEdit(self) self._txt_rsync_options.editingFinished.connect( self._slot_rsync_options_editing_finished) self._txt_rsync_options.setToolTip(tooltip) self._cb_rsync_options = StateBindCheckBox( _('Paste additional options to rsync'), self, self._txt_rsync_options) self._cb_rsync_options.setToolTip(tooltip) # ssh prefix rsync_options_value = '--rsync-path="FOO=bar:\\$FOO /usr/bin/rsync"' tooltip = [ _('Prefix to run before every command on remote host.'), _("Variables need to be escaped with \\$FOO. This doesn't touch " 'rsync. So to add a prefix for rsync use "{example_value}" with ' '{rsync_options_value}.').format( example_value=self._cb_rsync_options.text(), rsync_options_value=rsync_options_value), '', _('default') + ': ' + self.config.DEFAULT_SSH_PREFIX ] self._txt_ssh_prefix = QLineEdit(self) qttools.set_wrapped_tooltip(self._txt_ssh_prefix, tooltip) self._cb_ssh_prefix = StateBindCheckBox( _('Add prefix to SSH commands'), self, self._txt_ssh_prefix) qttools.set_wrapped_tooltip(self._cb_ssh_prefix, tooltip) sub_grid = QGridLayout() sub_grid.addWidget(self._cb_rsync_options, 0, 0) sub_grid.addWidget(self._txt_rsync_options, 0, 1) sub_grid.addWidget(self._cb_ssh_prefix, 1, 0) sub_grid.addWidget(self._txt_ssh_prefix, 1, 1) tab_layout.addLayout(sub_grid) self._cb_ssh_ping = QCheckBox(_('Check if remote host is online')) qttools.set_wrapped_tooltip( self._cb_ssh_ping, _('Warning: If disabled and the remote host is not available, ' 'this could lead to some weird errors.') ) self._cb_ssh_check_commands = QCheckBox( _('Check if remote host supports all necessary commands.')) qttools.set_wrapped_tooltip( self._cb_ssh_check_commands, _('Warning: If disabled and the remote host does not support all ' 'necessary commands, this could lead to some weird errors.') ) tab_layout.addWidget(self._cb_ssh_ping) tab_layout.addWidget(self._cb_ssh_check_commands) tab_layout.addStretch() @property def config(self) -> Config: """The config instance.""" return self._parent_dialog.config def _default_string(self, value: bool) -> str: return ' ' + _('(default: {})').format( _('enabled') if value else _('disabled')) def load_values(self): """Load config values into the GUI""" self._cb_nice_on_cron.setChecked(self.config.niceOnCron()) self._cb_ionice_on_cron.setChecked(self.config.ioniceOnCron()) self._cb_ionice_on_user.setChecked(self.config.ioniceOnUser()) self._cb_nice_on_remote.setChecked(self.config.niceOnRemote()) self._cb_ionice_on_remote.setChecked(self.config.ioniceOnRemote()) self._cb_nocache_on_local.setChecked( self.config.nocacheOnLocal() and self._cb_nocache_on_local.isEnabled()) self._cb_nocache_on_remote.setChecked(self.config.nocacheOnRemote()) self._cb_redirect_stdout_cron.setChecked( self.config.redirectStdoutInCron()) self._cb_redirect_stderr_cron.setChecked( self.config.redirectStderrInCron()) self._cb_bwlimit.setChecked(self.config.bwlimitEnabled()) self._spb_bwlimit.setValue(self.config.bwlimit()) self._cb_preserve_acl.setChecked(self.config.preserveAcl()) self._cb_preserve_xattr.setChecked(self.config.preserveXattr()) all_links = self.config.copyLinks() only_external = self.config.copyUnsafeLinks() self._wdg_copy_links.set_values(all_links, only_external) self._cb_one_filesystem.setChecked(self.config.oneFileSystem()) self._cb_rsync_options.setChecked(self.config.rsyncOptionsEnabled()) self._txt_rsync_options.setText(self.config.rsyncOptions()) self._cb_ssh_prefix.setChecked(self.config.sshPrefixEnabled()) self._txt_ssh_prefix.setText(self.config.sshPrefix()) self._cb_ssh_ping.setChecked(self.config.sshCheckPingHost()) self._cb_ssh_check_commands.setChecked(self.config.sshCheckCommands()) def store_values(self): """Store values from GUI into the config""" self.config.setNiceOnCron(self._cb_nice_on_cron.isChecked()) self.config.setIoniceOnCron(self._cb_ionice_on_cron.isChecked()) self.config.setIoniceOnUser(self._cb_ionice_on_user.isChecked()) self.config.setNiceOnRemote(self._cb_nice_on_remote.isChecked()) self.config.setIoniceOnRemote(self._cb_ionice_on_remote.isChecked()) self.config.setNocacheOnLocal(self._cb_nocache_on_local.isChecked()) self.config.setNocacheOnRemote(self._cb_nocache_on_remote.isChecked()) self.config.setRedirectStdoutInCron( self._cb_redirect_stdout_cron.isChecked()) self.config.setRedirectStderrInCron( self._cb_redirect_stderr_cron.isChecked()) self.config.setBwlimit(self._cb_bwlimit.isChecked(), self._spb_bwlimit.value()) self.config.setPreserveAcl(self._cb_preserve_acl.isChecked()) self.config.setPreserveXattr(self._cb_preserve_xattr.isChecked()) self.config.setCopyLinks(self._wdg_copy_links.all_links) self.config.setCopyUnsafeLinks( self._wdg_copy_links.only_external_links) self.config.setOneFileSystem(self._cb_one_filesystem.isChecked()) self.config.setRsyncOptions(self._cb_rsync_options.isChecked(), self._txt_rsync_options.text()) self.config.setSshPrefix(self._cb_ssh_prefix.isChecked(), self._txt_ssh_prefix.text()) self.config.setSshCheckPingHost(self._cb_ssh_ping.isChecked()) self.config.setSshCheckCommands( self._cb_ssh_check_commands.isChecked()) def update_items_state(self, enabled: bool): """Update state of widgets based on changed profile mode.""" self._cb_nice_on_remote.setEnabled(enabled) self._cb_ionice_on_remote.setEnabled(enabled) self._cb_nocache_on_remote.setEnabled(enabled) self._cb_ssh_prefix.setVisible(enabled) self._txt_ssh_prefix.setVisible(enabled) self._cb_ssh_ping.setVisible(enabled) self._cb_ssh_check_commands.setVisible(enabled) def _slot_rsync_options_editing_finished(self): """When editing the rsync options is finished warn and remove --old-args option if present. """ txt = self._txt_rsync_options.text() if '--old-args' in txt: # No translation for this message because it is a rare case. messagebox.warning( text='Found rsync flag "--old-args". That flag will be removed' ' from the options because it conflicts with the flag "-s" ' '(also known as "--secluded-args" or "--protected-args") which' ' is used by Back In Time to force the "new form of argument ' 'protection" in rsync.', widget_to_center_on=self ) # Don't leave two-blank spaces between other arguments txt = txt.replace('--old-args ', '') txt = txt.replace(' --old-args', '') txt = txt.replace('--old-args', '') self._txt_rsync_options.setText(txt) backintime-1.6.1/qt/manageprofiles/tab_general.py000066400000000000000000000726221514264426600221050ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about the General tab""" import os from pathlib import Path from typing import Any from PyQt6.QtCore import Qt from PyQt6.QtWidgets import (QCheckBox, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QToolButton, QVBoxLayout) from config import Config import tools import logger import sshtools from exceptions import MountException, NoPubKeyLogin, KnownHost import mount from bitbase import URL_ENCRYPT_TRANSITION, DIR_SSH_KEYS import version import schedule import qttools import messagebox # from statedata import StateData from manageprofiles import combobox from manageprofiles import schedulewidget from manageprofiles.sshproxywidget import SshProxyWidget from manageprofiles.sshkeyselector import SshKeySelector from bitwidgets import HLineWidget from filedialog import FileDialog class GeneralTab(QDialog): """Create the 'Generals' tab.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): # noqa: PLR0915 # pylint: disable=too-many-statements super().__init__(parent=parent) self._parent_dialog = parent tab_layout = QVBoxLayout(self) # Snapshot mode self.mode = None vlayout = QVBoxLayout() tab_layout.addLayout(vlayout) self._combo_modes = self._snapshot_mode_combobox() hlayout = QHBoxLayout() hlayout.addWidget(QLabel(_('Mode:'), self)) hlayout.addWidget(self._combo_modes, 1) vlayout.addLayout(hlayout) # EncFS deprecation (#1734, #1735) self._lbl_encfs_warning = self._create_label_encfs_deprecation() tab_layout.addWidget(self._lbl_encfs_warning) tab_layout.addWidget(HLineWidget()) # Where to save snapshots group_box = QGroupBox(self) self._group_mode_local = group_box group_box.setTitle(_('Where to save backups')) tab_layout.addWidget(group_box) vlayout = QVBoxLayout(group_box) hlayout = QHBoxLayout() vlayout.addLayout(hlayout) self._edit_backup_path = QLineEdit(self) self._edit_backup_path.setReadOnly(True) self._edit_backup_path.textChanged.connect( self._slot_full_path_changed) hlayout.addWidget(self._edit_backup_path) self._btn_backup_path = QToolButton(self) self._btn_backup_path.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonIconOnly) self._btn_backup_path.setIcon(self.icon.FOLDER) self._btn_backup_path.setMinimumSize(32, 28) hlayout.addWidget(self._btn_backup_path) self._btn_backup_path.clicked.connect( self._slot_snapshots_path_clicked) # --- SSH --- group_box = QGroupBox(self) self._group_mode_ssh = group_box group_box.setTitle(_('SSH Settings')) tab_layout.addWidget(group_box) vlayout = QVBoxLayout(group_box) hlayout1 = QHBoxLayout() vlayout.addLayout(hlayout1) hlayout2 = QHBoxLayout() vlayout.addLayout(hlayout2) # hlayout3 = QHBoxLayout() # vlayout.addLayout(hlayout3) self._lbl_ssh_host = QLabel(_('Host:'), self) hlayout1.addWidget(self._lbl_ssh_host) self._txt_ssh_host = QLineEdit(self) hlayout1.addWidget(self._txt_ssh_host) self._lbl_ssh_port = QLabel(_('Port:'), self) hlayout1.addWidget(self._lbl_ssh_port) self._txt_ssh_port = QLineEdit(self) hlayout1.addWidget(self._txt_ssh_port) self._lbl_ssh_user = QLabel(_('User:'), self) hlayout1.addWidget(self._lbl_ssh_user) self._txt_ssh_user = QLineEdit(self) hlayout1.addWidget(self._txt_ssh_user) self._lbl_ssh_path = QLabel(_('Path:'), self) hlayout2.addWidget(self._lbl_ssh_path) self._txt_ssh_path = QLineEdit(self) self._txt_ssh_path.textChanged.connect(self._slot_full_path_changed) hlayout2.addWidget(self._txt_ssh_path) group_box = QGroupBox(self) group_box.setTitle(_('Key file:')) group_layout = QVBoxLayout() group_box.setLayout(group_layout) self.key_selector = SshKeySelector( self, self._slot_ssh_private_key_file_clicked, self._slot_ssh_key_gen_clicked ) group_layout.addWidget(self.key_selector) vlayout.addWidget(group_box) # Align the width of that three labels width = max( self._lbl_ssh_host.sizeHint().width(), self._lbl_ssh_path.sizeHint().width() ) self._lbl_ssh_host.setMinimumWidth(width) self._lbl_ssh_path.setMinimumWidth(width) self._wdg_ssh_proxy = SshProxyWidget( self, self.config.sshProxyHost(), self.config.sshProxyPort(), self.config.sshProxyUser() ) vlayout.addWidget(self._wdg_ssh_proxy) # encfs self._group_mode_local_encfs = self._group_mode_local self._group_mode_ssh_encfs = self._group_mode_ssh # gocryptfs self._group_mode_local_gocrypt = self._group_mode_local # password group_box = QGroupBox(self) self._group_password1 = group_box group_box.setTitle(_('Password')) tab_layout.addWidget(group_box) vlayout = QVBoxLayout(group_box) grid = QGridLayout() # Used for SSH passphrase & Encfs password self._lbl_password1 = QLabel(_('Password'), self) self._txt_password1 = QLineEdit(self) self._txt_password1.setEchoMode(QLineEdit.EchoMode.Password) # Used for Encfs password in "ssh encrypted" mode *rofl* self._lbl_password2 = QLabel(_('Password'), self) self._txt_password2 = QLineEdit(self) self._txt_password2.setEchoMode(QLineEdit.EchoMode.Password) # DEBUG if logger.DEBUG or version.IS_UNSTABLE_DEV_VERSION: self._lbl_password1.setToolTip('DEBUG - password 1') self._txt_password1.setToolTip('DEBUG - password 1') self._lbl_password2.setToolTip('DEBUG - password 2') self._txt_password2.setToolTip('DEBUG - password 2') grid.addWidget(self._lbl_password1, 0, 0) grid.addWidget(self._txt_password1, 0, 1) grid.addWidget(self._lbl_password2, 1, 0) grid.addWidget(self._txt_password2, 1, 1) vlayout.addLayout(grid) self._cb_password_save = QCheckBox(_('Save Password to Keyring'), self) vlayout.addWidget(self._cb_password_save) self._cb_password_use_cache = QCheckBox( _('Cache Password for Cron (Security ' 'issue: root can read password)'), self ) vlayout.addWidget(self._cb_password_use_cache) self._keyring_supported = tools.keyringSupported() self._cb_password_save.setEnabled(self._keyring_supported) # mode change self._combo_modes.currentIndexChanged.connect( self._parent_dialog.slot_combo_modes_changed) # host, user, profile id group_box = QGroupBox(self) self._frame_advanced = group_box group_box.setTitle(_('Advanced')) tab_layout.addWidget(group_box) hlayout = QHBoxLayout(group_box) hlayout.addSpacing(12) vlayout2 = QVBoxLayout() hlayout.addLayout(vlayout2) hlayout2 = QHBoxLayout() vlayout2.addLayout(hlayout2) self._lbl_host = QLabel(_('Host:'), self) hlayout2.addWidget(self._lbl_host) self._txt_host = QLineEdit(self) self._txt_host.textChanged.connect(self._slot_full_path_changed) hlayout2.addWidget(self._txt_host) self._lbl_user = QLabel(_('User:'), self) hlayout2.addWidget(self._lbl_user) self._txt_user = QLineEdit(self) self._txt_user.textChanged.connect(self._slot_full_path_changed) hlayout2.addWidget(self._txt_user) self._lbl_profile = QLabel(_('Profile:'), self) hlayout2.addWidget(self._lbl_profile) self.txt_profile = QLineEdit(self) self.txt_profile.textChanged.connect(self._slot_full_path_changed) hlayout2.addWidget(self.txt_profile) self._lbl_full_path = QLabel(_('Full backup path:'), self) self._lbl_full_path.setWordWrap(True) vlayout2.addWidget(self._lbl_full_path) self._wdg_schedule = schedulewidget.ScheduleWidget(self) if schedule.CRONTAB_COMMAND is None: lbl_warning = qttools.create_info_label( text=_('Scheduling is disabled because no cron installation ' 'was found. Please install cron to enable scheduled ' 'backups.') ) tab_layout.addWidget(lbl_warning) self._wdg_schedule.setHidden(True) tab_layout.addWidget(self._wdg_schedule) tab_layout.addStretch() @property def mode(self) -> str: """The backup mode""" return self._parent_dialog.mode @mode.setter def mode(self, value: str) -> None: self._parent_dialog.mode = value @property def config(self) -> Config: """The config instance""" return self._parent_dialog.config @property def icon(self): """Workaround. Remove until import of icon module is solved.""" return self._parent_dialog.icon def _load_passwords(self): """A workaround to fix #2093 until the widgets are refactored and redesigned. """ # password password_1 = self.config.password( mode=self.mode, pw_id=1, only_from_keyring=True) password_2 = self.config.password( mode=self.mode, pw_id=2, only_from_keyring=True) if password_1 is None: password_1 = '' if password_2 is None: password_2 = '' self._txt_password1.setText(password_1) self._txt_password2.setText(password_2) self._cb_password_save.setChecked( self._keyring_supported and self.config.passwordSave(mode=self.mode) ) self._cb_password_use_cache.setChecked( self.config.passwordUseCache(mode=self.mode)) def load_values(self) -> Any: """Set the values of the widgets regarding the current config.""" backup_mode = self.config.snapshotsMode() self._combo_modes.select_by_data(backup_mode) # If the profile us an deprecated backup mode (#1734) if 'encfs' in backup_mode: self._combo_modes.unhide_by_data(backup_mode) # local self._edit_backup_path.setText( self.config.snapshotsPath(mode='local')) # SSH self._txt_ssh_host.setText(self.config.sshHost()) self._txt_ssh_port.setText(str(self.config.sshPort())) self._txt_ssh_user.setText(self.config.sshUser()) self._txt_ssh_path.setText(self.config.sshSnapshotsPath()) # SSH: Priate key file val = self.config.sshPrivateKeyFile() if val is False: # using key is disabled val = None elif val is None: # Select key by default if present try: val = sshtools.get_private_ssh_key_files()[0] except IndexError: # no key available pass self.key_selector.set_key(Path(val) if val else val) # local_encfs if self.mode == 'local_encfs': self._edit_backup_path.setText(self.config.localEncfsPath()) # local_gocryptfs if self.mode == 'local_gocryptfs': self._edit_backup_path.setText(self.config.localGocryptfsPath()) self._load_passwords() host, user, profile = self.config.hostUserProfile() self._txt_host.setText(host) self._txt_user.setText(user) self.txt_profile.setText(profile) # Schedule self._wdg_schedule.load_values(self.config) def _store_local_gocryptfs_destination_path(self) -> bool: """Path and password related to local gocryptfs profile. """ # save local_gocryptfs if self.get_active_snapshots_mode() != 'local_gocryptfs': return True # backup path path = self._edit_backup_path.text() if path and Path(path).exists(): self.config.setLocalGocryptfsPath(path) else: messagebox.warning( _('The backup destination path cannot be empty.'), _('Where to save backups'), self ) return False # password password_1 = self._txt_password1.text() if not password_1: messagebox.warning( _('The encryption password cannot be empty.'), _('Encryption'), self ) return False return True def store_values(self) -> bool: """Store the tab's values into the config instance. Returns: bool: Success or not. """ mode = self.get_active_snapshots_mode() self.config.setSnapshotsMode(mode) # passwords password_1 = self._txt_password1.text() password_2 = self._txt_password2.text() mount_kwargs = {} if mode in ('ssh', 'local_encfs'): mount_kwargs = {'password': password_1} elif mode == 'ssh_encfs': mount_kwargs = {'ssh_password': password_1, 'encfs_password': password_2} self.config.setHostUserProfile( self._txt_host.text(), self._txt_user.text(), self.txt_profile.text() ) # SSH self.config.setSshHost(self._txt_ssh_host.text()) self.config.setSshPort(self._txt_ssh_port.text()) self.config.setSshUser(self._txt_ssh_user.text()) sshproxy_vals = self._wdg_ssh_proxy.values() self.config.setSshProxyHost(sshproxy_vals['host']) self.config.setSshProxyPort(sshproxy_vals['port']) self.config.setSshProxyUser(sshproxy_vals['user']) self.config.setSshSnapshotsPath(self._txt_ssh_path.text()) # SSH key file if mode in ('ssh', 'ssh_encfs'): key_file = self.key_selector.get_key() self.config.setSshPrivateKeyFile(str(key_file) if key_file else '') # save local_encfs self.config.setLocalEncfsPath(self._edit_backup_path.text()) # _gocryptfs: path & password if self._store_local_gocryptfs_destination_path() is False: return False # schedule success = self._wdg_schedule.store_values(self.config) if success is False: return False # save password self.config.setPasswordSave(self._cb_password_save.isChecked(), mode=mode) self.config.setPasswordUseCache( self._cb_password_use_cache.isChecked(), mode=mode) self.config.setPassword(password_1, mode=mode) self.config.setPassword(password_2, mode=mode, pw_id=2) if mode != 'local': mnt = mount.Mount(cfg=self.config, tmp_mount=True, parent=self) hash_id = self._do_alot_pre_mount_checking(mnt, mount_kwargs) if hash_id is False: return False # snaphots_path if mode == 'local': self.config.set_snapshots_path(self._edit_backup_path.text()) snapshots_mountpoint = self.config.get_snapshots_mountpoint( tmp_mount=True) success = tools.validate_and_prepare_snapshots_path( path=snapshots_mountpoint, host_user_profile=self.config.hostUserProfile(), mode=mode, copy_links=self.config.copyLinks(), error_handler=self.config.notifyError) if success is False: return False # umount if mode != 'local': try: mnt.umount(hash_id=hash_id) except MountException as ex: messagebox.critical(self, str(ex)) return False return True def _do_alot_pre_mount_checking(self, mnt, mount_kwargs): # noqa: PLR0911 """Initiate several checks related to mounting and similar tasks. Depending on the backup mode used different checks are initiated. Dev note (buhtz, 2024-09): The code is parked and ready to refactoring. Returns: bool: ``True`` if successful otherwise ``False``. """ # pylint: disable=too-many-return-statements try: mode = self.config.snapshotsMode() if 'gocryptfs' in mode: if not mnt.get_backend(mode).isConfigured(): mnt.init_backend(mode=mode, **mount_kwargs) except MountException as ex: messagebox.critical(self, str(ex)) return False try: # This will run several checks depending on the snapshots mode # used. Exceptions are raised if something goes wrong. On mode # "local" nothing is checked. mnt.preMountCheck( mode=self.config.snapshotsMode(), first_run=True, **mount_kwargs) except NoPubKeyLogin as ex: logger.error(str(ex), self) if not self.config.sshPrivateKeyFile_enabled(): # Configured without explicit SSH key file messagebox.critical(self, str(ex)) return False question = ( '

' + _('An error occurred while attempting to log in to ' 'the remote host. The following error message was ' 'returned:') + '

' + str(ex) + '

' + _('To enable password-less login, the public SSH key can be ' 'copied to the remote host.') + '

' + _('Proceed with copying the SSH key?') + '

' ) answer = messagebox.warning(text=question, as_question=True) if not answer: return False rc_copy_id = sshtools.sshCopyId( self.config.sshPrivateKeyFile() + '.pub', self.config.sshUser(), self.config.sshHost(), port=str(self.config.sshPort()), proxy_user=self.config.sshProxyUser(), proxy_host=self.config.sshProxyHost(), proxy_port=self.config.sshProxyPort(), # This will open an extra input dialog to ask for the # SSH password. askPass=tools.which('backintime-askpass'), cipher=self.config.sshCipher() ) if not rc_copy_id: messagebox.warning(_( 'The public SSH key could not be copied. This may ' 'be due to a connection or permission issue.' )) return False # --- DEV NOTE TODO --- # Why this recursive call? return self._parent_dialog.save_profile() except KnownHost as ex: logger.error(str(ex), self) fingerprint, hashed_key, key_type = sshtools.sshHostKey( host=self.config.sshHost(), port=str(self.config.sshPort())) if not fingerprint: messagebox.critical(self, str(ex)) return False msg = ( '

' + _("The authenticity of host {host} can't be " "established.").format(host=self.config.sshHost()) + '

' + _('{keytype} key fingerprint is:').format(keytype=key_type) + '

' + fingerprint + '

' + _('Please verify this fingerprint. Add it to the ' '"known_hosts" file?') + '

' ) if messagebox.question(msg): sshtools.writeKnownHostsFile(hashed_key) # --- DEV NOTE TODO --- # AGAIN: Why this recursive call? return self.saveProfile() return False except MountException as ex: messagebox.critical(self, str(ex)) return False # okay, let's try to mount try: hash_id = mnt.mount( mode=self.config.snapshotsMode(), check=False, **mount_kwargs) except MountException as ex: messagebox.critical(self, str(ex)) return False return hash_id def _snapshot_mode_combobox(self) -> combobox.BitComboBox: # Workaround until encryption transition (#1734) is finished. # # Find out if profiles using EncFS # all_used_modes = { # self.config.snapshotsMode(pid) for pid in self.config.profiles() # } # print(f'{all_used_modes=}') # DEBUG snapshot_modes = {} for key in self.config.SNAPSHOT_MODES: snapshot_modes[key] = self.config.SNAPSHOT_MODES[key][1] return combobox.BitComboBox(self, snapshot_modes) def _create_label_encfs_deprecation(self): # encfs deprecation warning (see #1734, #1735) whitepaper = f'' whitepaper = whitepaper + 'whitepaper' + '' txt = [ 'Encrypted profiles using EncFS are no longer ' 'supported.', 'New EncFS backup profiles can not be created anymore. ' 'Existing EncFS profiles are still displayed and ' 'supported for now, but EncFS support will be ' 'completely removed in a future release ' '(expected around 2027).', 'EncFS is considered insecure and is no longer actively ' 'maintained. For more information, see this ' f'{whitepaper}.' ] txt = '

' + '

'.join(txt) + '

' return qttools.create_warning_label(txt, icon_scale_factor=3) def _slot_snapshots_path_clicked(self): old_path = Path(self._edit_backup_path.text()) dlg = FileDialog( parent=self, title=_('Where to save backups'), show_hidden=True, allow_multiselection=False, dirs_only=True, start_dir=old_path) path = dlg.result() # nothing selected (Cancel) if not path: return # nothing changed if old_path and old_path == path: return # gocryptfs destination need to be empty if 'gocryptfs' in self.mode: # is not empty if not self._is_gocryptfs_path_empty(path): return # Really change? answer = messagebox.question( text=_('Really change the backup directory?'), widget_to_center_on=self) if not answer: return # Set the path self._edit_backup_path.setText(str(path)) def _is_gocryptfs_path_empty(self, path: Path) -> bool: # is not empty if not any(path.iterdir()): return True messagebox.warning( '

' + _('The selected backup destination is not empty.') + '

' + _('It must be empty to use encryption.') + '

', widget_to_center_on=self ) return False def _slot_ssh_private_key_file_clicked(self): key_file = self.key_selector.get_key() if key_file: start_dir = key_file.parent else: start_dir = DIR_SSH_KEYS file_dialog = FileDialog( parent=self, title=_('SSH private key'), start_dir=start_dir, allow_multiselection=False ) key_file = file_dialog.result() if not key_file: return # No public key if key_file.suffix.lower() == '.pub': title = _('Invalid file: Not a private SSH key') msg = _('The selected file ({path}) is a public SSH key. ' 'Please choose the corresponding private key file instead ' '(without ".pub").').format(path=key_file) messagebox.warning(msg, title, self) return # self.txtSshPrivateKeyFile.setText(str(key_file)) self.key_selector.add_and_select_key(key_file) def _slot_ssh_key_gen_clicked(self): default_keyfile_name = sshtools.determine_default_ssh_key_filename() if not default_keyfile_name: msg = 'Unable to determine the default filename for new ' \ 'generated ssh keys used by "ssh-keygen".' logger.critical(msg) messagebox.critical(self, msg) return key_file_path = DIR_SSH_KEYS / default_keyfile_name if key_file_path.exists(): msg = _('The file {path} already exists. Cannot create a new ' 'SSH key with that name.').format(path=key_file_path) messagebox.critical(self, msg) return # Generate the key if sshtools.sshKeyGen(str(key_file_path)): self.key_selector.add_and_select_key(key_file_path) return msg = _('Failed to create new SSH key in {path}.') \ .format(path=key_file_path) messagebox.critical(self, msg) def _slot_full_path_changed(self, _text: Any): if self.mode in ('ssh', 'ssh_encfs'): path = self._txt_ssh_path.text() else: path = self._edit_backup_path.text() self._lbl_full_path.setText( _('Full backup path:') + ' ' + os.path.join( path, 'backintime', self._txt_host.text(), self._txt_user.text(), self.txt_profile.text() )) def get_active_snapshots_mode(self) -> str: """Current profile mode""" return self._combo_modes.current_data def handle_combo_modes_changed(self): """Hide/show widget elements related to one of the four snapshot modes. This is not a slot connected to a signal. But it is called by the parent dialog. """ # Mode selected in the combo box active_mode = self.get_active_snapshots_mode() # state_data = StateData() # profile_state = state_data.profile(self.config.currentProfile()) # New selected mode different from previous one? if active_mode != self.mode: self.mode = active_mode self._group_mode_local.setVisible( active_mode in ('local', 'local_encfs', 'local_gocryptfs')) self._group_mode_ssh.setVisible( active_mode in ('ssh', 'ssh_encfs')) self._wdg_schedule.allow_udev( active_mode in ('local', 'local_encfs', 'local_gocryptfs')) # gocryptfs destination need to be empty if 'gocryptfs' in self.mode: path = self._edit_backup_path.text() # dir exists and is not empty if path and any(Path(path).iterdir()): self._edit_backup_path.setText('') # Don't offer deprecated modes (#1734) modes_to_hide = {'local_encfs', 'ssh_encfs'} - {active_mode} for hide in modes_to_hide: self._combo_modes.hide_by_data(hide) # A mode using password fields? if self.config.modeNeedPassword(active_mode): self._lbl_password1.setText( self.config.SNAPSHOT_MODES[active_mode][2] + ':') self._group_password1.show() if self.config.modeNeedPassword(active_mode, 2): self._lbl_password2.setText( self.config.SNAPSHOT_MODES[active_mode][3] + ':') self._lbl_password2.show() self._txt_password2.show() else: self._lbl_password2.hide() self._txt_password2.hide() self._load_passwords() else: self._group_password1.hide() # EncFS deprecation warnings (see #1734) if active_mode in ('local_encfs', 'ssh_encfs'): self._lbl_encfs_warning.show() # # Workaround to avoid showing the warning messagebox just when # # opening the manage profiles dialog. # if self._parent_dialog.isVisible(): # # Show the profile specific warning dialog only once per # # profile. # if profile_state.msg_encfs < ENCFS_MSG_STAGE: # profile_state.msg_encfs = ENCFS_MSG_STAGE # dlg = encfsmsgbox.EncfsCreateWarning(self) # dlg.exec() else: self._lbl_encfs_warning.hide() backintime-1.6.1/qt/manageprofiles/tab_include.py000066400000000000000000000176241514264426600221140ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # SPDX-FileCopyrightText: © 2025 Devin Black # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """The IncludeTab class for managing include paths""" from pathlib import Path from PyQt6.QtCore import Qt from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QTreeWidget, QTreeWidgetItem, QPushButton, QHeaderView, QAbstractItemView) from qttools import custom_sort_order from filedialog import FileDialog class IncludeTab(QWidget): """Tab for managing include files and directories.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): super().__init__(parent=parent) self._parent_dialog = parent self.icon = parent.icon self.config = parent.config layout = QVBoxLayout(self) self.list_include = QTreeWidget(self) self.list_include.setSelectionMode( QAbstractItemView.SelectionMode.ExtendedSelection ) self.list_include.setRootIsDecorated(False) self.list_include.setHeaderLabels([ _('Include files and directories'), 'Count' ]) self.list_include.header().setSectionResizeMode( 0, QHeaderView.ResizeMode.Stretch ) self.list_include.header().setSectionsClickable(True) self.list_include.header().setSortIndicatorShown(True) self.list_include.header().setSectionHidden(1, True) layout.addWidget(self.list_include) self.list_include_count = 0 self.list_include_sort_loop = False self.list_include.header().sortIndicatorChanged.connect( self.include_custom_sort_order ) buttons_layout = QHBoxLayout() layout.addLayout(buttons_layout) self.btn_include_file = QPushButton( self.icon.ADD, _('Add files'), self) buttons_layout.addWidget(self.btn_include_file) self.btn_include_file.clicked.connect(self.btn_include_file_clicked) self.btn_include_add = QPushButton( self.icon.ADD, _('Add directories'), self ) buttons_layout.addWidget(self.btn_include_add) self.btn_include_add.clicked.connect(self.btn_include_add_clicked) self.btn_include_remove = QPushButton( self.icon.REMOVE, _('Remove'), self ) buttons_layout.addWidget(self.btn_include_remove) self.btn_include_remove.clicked.connect( self.btn_include_remove_clicked ) def load_values(self, profile_state): """Load config values into the GUI""" self.list_include.clear() for include in self.config.include(): self.add_include(include) try: incl_sort = profile_state.include_sorting self.list_include.sortItems( incl_sort[0], Qt.SortOrder(incl_sort[1]) ) except KeyError: pass def store_values(self, profile_state): """Store values from GUI into the config""" profile_state.include_sorting = ( self.list_include.header().sortIndicatorSection(), self.list_include.header().sortIndicatorOrder().value ) self.list_include.sortItems(1, Qt.SortOrder.AscendingOrder) include_list = [] for index in range(self.list_include.topLevelItemCount()): item = self.list_include.topLevelItem(index) include_list.append( (item.text(0), item.data(0, Qt.ItemDataRole.UserRole)) ) self.config.setInclude(include_list) def add_include(self, data): """Add a file or directory to the list.""" item = QTreeWidgetItem() icon = self.icon.FOLDER if data[1] == 0 else self.icon.FILE item.setIcon(0, icon) duplicates = self.list_include.findItems( data[0], Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive ) if duplicates: self.list_include.setCurrentItem(duplicates[0]) return item.setText(0, data[0]) item.setData(0, Qt.ItemDataRole.UserRole, data[1]) self.list_include_count += 1 item.setText(1, str(self.list_include_count).zfill(6)) item.setData(1, Qt.ItemDataRole.UserRole, self.list_include_count) self.list_include.addTopLevelItem(item) self.list_include.setCurrentItem(item) def btn_include_remove_clicked(self): """Handle removal of selected include entries.""" for item in self.list_include.selectedItems(): index = self.list_include.indexOfTopLevelItem(item) if index >= 0: self.list_include.takeTopLevelItem(index) if self.list_include.topLevelItemCount() > 0: self.list_include.setCurrentItem(self.list_include.topLevelItem(0)) def _copy_links_or_unsafe_links(self) -> bool: """Return `True` if one of the two Expert Options "Copy links" and "Copy unsafe links" are set/checked. Dev note (buhtz, 2025-10): The values from config are used. Keep in mind that these do not have to reflect the check boxes in the Expert Options TAB. Modifications in those checkboxes are not stored to config immediatel but only after clicking OK to the Manage Profiles dialog. This behavior of the dialog need to be changed. """ return self.config.copyUnsafeLinks() or self.config.copyLinks() def _ask_include_symlinks_target(self, path: Path): question_msg = _( '"{path}" is a symlink. The linked target will not be backed up ' 'until it is included, too.').format(path=path) question_msg = question_msg + '\n' + _( "Include the symlink's target instead?") return self._parent_dialog.questionHandler(question_msg) def btn_include_file_clicked(self): """Handle file-adding button click.""" dlg = FileDialog( parent=self, title=_('Include files'), show_hidden=True, allow_multiselection=True, dirs_only=False) for path in dlg.result(): if not path: continue if path.is_symlink() and not self._copy_links_or_unsafe_links(): if self._ask_include_symlinks_target(path): path = path.resolve() self.add_include((str(path), 1)) def btn_include_add_clicked(self): """Handle directory-adding button click.""" # pylint: disable=duplicate-code dlg = FileDialog(parent=self, title=_('Include directories'), show_hidden=True, allow_multiselection=True, dirs_only=True) for path in dlg.result(): if not path: continue if path.is_symlink() and not self._copy_links_or_unsafe_links(): if self._ask_include_symlinks_target(path): path = path.resolve() self.add_include((str(path), 0)) def include_custom_sort_order(self, *args): """Trigger custom sort order when header is clicked.""" self.list_include_sort_loop = custom_sort_order( self.list_include.header(), self.list_include_sort_loop, *args ) backintime-1.6.1/qt/manageprofiles/tab_options.py000066400000000000000000000173521514264426600221620ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about the Options tab""" from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QCheckBox) from config import Config import tools from event import Event import qttools from manageprofiles import combobox from manageprofiles.statebindcheckbox import StateBindCheckBox from manageprofiles.storagesizewidget import StorageSizeWidget class OptionsTab(QDialog): """The 'Options' tab in the Manage Profiles dialog.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): super().__init__(parent=parent) self._parent_dialog = parent tab_layout = QVBoxLayout(self) self._cb_notify = QCheckBox(_('Enable notifications'), self) tab_layout.addWidget(self._cb_notify) self._cb_no_backup_on_battery \ = QCheckBox(_('Disable backups when on battery'), self) tab_layout.addWidget(self._cb_no_backup_on_battery) if not tools.powerStatusAvailable(): self._cb_no_backup_on_battery.setEnabled(False) self._cb_no_backup_on_battery.setToolTip( _('Power status not available from system')) self._cb_one_backup_at_a_time \ = QCheckBox(_('Run only one backup at a time')) tab_layout.addWidget(self._cb_one_backup_at_a_time) qttools.set_wrapped_tooltip( self._cb_one_backup_at_a_time, _('Other backups will be blocked until the current backup is ' 'completed. This is a global setting, meaning it will affect ' 'all profiles for this user. However, it must also be ' 'activated for all other users.') ) self._cb_backup_on_restore = QCheckBox( _('Backup replaced files on restore'), self) tab_layout.addWidget(self._cb_backup_on_restore) backup_suffix = self._parent_dialog.snapshots.backupSuffix() qttools.set_wrapped_tooltip( self._cb_backup_on_restore, [ _("Before restoring, newer versions of files will be renamed " "with the appended {suffix}. These files can be removed " "with the following command:").format( suffix=backup_suffix), f'find ./ -name "*{backup_suffix}" -delete' ] ) self._cb_continue_on_errors = QCheckBox( _('Continue on errors (keep incomplete backups)'), self) tab_layout.addWidget(self._cb_continue_on_errors) self._cb_use_checksum = QCheckBox( _('Use checksum to detect changes'), self) tab_layout.addWidget(self._cb_use_checksum) self._cb_backup_regard_changes = QCheckBox( _('Create a new backup whether there were changes or not.')) tab_layout.addWidget(self._cb_backup_regard_changes) # warn free space hlayout = QHBoxLayout() tab_layout.addLayout(hlayout) self._su_warn_free_space = StorageSizeWidget(self, (1, 9999999)) self._cb_warn_free_space = StateBindCheckBox( _('Warn if the free disk space falls below'), self) self._cb_warn_free_space.bind(self._su_warn_free_space) hlayout.addWidget(self._cb_warn_free_space) hlayout.addWidget(self._su_warn_free_space) tooltip = [ _('Shows a warning when free space on the backup destination disk ' 'is less than the specified value.'), _('If the Remove & Retention policy is enabled and old backups ' 'are removed based on available free space, this value cannot ' 'be lower than the value set in the policy.') ] qttools.set_wrapped_tooltip(self._su_warn_free_space, tooltip) qttools.set_wrapped_tooltip(self._cb_warn_free_space, tooltip) # Event: Notify observers if "remove less free space" value has changed self.event_warn_free_space_value_changed = Event() # pylint: disable=unnecessary-lambda self._su_warn_free_space.event_value_changed.register( lambda value: # noqa: PLW0108 self.event_warn_free_space_value_changed.notify(value) ) # log level hlayout = QHBoxLayout() tab_layout.addLayout(hlayout) hlayout.addWidget(QLabel(_('Log Level:'), self)) self._combo_log_level = self._create_combo_log_level() hlayout.addWidget(self._combo_log_level) hlayout.addStretch() tab_layout.addStretch() @property def config(self) -> Config: """The config instance.""" return self._parent_dialog.config def load_values(self): """Load config values into the GUI""" self._cb_notify.setChecked(self.config.notify()) self._cb_no_backup_on_battery.setChecked( self.config.noSnapshotOnBattery()) self._cb_one_backup_at_a_time.setChecked(self.config.globalFlock()) self._cb_backup_on_restore.setChecked(self.config.backupOnRestore()) self._cb_continue_on_errors.setChecked(self.config.continueOnErrors()) self._cb_use_checksum.setChecked(self.config.useChecksum()) self._cb_backup_regard_changes.setChecked( self.config.takeSnapshotRegardlessOfChanges()) value = self.config.warnFreeSpace() self._cb_warn_free_space.setChecked(self.config.warnFreeSpaceEnabled()) self._su_warn_free_space.set_storagesize(value) self._combo_log_level.select_by_data(self.config.logLevel()) def store_values(self): """Store values from GUI into the config""" self.config.setNotify(self._cb_notify.isChecked()) self.config.setNoSnapshotOnBattery( self._cb_no_backup_on_battery.isChecked()) self.config.setGlobalFlock(self._cb_one_backup_at_a_time.isChecked()) self.config.setBackupOnRestore(self._cb_backup_on_restore.isChecked()) self.config.setContinueOnErrors( self._cb_continue_on_errors.isChecked()) self.config.setUseChecksum(self._cb_use_checksum.isChecked()) self.config.setTakeSnapshotRegardlessOfChanges( self._cb_backup_regard_changes.isChecked()) if self._su_warn_free_space.isEnabled(): self.config.setWarnFreeSpace( self._su_warn_free_space.get_storagesize()) else: self.config.setWarnFreeSpaceDisabled() self.config.setLogLevel(self._combo_log_level.current_data) def remove_free_space_value_changed(self, value): """Event handler in case the value of 'Remove if less than X free space' in 'Remove & Retention' tab was modified. That value can not be lower than 'Warn on free space' value. """ warn_val = self._su_warn_free_space.get_storagesize() if warn_val < value: self._su_warn_free_space.set_storagesize( value, dont_touch_unit=True) def _create_combo_log_level(self) -> combobox.BitComboBox: fill = { 0: _('None'), 1: _('Errors'), 2: _('Changes') + ' & ' + _('Errors'), 3: _('All'), } return combobox.BitComboBox(self, fill) backintime-1.6.1/qt/manageprofiles/tab_remove_retention.py000066400000000000000000000362671514264426600240610ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about the Remove & Retention policy tab""" from PyQt6.QtWidgets import (QCheckBox, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QSpinBox, QToolTip, QWidget) from PyQt6.QtCore import Qt from PyQt6.QtGui import QCursor from config import Config from bitbase import TimeUnit from event import Event import qttools from manageprofiles.statebindcheckbox import StateBindCheckBox from manageprofiles.spinboxunit import SpinBoxWithUnit from manageprofiles.storagesizewidget import StorageSizeWidget from bitwidgets import HLineWidget class RemoveRetentionTab(QDialog): """The 'Remove & Retention' tab in the Manage Profiles dialog.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent): super().__init__(parent=parent) self._parent_dialog = parent # Vertical main layout # self._tab_layout = QVBoxLayout(self) self._tab_layout = QGridLayout() self.setLayout(self._tab_layout) # Keep most recent self._label_keep_most_recent() # Keep named backups self._cb_keep_named = self._checkbox_keep_named() # --- self._tab_layout.addWidget( HLineWidget(), # fromRow self._tab_layout.rowCount(), # fromColumn 0, # rowSpan, 1, # columnSpan 3) # Icon & Info label self._label_rule_execute_order() # --- self._tab_layout.addWidget( HLineWidget(), # fromRow self._tab_layout.rowCount(), # fromColumn 0, # rowSpan, 1, # columnSpan 3) # Remove older than N years/months/days self._checkbox_remove_older, self._spinunit_remove_older \ = self._remove_older_than() row = self._tab_layout.rowCount() self._tab_layout.addWidget(self._checkbox_remove_older, row, 0, 1, 2) self._tab_layout.addWidget(self._spinunit_remove_older, row, 2) # Retention policy self._cb_retention_policy, \ self._cb_run_remote_in_background, \ self._spb_keep_all, \ self._spb_keep_one_per_day, \ self._spb_keep_one_per_week, \ self._spb_keep_one_per_month \ = self._groupbox_retention_policy() self._checkbox_space, \ self._spin_unit_space, \ self._checkbox_inodes, \ self._spin_inodes \ = self._remove_free_space_inodes() # Layout self._tab_layout.setColumnStretch(0, 2) self._tab_layout.setColumnStretch(1, 1) self._tab_layout.setColumnStretch(2, 0) self._tab_layout.setRowStretch(self._tab_layout.rowCount(), 1) # Event: Notify observers if "warn free space" value has changed self.event_remove_free_space_value_changed = Event() # pylint: disable=unnecessary-lambda self._spin_unit_space.event_value_changed.register( lambda value: # noqa: PLW0108 self.event_remove_free_space_value_changed.notify(value) ) @property def config(self) -> Config: """The config instance""" return self._parent_dialog.config def load_values(self): """Load config values into the GUI""" # don't remove named snapshots self._cb_keep_named.setChecked( self.config.dontRemoveNamedSnapshots()) # remove old snapshots enabled, value, unit = self.config.removeOldSnapshots() self._checkbox_remove_older.setChecked(enabled) self._spinunit_remove_older.set_value(value) self._spinunit_remove_older.select_unit(unit) # smart remove smart_remove, keep_all, keep_one_per_day, keep_one_per_week, \ keep_one_per_month = self.config.smartRemove() self._cb_retention_policy.setChecked(smart_remove) self._spb_keep_all.setValue(keep_all) self._spb_keep_one_per_day.setValue(keep_one_per_day) self._spb_keep_one_per_week.setValue(keep_one_per_week) self._spb_keep_one_per_month.setValue(keep_one_per_month) self._cb_run_remote_in_background.setChecked( self.config.smartRemoveRunRemoteInBackground()) # min free space enabled, value = self.config.minFreeSpaceAsStorageSize() self._checkbox_space.setChecked(enabled) self._spin_unit_space.set_storagesize(value) # min free inodes self._checkbox_inodes.setChecked(self.config.minFreeInodesEnabled()) self._spin_inodes.setValue(self.config.minFreeInodes()) def store_values(self): """Store values from GUI into the config""" self.config.setRemoveOldSnapshots( self._checkbox_remove_older.isChecked(), self._spinunit_remove_older.value(), self._spinunit_remove_older.unit() ) self.config.setDontRemoveNamedSnapshots( self._cb_keep_named.isChecked()) self.config.setSmartRemove( self._cb_retention_policy.isChecked(), self._spb_keep_all.value(), self._spb_keep_one_per_day.value(), self._spb_keep_one_per_week.value(), self._spb_keep_one_per_month.value()) self.config.setSmartRemoveRunRemoteInBackground( self._cb_run_remote_in_background.isChecked()) self.config.setMinFreeSpaceWithStorageSize( self._spin_unit_space.isEnabled(), self._spin_unit_space.get_storagesize()) self.config.setMinFreeInodes( self._spin_inodes.isEnabled(), self._spin_inodes.value()) def warn_free_space_value_changed(self, value): """See tab_options.py::OptionsTab.remove_free_space_value_changed(). The remove value need to be lower than the warn value. """ remove_value = self._spin_unit_space.get_storagesize() if remove_value >= value: self._spin_unit_space.set_storagesize(value, dont_touch_unit=True) def update_items_state(self, enabled): """Update items regarding profile modes changes.""" self._cb_run_remote_in_background.setVisible(enabled) def _label_rule_execute_order(self) -> QWidget: icon_label = qttools.create_icon_label_info(fixed_size_widget=True) # Info text manual_link = '' + _('user manual') + '' txt = _( 'The following rules are processed from top to bottom. Later ' 'rules override earlier ones. See the {manual_link} for details ' 'and examples.').format(manual_link=manual_link) txt_label = QLabel(txt) txt_label.setWordWrap(True) txt_label.linkActivated.connect(self._handle_link_activated) txt_label.setTextInteractionFlags( Qt.TextInteractionFlag.TextBrowserInteraction) # Show URL in tooltip without anoing http-protocol prefix. txt_label.linkHovered.connect( lambda url: QToolTip.showText( # QCursor.pos(), url.replace('https://', '')) QCursor.pos(), _('Open user manual in browser.')) ) wdg = QWidget() layout = QHBoxLayout(wdg) layout.addWidget(icon_label) layout.addWidget(txt_label) self._tab_layout.addWidget(wdg, self._tab_layout.rowCount(), 0, 1, 3) def _handle_link_activated(self, _link): qttools.open_user_manual() def _label_keep_most_recent(self) -> None: cb = QCheckBox(_('Keep the most recent backup.'), self) qttools.set_wrapped_tooltip( cb, ( _('The most up-to-date backup is kept under ' 'all circumstances.'), _('That behavior cannot be changed.') ) ) # Always enabled cb.setChecked(True) cb.nextCheckState = lambda: None # fromRow, fromColumn spanning rowSpan rows and columnSpan self._tab_layout.addWidget(cb, self._tab_layout.rowCount(), 0, 1, 2) def _checkbox_keep_named(self) -> QCheckBox: cb = QCheckBox(_('Keep named backups.'), self) qttools.set_wrapped_tooltip( cb, _('Backups that have been given a name, in addition to the ' 'usual timestamp, will be retained under all circumstances ' 'and will not be removed.') ) # fromRow, fromColumn spanning rowSpan rows and columnSpan self._tab_layout.addWidget(cb, self._tab_layout.rowCount(), 0, 1, 2) return cb def _remove_older_than(self) -> QWidget: # units units = { TimeUnit.DAY: _('Day(s)'), TimeUnit.WEEK: _('Week(s)'), TimeUnit.YEAR: _('Year(s)') } spin_unit = SpinBoxWithUnit(self, (1, 999), units) # checkbox checkbox = StateBindCheckBox(_('Remove backups older than'), self) checkbox.bind(spin_unit) # tooltip tip = ( f'{units[TimeUnit.DAY]}: ' + _('Full days. Current day is ignored.'), f'{units[TimeUnit.WEEK]}: ' + _('Calendar weeks with Monday as first day. ' 'Current week is ignored.'), f'{units[TimeUnit.YEAR]}: ' + _('12 months periods. Current month is ignored.') ) qttools.set_wrapped_tooltip(checkbox, tip) qttools.set_wrapped_tooltip(spin_unit, tip) return checkbox, spin_unit def _groupbox_retention_policy(self) -> tuple: # noqa: PLR0915 # pylint: disable=too-many-statements layout = QGridLayout() # col, fx layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 0) layout.setColumnStretch(2, 0) checkbox_group = QGroupBox(_('Retention policy'), self) checkbox_group.setCheckable(True) checkbox_group.setLayout(layout) cb_in_background = QCheckBox( _('Run in background on remote host.'), self) qttools.set_wrapped_tooltip( cb_in_background, (_('The retention policy will be executed directly on the remote ' 'machine, not locally. The commands "bash", "screen", and ' '"flock" must be installed and available on that ' 'remote machine.'), _('If selected, Back In Time will first test the ' 'remote machine.'))) layout.addWidget(cb_in_background, 0, 0, 1, 2) tip = _('The days are counted starting from today.') label = QLabel(_('Keep all backups for the last'), self) qttools.set_wrapped_tooltip(label, tip) layout.addWidget(label, 1, 0) all_last_days = QSpinBox(self) all_last_days.setRange(1, 999) all_last_days.setSuffix(' ' + _('day(s).')) qttools.set_wrapped_tooltip(all_last_days, tip) # all_last_days.setAlignment(Qt.AlignmentFlag.AlignRight) layout.addWidget(all_last_days, 1, 1) # tip = same as the previous label label = QLabel( _('Keep the last backup for each day for the last'), self) qttools.set_wrapped_tooltip(label, tip) layout.addWidget(label, 2, 0) one_per_day = QSpinBox(self) one_per_day.setRange(1, 999) one_per_day.setSuffix(' ' + _('day(s).')) qttools.set_wrapped_tooltip(one_per_day, tip) # one_per_day.setAlignment(Qt.AlignmentFlag.AlignRight) layout.addWidget(one_per_day, 2, 1) tip = _('The weeks are counted starting from the current running ' 'week. A week starts on Monday.') label = QLabel( _('Keep the last backup for each week for the last'), self) qttools.set_wrapped_tooltip(label, tip) layout.addWidget(label, 3, 0) one_per_week = QSpinBox(self) one_per_week.setRange(1, 999) one_per_week.setSuffix(' ' + _('week(s).')) qttools.set_wrapped_tooltip(one_per_week, tip) # one_per_week.setAlignment(Qt.AlignmentFlag.AlignRight) layout.addWidget(one_per_week, 3, 1) tip = _('The months are counted as calendar months starting with ' 'the current month.') label = QLabel( _('Keep the last backup for each month for the last'), self) qttools.set_wrapped_tooltip(label, tip) layout.addWidget(label, 4, 0) one_per_month = QSpinBox(self) one_per_month.setRange(1, 999) one_per_month.setSuffix(' ' + _('month(s).')) qttools.set_wrapped_tooltip(one_per_month, tip) # one_per_month.setAlignment(Qt.AlignmentFlag.AlignRight) layout.addWidget(one_per_month, 4, 1) tip = _('The years are counted as calendar years starting with ' 'the current year.') label = QLabel(_('Keep the last backup for each year for'), self) layout.addWidget(label, 5, 0) labeltwo = QLabel(_('all years.'), self) layout.addWidget(labeltwo, 5, 1) qttools.set_wrapped_tooltip([label, labeltwo], tip) self._tab_layout.addWidget( checkbox_group, self._tab_layout.rowCount(), 0, 1, 3) return (checkbox_group, cb_in_background, all_last_days, one_per_day, one_per_week, one_per_month) def _remove_free_space_inodes(self) -> tuple: # free space less than spin_unit_space = StorageSizeWidget(self, (1, 99999)) checkbox_space = StateBindCheckBox( _('… the free space is less than'), self) checkbox_space.bind(spin_unit_space) # min free inodes checkbox_inodes = StateBindCheckBox( _('… the free inodes are less than'), self) spin_inodes = QSpinBox(self) spin_inodes.setSuffix(' %') spin_inodes.setRange(0, 15) checkbox_inodes.bind(spin_inodes) # layout groupbox = QGroupBox(_('Remove oldest backup if …'), self) grid = QGridLayout() groupbox.setLayout(grid) grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 0) grid.setColumnStretch(2, 0) # wdg, row, col grid.addWidget(checkbox_space, 0, 0, 1, 2) grid.addWidget(spin_unit_space, 0, 2) grid.addWidget(checkbox_inodes, 1, 0, 1, 2) grid.addWidget(spin_inodes, 1, 2) self._tab_layout.addWidget( groupbox, self._tab_layout.rowCount(), 0, 1, 3 ) return checkbox_space, spin_unit_space, checkbox_inodes, spin_inodes backintime-1.6.1/qt/messagebox.py000066400000000000000000000103211514264426600167670ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module offering several message boxes to inform user in the GUI.""" from PyQt6.QtCore import QTimer from PyQt6.QtWidgets import (QApplication, QInputDialog, QLineEdit, QMessageBox, QWidget) import qttools # pylint: disable=cyclic-import def ask_password_dialog(parent, title, prompt, language_code, timeout): """Dev note (2025-07, buhtz): Replace with extern use of zenity, yat, kdialog e.g. zenity --entry --title="foo" --text="text" --hide-text yad --entry --title="foo" --text="text" --hide-text kdialog --password "enter password" """ if parent is None: app = qttools.create_qapplication() translator = qttools.initiate_translator(language_code) app.installTranslator(translator) # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 dialog = QInputDialog() timer = QTimer() if timeout is not None: timer.timeout.connect(dialog.reject) timer.setInterval(timeout * 1000) timer.start() dialog.setWindowIcon(icon.BIT_LOGO) dialog.setWindowTitle(title) dialog.setLabelText(prompt) dialog.setTextEchoMode(QLineEdit.EchoMode.Password) QApplication.processEvents() result = dialog.exec() timer.stop() password = dialog.textValue() if result else '' del dialog return password def info(text, title=None, widget_to_center_on=None): """Show a modal information message box. The message box is centered on the primary screen if ``widget_to_center_on`` is not given. Args: text(str): The information text central to the dialog. title(str): Title of the message box dialog. widget_to_center_on(QWidget): Center the message box on that widget. """ QMessageBox.information( widget_to_center_on, title if title else ngettext('Information', 'Information', 1), text) def warning(text: str, title: str = None, widget_to_center_on: QWidget = None, as_question: bool = False) -> bool | None: """Show a modal warning message box. The message box is centered on the primary screen if ``widget_to_center_on`` is not given. Args: text: The warning message central to the dialog. title: Title of the message box dialog (default: 'Warning'). widget_to_center_on: Center the message box on that widget. as_question: Use Yes and No buttons. """ buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No \ if as_question else QMessageBox.StandardButton.Ok answer = QMessageBox.warning( widget_to_center_on, title if title else _('Warning'), text, buttons ) return answer == QMessageBox.StandardButton.Yes def question(text, title=None, widget_to_center_on=None) -> bool: """Show a modal question message box. The message box is centered on the primary screen if ``widget_to_center_on`` is not given. Args: text(str): The question central to the dialog. title(str): Title of the message box dialog (default: 'Question'). widget_to_center_on(QWidget): Center the message box on that widget. Return: bool: ``True`` if the answer was "Yes", otherwise ``False``. """ answer = QMessageBox.question( widget_to_center_on, title if title else _('Question'), text) return answer == QMessageBox.StandardButton.Yes def critical(parent, msg): """Shows an error message box. Qt itseld does not distinguish between error and critical messages. """ return QMessageBox.critical( parent, _('Error'), msg, buttons=QMessageBox.StandardButton.Ok, defaultButton=QMessageBox.StandardButton.Ok) backintime-1.6.1/qt/net.launchpad.backintime.policy000066400000000000000000000043201514264426600223340ustar00rootroot00000000000000 BackInTime https://github.com/bit-team/backintime document-save Authentication is required to run Back In Time as root. Start Back In Time GUI as root. auth_admin auth_admin auth_admin_keep /usr/bin/backintime-qt true Authentication is required to change backup schedules triggered by external storage device connections. This will install Udev rules which will start Back In Time if a drive get connected. auth_admin auth_admin_keep auth_admin_keep Authentication is required to change backup schedules triggered by external storage device connections. This will delete Udev rules related to a specific Back In Time backup profile. auth_admin auth_admin_keep auth_admin_keep backintime-1.6.1/qt/net.launchpad.backintime.serviceHelper.conf000066400000000000000000000023311514264426600245610ustar00rootroot00000000000000 system backintime-1.6.1/qt/net.launchpad.backintime.serviceHelper.service000066400000000000000000000007471514264426600253050ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2016 Germar Reitze # SPDX-FileCopyrightText: © 2017 Matthias Gerstner # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # [D-BUS Service] Name=net.launchpad.backintime.serviceHelper Exec=/usr/bin/python3 -Es /usr/share/backintime/qt/serviceHelper.py User=root backintime-1.6.1/qt/placeswidget.py000066400000000000000000000127611514264426600173170ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # SPDX-FileCopyrightText: © 2025 Samuel Moore # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # Split from app.py """Module offering the Places widget in the main window. """ import os import pathlib from PyQt6.QtWidgets import ( QAbstractItemView, QTreeWidget, QTreeWidgetItem, QWidget ) from PyQt6.QtGui import QFont, QIcon, QPalette from PyQt6.QtCore import Qt import bitbase import config class PlacesWidget(QTreeWidget): """A tree widget used in the main window. It contain the file system root and current users home directory as entry points. It also contain all included backup directories as entries. """ def __init__(self, parent: QWidget, cfg: config.Config): QTreeWidget.__init__(self, parent=parent) self.config = cfg self.parent = parent # Do not show controls for expanding and collapsing top-level items self.setRootIsDecorated(False) self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setHeaderLabel(_('Shortcuts')) self.header().setSectionsClickable(True) self.header().setSortIndicatorShown(True) self.header().setSectionHidden(1, True) self.header().sortIndicatorChanged.connect(self.do_update) self.currentItemChanged.connect(self._slot_changed) def do_update(self, _col: int = None, _order: Qt.SortOrder = None) -> None: """Update the places view""" self.clear() # name, path, icon self._add_place(_('Places'), '', '') self._add_place(_('File System'), '/', 'computer') fp_home = pathlib.Path.home() self._add_place( # Use full path in root mode ("/root") otherwise users name only str(fp_home) if bitbase.IS_IN_ROOT_MODE else fp_home.name, str(fp_home), 'user-home') # "Now" or a specific snapshot selected? if self.parent.sid.isRoot: # Use snapshots profiles list of include files and folders include_entries = self.config.include() else: # Determine folders from the snapshot itself base = os.path.expanduser('~') if not os.path.isdir(self.parent.sid.pathBackup(base)): # Folder not mounted. We can skip for the next updatePlaces() return folders = [ i.name for i in os.scandir(self.parent.sid.pathBackup(base)) if i.is_dir() ] include_entries = [(os.path.join(base, f), 0) for f in folders] # Use folders only (if 2nd tuple entry is 0) only_folders = filter(lambda entry: entry[1] == 0, include_entries) include_folders = [item[0] for item in only_folders] if not include_folders: return if not self.header().sortIndicatorSection(): indic = self.header().sortIndicatorOrder() reverse = indic == Qt.SortOrder.DescendingOrder include_folders = sorted(include_folders, reverse=reverse) self._add_place(_('Backup directories'), '', '') for folder in include_folders: self._add_place(folder, folder, 'document-save') def _add_place(self, name, path, icon): """ Dev note (buhtz, 2024-01-14): Parts of that code are redundant with timeline.py::HeaderItem.__init__(). """ item = QTreeWidgetItem() item.setText(0, name) if icon: item.setIcon(0, QIcon.fromTheme(icon)) item.setData(0, Qt.ItemDataRole.UserRole, path) if not path: font = item.font(0) font.setWeight(QFont.Weight.Bold) item.setFont(0, font) # item.setFlags(Qt.ItemFlag.ItemIsEnabled) item.setFlags(Qt.ItemFlag.NoItemFlags) item.setForeground( 0, self.palette().color(QPalette.ColorRole.PlaceholderText)) item.setBackground( 0, self.palette().color(QPalette.ColorRole.AlternateBase)) self.addTopLevelItem(item) if path == self.parent.path: self.setCurrentItem(item) return item def _slot_changed(self, item, _previous): if item is None: return path = str(item.data(0, Qt.ItemDataRole.UserRole)) if not path: return if path == self.parent.path: return # ??? self.parent.path = path self.parent.path_history.append(path) self.parent.updateFilesView(3) def get_sorting(self) -> tuple[int, int]: """Current sorting column and order as a tuple.""" return ( self.header().sortIndicatorSection(), self.header().sortIndicatorOrder().value ) def set_sorting(self, sorting: tuple[int, int]) -> None: """Set sorting.""" self.header().setSortIndicator(sorting[0], Qt.SortOrder(sorting[1])) backintime-1.6.1/qt/plugins/000077500000000000000000000000001514264426600157445ustar00rootroot00000000000000backintime-1.6.1/qt/plugins/notifyplugin.py000066400000000000000000000046501514264426600210520ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2021 Felix Stupp # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Notify plugin module""" import getpass import dbus import pluginmanager import logger class NotifyPlugin(pluginmanager.Plugin): """Plugin used to create notification bubbles in systray. The plugin use DBUS to send notifications. See its base class for more details. """ def isGui(self): # noqa: N802 return True # pylint: disable-next=too-many-arguments,too-many-positional-arguments def message(self, profile_id, profile_name, level, message, timeout): # 1 is ERROR, 0 is INFO if level != 1: # Dev note (2024-10, buhtz): # Message with level 0/INFO for example generatet by # setTakeSnapshotMessage() # Not clear to me why the notify plugin should only process # errors. return try: notify_interface = dbus.Interface( object=dbus.SessionBus().get_object( "org.freedesktop.Notifications", "/org/freedesktop/Notifications"), dbus_interface="org.freedesktop.Notifications" ) except dbus.exceptions.DBusException as exc: logger.error('Unexpected DBusException while initiating ' f'dbus.Interface(): {exc}') return if timeout > 0: timeout = 1000 * timeout else: # let timeout default to notification server settings timeout = -1 title = f'Back In Time ({getpass.getuser()}) : {profile_name}' message = message.replace('\n', ' ') message = message.replace('\r', '') try: notify_interface.Notify( 'Back In Time', 0, '', title, message, [], {}, timeout) except dbus.exceptions.DBusException as exc: logger.error(f'Unexpected DBusException while Notify(): {exc}') backintime-1.6.1/qt/plugins/systrayiconplugin.py000066400000000000000000000103671514264426600221330ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # Known open issues: # this script should get started and consider some cmd line arguments from BiT # (parsed via backintime.createParsers()) so that the same paths are used, # mainly "share-path" and "config" (path to the config file). # Otherwise e.g. unit tests or special user path settings may lead to # wrong status info in the systray icon! """Plugin starting the systray icon process Dev note (buhtz, 2025-07): Not sure why this need to be a plugin. """ import sys import os import gettext import subprocess import pluginmanager import tools import logger _ = gettext.gettext if not os.getenv('DISPLAY', ''): os.putenv('DISPLAY', ':0.0') class SysTrayIconPlugin(pluginmanager.Plugin): """A Back In Time plugin responsible to start the systray icon instance""" def __init__(self): self.process = None self.snapshots = None def init(self, snapshots): self.snapshots = snapshots # Old implementation disabled: # Why can a systray icon only be shown on X11 (not wayland)? # Qt can handle wayland now! # if not tools.checkXServer(): # return False # New implementation: Let Qt decide if a system tray icon can be shown. # See https://doc.qt.io/qt-5/qsystemtrayicon.html#details: # > To check whether a system tray is present on the user's desktop, # > call the QSystemTrayIcon::isSystemTrayAvailable() static function. # # This requires a QApplication instance (otherwise Qt causes a # segfault) which we don't have here so we create it to check if a # window manager ("GUI") is active at all (e.g. in headless # installations it isn't). # See: https://forum.qt.io/topic/3852/issystemtrayavailable- # always-crashes-segfault-on-ubuntu-10-10-desktop/6 try: if tools.is_Qt_working(systray_required=True): logger.debug('System tray is available to show the ' 'BIT system tray icon') return True # pylint: disable-next=broad-exception-caught except Exception as exc: logger.debug( f'Could not ask Qt if system tray is available: {repr(exc)}') logger.debug( 'No system tray available to show the BIT system tray icon') return False def isGui(self): # noqa: N802 """True""" return True def processBegin(self): # noqa: N802 """Start the process.""" try: logger.debug('Trying to start systray icon sub process...') path = os.path.join( tools.as_backintime_path('qt'), 'qtsystrayicon.py') cmd = [ sys.executable, path, self.snapshots.config.currentProfile() ] if logger.DEBUG: # HACK to propagate DEBUG logging level to sub process cmd.append('--debug') # pylint: disable-next=consider-using-with self.process = subprocess.Popen(cmd) # pylint: disable-next=broad-exception-caught except Exception as exc: logger.critical(f'Undefined situation: {exc}', self) else: logger.info('Systray icon sub process started.') # def processEnd(self): # """Dev note(2025-07, buhtz): Method makes no sense to me anymore. # Remove it soon. # """ # if self.process is not None: # try: # # The "qtsystrayicon.py" app does terminate itself # # once the snapshot has been taken so there is no need # # to do anything here to stop it or clean-up anything. # # self.process.terminate() # return # # ??? # except: # pass backintime-1.6.1/qt/qtsystrayicon.py000066400000000000000000000431141514264426600175740ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2025 Christian Buhtz # SPDX-FileCopyrightText: © 2025 Gregory Deseck # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Separate application managing the systray icon""" import sys import os import re import pwd import json import subprocess import signal import textwrap import functools from typing import Callable # TODO Is this really required? If the client is not configured for X11 # it may use Wayland or something else... # Or is this just required when run as root (where GUIs are not # configured normally)? if not os.getenv('DISPLAY', ''): os.putenv('DISPLAY', ':0.0') import qttools qttools.register_backintime_path('common') import logger # Workaround until the codebase allows a single place to init all translations import tools tools.initiate_translation(None) import snapshots import progress import logviewdialog import encfstools from PyQt6.QtCore import QTimer from PyQt6.QtWidgets import QSystemTrayIcon, QMenu, QProgressBar, QWidget from PyQt6.QtGui import QIcon, QRegion def trust_required(method: Callable) -> Callable: """Decorator to allow execution only if _trust_desktop is True.""" @functools.wraps(method) def wrapper(self, *args, **kwargs): if self._trust_desktop: return method(self, *args, **kwargs) return None return wrapper class QtSysTrayIcon: """Application instance for the Back In Time systray icon""" # pylint: disable-next=line-too-long ICON_PATH_ONLY = '\n' # pylint: disable-next=line-too-long ICON_PART_A = '' def __init__(self): self.snapshots = snapshots.Snapshots() self.config = self.snapshots.config self.decode = None self._current_user = pwd.getpwuid(os.getuid()).pw_name if len(sys.argv) > 1: if not self.config.setCurrentProfile(sys.argv[1]): logger.warning( f'Failed to change Profile_ID {sys.argv[1]}', self) self.qapp = qttools.create_qapplication(self.config.APP_NAME) translator = qttools.initiate_translator(self.config.language()) self.qapp.installTranslator(translator) self.qapp.setQuitOnLastWindowClosed(False) import icon self.qapp.setWindowIcon(icon.BIT_LOGO) self.status_icon = self._create_status_icon() self.contextMenu = QMenu() # The systray icon instance runs as the same user and with similar # privilegs as the BIT instance itself; e.g. root. # We need to know which user "owns" the desktop. If it is another # user, the systray instance should not expose sensible data like # paths of files and dirs in the backup. desktop_user = self._determine_desktop_session_user() self._trust_desktop = desktop_user == self._current_user if self._trust_desktop: logger.info('Trusting the desktop session.') else: logger.info( 'Not trusting the desktop session, which is owned by ' f'"{desktop_user}". ' f'But backup runs as "{self._current_user}".') if self._trust_desktop: txt = _('Profile: {profile_name}').format( profile_name=self.config.profileName()) else: txt = _('Profile: {profile_name} (by user "{desktop_user}")') \ .format(profile_name=self.config.profileName(), desktop_user=desktop_user) self.menuProfileName = self.contextMenu.addAction(txt) self.contextMenu.addSeparator() self.menuStatusMessage = self.contextMenu.addAction(_('Done')) self.menuProgress = self.contextMenu.addAction('') self.menuProgress.setVisible(False) self.contextMenu.addSeparator() self.btnPause = self.contextMenu.addAction( icon.PAUSE, _('Pause backup process')) self.btnPause.triggered.connect(self._slot_pause) self.btnPause.setVisible(self._trust_desktop) self.btnResume = self.contextMenu.addAction( icon.RESUME, _('Resume backup process')) self.btnResume.triggered.connect(self._slot_resume) self.btnResume.setVisible(False) self.btnStop = self.contextMenu.addAction( icon.STOP, _('Stop backup process')) self.btnStop.triggered.connect(self.onBtnStop) self.btnStop.setVisible(self._trust_desktop) self.contextMenu.addSeparator() # Dev note (2025-12, buhtz): I wondered why this decode checkbox is # visible only in ssh_encfs mode but not in local_encfs. Still not # sure but I think the reason is that in ssh_encfs there is no # "double-mounting": First SSH and then EncFS. In consequence this # decode button is a workaround. Explicit decoding in local_encfs # is not necessary because this happens via encfs-mounting. This # step is missing when using ssh_encfs. self.btnDecode = self.contextMenu.addAction( icon.VIEW_SNAPSHOT_LOG, _('decode paths')) self.btnDecode.setCheckable(True) self.btnDecode.setVisible( self.config.snapshotsMode() == 'ssh_encfs' and self._trust_desktop) self.btnDecode.toggled.connect(self.onBtnDecode) self.openLog = self.contextMenu.addAction( icon.VIEW_LAST_LOG, _('View Last Log')) self.openLog.triggered.connect(self.onOpenLog) self.openLog.setVisible(self._trust_desktop) self.startBIT = self.contextMenu.addAction( icon.BIT_LOGO, _('Start {appname}').format(appname=self.config.APP_NAME) ) self.startBIT.triggered.connect(self.onStartBIT) self.startBIT.setVisible(self._trust_desktop) self.status_icon.setContextMenu(self.contextMenu) self.progressBar = self._create_progress_bar() self.first_error = self.config.notify() self.popup = None self.last_message = None self.timer = QTimer() self.timer.timeout.connect(self.updateInfo) def _create_status_icon(self) -> QSystemTrayIcon: # Logo color depending on dark/light mode mode = self.config.systray() if mode == 'light': return QSystemTrayIcon(self.get_light_icon()) if mode == 'dark': return QSystemTrayIcon(self.get_dark_icon()) if qttools.in_dark_mode(self.qapp): return QSystemTrayIcon(self.get_light_icon()) return QSystemTrayIcon(self.get_dark_icon()) def _create_progress_bar(self) -> QProgressBar: bar = QProgressBar() bar.setMinimum(0) bar.setMaximum(100) bar.setValue(0) bar.setTextVisible(False) bar.resize(24, 6) import icon bar.render( icon.BIT_LOGO.pixmap(24), sourceRegion=QRegion(0, -14, 24, 6), flags=QWidget.RenderFlag.DrawChildren ) return bar def prepareExit(self): self.timer.stop() if not self.status_icon is None: self.status_icon.hide() self.status_icon = None if not self.popup is None: self.popup.deleteLater() self.popup = None self.qapp.processEvents() def run(self): if '--keep-alive' not in sys.argv: if not self.snapshots.busy(): sys.exit() self.status_icon.show() self.timer.start(500) self.qapp.exec() self.prepareExit() def updateInfo(self): # Exit this systray icon "app" when the snapshots is taken if '--keep-alive' not in sys.argv: if not self.snapshots.busy(): self.prepareExit() self.qapp.exit(0) return paused = tools.processPaused(self.snapshots.pid()) self.btnPause.setVisible(not paused and self._trust_desktop) self.btnResume.setVisible(paused and self._trust_desktop) if self._trust_desktop: message = self.snapshots.takeSnapshotMessage() else: message = None if message is None and self.last_message is None: message = (0, _('Working…')) if not message is None: if message != self.last_message: self.last_message = message if self.decode: message = (message[0], self.decode.log(message[1])) self.menuStatusMessage.setText( '\n'.join(textwrap.wrap(message[1], width=80))) self.status_icon.setToolTip(message[1]) pg = progress.ProgressFile(self.config) if pg.fileReadable(): pg.load() # percent = pg.intValue('percent') ## disable progressbar in icon until BiT has it's own icon ## fixes bug #902 # if percent != self.progressBar.value(): # self.progressBar.setValue(percent) # self.progressBar.render( # self.pixmap, # sourceRegion=QRegion(0, -14, 24, 6), # flags=QWidget.RenderFlags(QWidget.DrawChildren)) # self.status_icon.setIcon(QIcon(self.pixmap)) self.menuProgress.setText(' | '.join(self.getMenuProgress(pg))) self.menuProgress.setVisible(True) else: # self.status_icon.setIcon(self.icon.BIT_LOGO) self.menuProgress.setVisible(False) def getMenuProgress(self, pg): """See common/app.py::MainWindow.getProgressBarFormat(). The code is a near duplicate. """ data = ( ('sent', _('Sent:')), ('speed', _('Speed:')), ('eta', _('ETA:')) ) for key, txt in data: value = pg.strValue(key, '') if not value: continue yield txt + ' ' + value @trust_required def _slot_pause(self, *_args, **_kwargs): os.kill(self.snapshots.pid(), signal.SIGSTOP) @trust_required def _slot_resume(self, *_args, **_kwargs): os.kill(self.snapshots.pid(), signal.SIGCONT) @trust_required def onStartBIT(self, *_args, **_kwargs): profileID = self.config.currentProfile() cmd = ['backintime-qt',] if not profileID == '1': cmd += ['--profile', profileID] _proc = subprocess.Popen(cmd) @trust_required def onOpenLog(self, *_args, **_kwargs): dlg = logviewdialog.LogViewDialog( parent=self, decode=self.btnDecode.isChecked()) dlg.exec() @trust_required def onBtnDecode(self, checked, *_args, **_kwargs): if checked: self.decode = encfstools.Decode(self.config) self.last_message = None self.updateInfo() return self.decode = None @trust_required def onBtnStop(self, *_args, **_kwargs): os.kill(self.snapshots.pid(), signal.SIGKILL) self.btnStop.setEnabled(False) self.btnPause.setEnabled(False) self.btnResume.setEnabled(False) self.snapshots.setTakeSnapshotMessage(0, 'Backup terminated') def _get_desktop_user_via_loginctl(self) -> str | None: """Get name of user logged in to the current desktop session using loginctl. """ try: # get list of sessions cmd = ['loginctl', 'list-sessions', '--no-legend', '--json=short'] # logger.debug(f'Execute {cmd=}') output = subprocess.check_output(cmd, text=True) except FileNotFoundError: logger.warning( 'Can not determine user name of current desktop ' 'session because "loginctl" is not available.' ) return None except Exception as exc: logger.error( 'Unexpected error while determining user name of ' f'current desktop session: {exc}' ) return None sessions = [] # Check each session for session in json.loads(output): # logger.debug(f'{session=}') # Ignore none-user sessions if session.get('class') != 'user': continue # properties of the session info = subprocess.check_output( [ 'loginctl', 'show-session', str(session['session']), '--property=Active', '--property=Name', '--property=Seat', '--property=Type', '--property=Display', ], text=True ).strip() # logger.debug(f'{info=}') props = dict(line.split('=', 1) for line in info.splitlines()) # logger.debug(f'{props=}') sessions.append(props) # logger.debug(f'{sessions=}') display = os.environ.get('DISPLAY') # logger.debug(f'{display=}') if display: display = display.split('.')[0] matches = [ s for s in sessions if s.get('Display', '').split('.')[0] == display ] # logger.debug(f'{matches=}') if len(matches) == 1: logger.debug( 'User determined via loginctl using DISPLAY', self) return matches[0].get('Name') return None # Fallback checking for one active session, if DISPLAY not set fallback = [ s for s in sessions if s.get('Active', '').lower() == 'yes' and s.get('Seat') == 'seat0' and s.get('Type') in ('x11', 'wayland') ] if len(fallback) == 1: logger.debug( 'User determined via loginctl fallback (DISPLAY is not set)', self) return fallback[0].get('Name') return None def _get_desktop_user_via_x11_who(self) -> str | None: """Using 'who' to determine the current DISPLAY's user. The output of 'who' can look like this: user sshd pts/0 2025-09-16 08:30 (fe80::d65:ea81:c46f:7f0d%eth0) lightdm seat0 2025-09-15 16:07 (:0) """ if not os.environ.get('DISPLAY'): return None try: # list of users logged in output = subprocess.check_output(['who'], text=True).strip() except Exception as exc: logger.error( 'Unexpected error while determining user name of ' f'current desktop session: {exc}' ) return None display = os.environ.get('DISPLAY', ':0').split('.')[0] # each user for line in output: found = re.match(r'^(\S+).*\((.*)\)$', line) if not found: continue user, userdisplay = found.groups() userdisplay = userdisplay.split('.')[0] if userdisplay == display: logger.debug('User determined via x11 who', self) return user return None def _determine_desktop_session_user(self): """Return name of user logged in to the current desktop session. """ logger.info( 'Try to determine user of current desktop session via loginctl') user = self._get_desktop_user_via_loginctl() if not user: logger.info( 'Try to determine user of current desktop session via x11-who') user = self._get_desktop_user_via_x11_who() logger.info( f'Systray Icon determined the user "{user}" as owner of ' 'current desktop session.') return user @classmethod def _get_icon_filled(cls, color: str) -> QIcon: """Generate the dark symbolic icon""" svg_content = cls.ICON_PART_A + f' fill="{color}"' + cls.ICON_PART_B qicon = qttools.create_qicon_from_svg_source(svg_content) return qicon @staticmethod def get_dark_icon() -> QIcon: return QtSysTrayIcon._get_icon_filled('black') @staticmethod def get_light_icon() -> QIcon: return QtSysTrayIcon._get_icon_filled('white') if __name__ == '__main__': # Use '--keep-alive' to keep the systray icon alive. This is for debug # purpose only. logger.openlog('SYSTRAY') # HACK: Minimal arg parsing to enable debug-level logging if '--debug' in sys.argv: logger.DEBUG = True logger.debug( f'Systray icon process (PID: {os.getpid()} User: {logger.USER}) ' f'called with {sys.argv}') QtSysTrayIcon().run() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������backintime-1.6.1/qt/qttools.py����������������������������������������������������������������������0000664�0000000�0000000�00000051364�15142644266�0016353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Some helper functions and additional classes in context of Qt. - Helpers for Qt Fonts. - Helpers about path manipulation. - FiledialogShowHidden - Menu (tooltips in menus) - etc """ # pylint: disable=wrong-import-position,wrong-import-order import os import sys import atexit import pwd import re import json import textwrap import subprocess import tempfile from typing import Union, Iterable, Callable from pathlib import Path from contextlib import contextmanager from textdlg import TextDialog from PyQt6.QtGui import (QCursor, QDesktopServices, QGuiApplication, QFontMetricsF, QIcon, QPalette) from PyQt6.QtCore import (QEvent, QLibraryInfo, QLocale, Qt, QObject, QTranslator, QUrl) from PyQt6.QtWidgets import (QApplication, QHBoxLayout, QLabel, QStyle, QStyleFactory, QSystemTrayIcon, QToolTip, QWidget) from qttools_path import register_backintime_path register_backintime_path('common') import tools # noqa: E402 import logger # noqa: E402 import bitbase # noqa: E402 import version # noqa: E402 import messagebox # noqa: E402 _DARK_MODE_THRESHOLD = 128 # |--------------------------------| # | Widget modification & creation | # |--------------------------------| def can_render(string, widget): """Check if the string can be rendered by the font used by the widget. Args: string(str): The string to check. widget(QWidget): The widget which font is used. Returns: (bool) True if the widgets font contain all given characters. """ fm = widget.fontMetrics() for c in string: # Convert the unicode character to its integer representation # because fm.inFont() is not able to handle 2-byte characters if not fm.inFontUcs4(ord(c)): return False return True def in_dark_mode(widget_or_application: QWidget | QApplication) -> bool: """Determine if the desktop/theme is in dark mode.""" palette = widget_or_application.palette() window_color = palette.color(QPalette.ColorRole.Window) return window_color.value() < _DARK_MODE_THRESHOLD _REX_RICHTEXT = re.compile( # begin of line r'^' # all characters, except a new line r'[^\n]*' # tag opening r'<' # every character (as tagname) except > r'[^>]+' # tag closing r'>') def might_be_richtext(txt: str) -> bool: """Returns `True` if the text is rich text. Rich text is a subset of HTML used by Qt to allow text formatting. The function checks if the first line (before the first `\n') does contain a tag. A tag begins with with `<`, following by one or more characters and close with `>`. Qt itself does use `Qt::mightBeRichText()` internally but this is not available in PyQt for unknown reasons. Args: txt: The text to check. Returns: `True` if it looks like a rich text, otherwise `False`. """ return bool(_REX_RICHTEXT.match(txt)) def set_wrapped_tooltip(widget: Union[QWidget, Iterable[QWidget]], tooltip: Union[str, Iterable[str]], wrap_length: int = 72): """Add a tooltip to the widget but insert line breaks when appropriated. If a list of strings is provided, each string is wrapped individually and then joined with a line break. Args: widget: The widget or list of widgets to which a tooltip should be added. tooltip: The tooltip as string or iterable of strings. wrap_length: Every line is at most this lengths. """ if isinstance(widget, Iterable): for wdg in widget: set_wrapped_tooltip(wdg, tooltip, wrap_length) return # Always use tuple or list if isinstance(tooltip, str): tooltip = (tooltip, ) # Richtext or plain text is_richtext = might_be_richtext(tooltip[0]) newline = {True: '
', False: '\n'}[is_richtext] result = [] # Wrap each paragraph in itself for paragraph in tooltip: result.append('\n'.join( textwrap.wrap(paragraph, wrap_length) )) # glue all together result = newline.join(result) # Qt handles the string as richttext (interpreting html tags) only, # if it begins with a tag. if is_richtext and result[0] != '<': result = f'{result}' widget.setToolTip(result) def update_combo_profiles(config, combo_profiles, current_profile_id): """ Updates the combo box with profiles. :param config: Configuration object with access to profile data. :param combo_profiles: The combo box widget to be updated. :param current_profile_id: The ID of the current profile to be selected. """ profiles = config.profilesSortedByName() for profile_id in profiles: combo_profiles.add_profile_id(profile_id) if profile_id == current_profile_id: combo_profiles.set_current_profile_id(profile_id) def create_icon_label( icon_type: QStyle.StandardPixmap, icon_size: QStyle.PixelMetric = QStyle.PixelMetric.PM_LargeIconSize, icon_scale_factor: float | int = None, fixed_size_widget: bool = False) -> QLabel: """Return a ``QLabel`` instance containing an icon. Args: icon_type: The icon, eg. info or warning. icon_size: Size reference. fixed_size_widget: Fix label size to its icon (default: False) Returns: The QLabel """ style = QApplication.style() ico = style.standardIcon(icon_type) sz = style.pixelMetric(icon_size) if icon_scale_factor: sz = int(sz * icon_scale_factor) pixmap = ico.pixmap(sz) label = QLabel() label.setPixmap(pixmap) if fixed_size_widget: label.setFixedSize(pixmap.size()) return label def create_icon_label_info( icon_size: QStyle.PixelMetric = QStyle.PixelMetric.PM_LargeIconSize, icon_scale_factor: float | int = None, fixed_size_widget: bool = False) -> QLabel: """Return a QLabel with an info icon. See `create_icon_label` for details. """ return create_icon_label( icon_type=QStyle.StandardPixmap.SP_MessageBoxInformation, icon_size=icon_size, icon_scale_factor=icon_scale_factor, fixed_size_widget=fixed_size_widget) def create_icon_label_warning( icon_size: QStyle.PixelMetric = QStyle.PixelMetric.PM_LargeIconSize, icon_scale_factor: float | int = None, fixed_size_widget: bool = False) -> QLabel: """Return a QLabel with a warning icon. See `create_icon_label` for details. """ return create_icon_label( icon_type=QStyle.StandardPixmap.SP_MessageBoxWarning, icon_size=icon_size, icon_scale_factor=icon_scale_factor, fixed_size_widget=fixed_size_widget) def create_info_label( text: str, icon_size: QStyle.PixelMetric = QStyle.PixelMetric.PM_LargeIconSize, icon_scale_factor: float | int = None, fixed_size_widget: bool = True) -> QLabel: """Return a widget with an info icon and text. See `create_icon_label` for details. """ ico = create_icon_label_info( icon_size, icon_scale_factor, fixed_size_widget) return _combine_icon_with_label(ico, text) def create_warning_label( text: str, icon_size: QStyle.PixelMetric = QStyle.PixelMetric.PM_LargeIconSize, icon_scale_factor: float | int = None, fixed_size_widget: bool = True) -> QLabel: """Return a widget with a warning icon and text. See `create_icon_label` for details. """ ico = create_icon_label_warning( icon_size, icon_scale_factor, fixed_size_widget) return _combine_icon_with_label(ico, text) def _combine_icon_with_label(icon: QLabel, text: str) -> QWidget: """Horizontally combine the given `icon` with a text label Args: icon: A `QLabel` containing an icon used as first item in the horizontal layout. text: The text used in a `Qlabel` as second item in the horizontal layout. Returns: A widget with horizontal layout containing an icon label and a text label. """ txt = QLabel(text) txt.setWordWrap(True) # Show URL in tooltip without anoing http-protocol prefix. if ' QIcon: """Create a QIcon instance based on SVG/XML source. QIcon is not capable of reading from a byte stream. This workaround write the SVG/XML-string to a temporary in-RAM file before QIcon reads it back. """ svg_fn = None with tempfile.NamedTemporaryFile(suffix='.svg', mode='w', delete=False ) as handle: handle.write(svg_source) svg_fn = handle.name atexit.register(Path(svg_fn).unlink) return QIcon(svg_fn) def custom_sort_order(header, loop, new_column, new_order): """Provides a toggled sort order across two columns for QTreeWidget.""" if new_column == 0 and new_order == Qt.SortOrder.AscendingOrder: if loop: new_column, new_order = 1, Qt.SortOrder.AscendingOrder header.setSortIndicator(new_column, new_order) loop = False else: loop = True header.model().sort(new_column, new_order) return loop # |---------------------| # | Misc / Uncatgorized | # |---------------------| class MouseButtonEventFilter(QObject): """Catch mouse buttons 4 and 5 (mostly used as back and forward) and assign it to browse in file history. """ def __init__(self, back_handler: Callable, forward_handler: Callable): # mouse button 4 self._handle_back = back_handler # mouse button 5 self._handle_forward = forward_handler super().__init__() # pylint: disable-next=invalid-name def eventFilter(self, receiver: QObject, event: QEvent): # noqa: N802 """Catch global input events.""" # not a mouse press event if event.type() != QEvent.Type.MouseButtonPress: return super().eventFilter(receiver, event) try: # button 4 or 5 ? handler = { Qt.MouseButton.BackButton: self._handle_back, Qt.MouseButton.ForwardButton: self._handle_forward }[event.button()] except KeyError: pass else: # no exception handler() return True return super().eventFilter(receiver, event) def _determine_root_mode_user() -> str: """Determine the users name who started BIT in root mode Usually pkexec is used but some users do use sudo themself. """ # Try pkexec uid = os.getenv('PKEXEC_UID', None) if uid: return pwd.getpwuid(int(uid)).pw_name # Try sudo sudo_user = os.getenv('SUDO_USER', None) if sudo_user: return sudo_user return None def open_url(url: str) -> None: """Open a URL with the systems default browser using xdg-open.""" # regular user mode if not bitbase.IS_IN_ROOT_MODE: QDesktopServices.openUrl(QUrl(url)) return # root mode user_name = _determine_root_mode_user() try: subprocess.run( [ 'runuser', '-u', user_name, '--', 'xdg-open', url ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) except (subprocess.CalledProcessError, FileNotFoundError) as exc: logger.error(f'Problem while opening "{url}" in as user ' f'"{user_name}" while in root-mode. ' f'Error was: {exc}') except Exception as exc: # pylint: disable=broad-exception-caught logger.critical(f'Unknown problem while opening "{url}" in as user ' f'"{user_name}" while in root-mode. ' f'Error was: {exc}') def screen_width_in_chars(widget: QWidget, reference_char: str = 'M') -> int: """Width of the screen in number of characters ('em'). The calculation is based on the width of one character, determined via font metrics regarding the given widget. """ # Calculate width in pixel for one 'em' (letter 'M') metrics = QFontMetricsF(widget.font()) char_px = metrics.horizontalAdvance(reference_char) # Screen width handle = widget.windowHandle() screen = handle.screen() if handle else QGuiApplication.primaryScreen() geom = screen.availableGeometry() # Screen width in 'em' (number of characters) return int(geom.width() / char_px) def open_man_page(manpage: str, icon: QIcon = None, section: str = None) -> None: """Open the manpage in a text browser window. The position and geometry of the dialog depends on fractions of the screen. The the man page content's linebreaks in the dialog are adjusted to the width of the dialog. Args: manpage: Name of the manpage. icon: Icon to use for the window. section: Section of the man page to scroll to. """ content = '' if section: # Search for one line containing only the section heading but # allow blanks before and behind it. pattern = r'(?m)^\s*' + section + r'\s*$' else: pattern = None # The dialog td = TextDialog( content, markdown=False, scroll_to=pattern, title=_('man page: {man_page_name}').format( man_page_name=manpage), icon=icon ) # Determine man page width in characters... chars = screen_width_in_chars(td.browser_widget) # ...using text dialogs screen fraction and a 5% security buffer chars = int(chars * td.width_fraction * 0.95) env = os.environ.copy() env['MANWIDTH'] = f'{chars}' # Get content from man page try: proc = subprocess.run( ['man', manpage], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env, check=False ) content = proc.stdout if not content: raise FileNotFoundError( f'No content for man page "{manpage}".\n' f'Error: {proc.stderr.strip()} ({proc.returncode})' ) except FileNotFoundError as exc: messagebox.critical(None, str(exc)) logger.error(str(exc)) return # Show dialog with content td.set_content(content) td.exec() def user_manual_uri() -> str: """Return the URI to the user manual. If available the local URI is used otherwise the online version is. """ uri = bitbase.USER_MANUAL_LOCAL_PATH.as_uri() \ if bitbase.USER_MANUAL_LOCAL_AVAILABLE \ else bitbase.URL_USER_MANUAL return uri def open_user_manual() -> None: """Open the user manual in browser. If available the local manual is used otherwise the online version is opened. """ open_url(user_manual_uri()) def _show_qt_debug_info(the_qapp: QApplication): if not logger.DEBUG: return try: info = { # The platform name indicates eg. wayland vs. X11, see also: # https://doc.qt.io/qt-5/qguiapplication.html#platformName-prop # For more details see our X11/Wayland/Qt documentation in the # directory doc/maintain 'QT QPA platform plugin': the_qapp.platformName(), 'QT_QPA_PLATFORMTHEME': os.environ.get('QT_QPA_PLATFORMTHEME', ''), # styles and themes determine the look & feel of the GUI 'QT_STYLE_OVERRIDE': os.environ.get('QT_STYLE_OVERRIDE', ''), 'QT active style': the_qapp.style().objectName(), 'QT fallback style': QIcon.fallbackThemeName(), 'QT supported styles': QStyleFactory.keys(), 'themeSearchPaths': QIcon.themeSearchPaths(), 'fallbackSearchPaths': QIcon.fallbackSearchPaths(), # The Back In Time system tray icon can only be shown if the # desktop environment supports this 'Is SystemTray available': QSystemTrayIcon.isSystemTrayAvailable(), } # msg = '\n' + json.dumps(info, indent=4) msg = json.dumps(info) except Exception as exc: # pylint: disable=broad-exception-caught msg = f'Error reading QT QPA platform plugin or style: {exc}' logger.debug(msg) def create_qapplication(app_name=bitbase.APP_NAME) -> QApplication: """Create a QAppliction instance or return the existing one. Dev note (buhtz, 2025-10): Refactoring is needed. e.g. A QApplication derived class (BITApplication) to handle the singleton. """ # pylint: disable-next=global-variable-undefined global qapp # noqa: PLW0603 try: # pylint: disable-next=used-before-assignment return qapp # "singleton pattern": Reuse already instantiated qapp except NameError: pass qapp = QApplication(sys.argv) _show_qt_debug_info(qapp) # Release Candidate indicator if version.IS_RELEASE_CANDIDATE: app_name = f'{app_name} -- RELEASE CANDIDATE -- ' \ f'({version.__version__})' elif version.IS_UNSTABLE_DEV_VERSION: app_name = f'{app_name} -- UNSTABLE DEVELOPMENT ' \ f'VERSION -- ({version.__version__})' # This will influence the main window title qapp.setApplicationName(app_name) try: if bitbase.IS_IN_ROOT_MODE: qapp.setApplicationName(app_name + " (root)") qapp.setDesktopFileName("backintime-qt-root") else: qapp.setDesktopFileName("backintime-qt") except Exception as exc: # pylint: disable=broad-exception-caught logger.warning('Could not set App ID (required for Wayland App icon ' f'and more). Reason: {exc}') # With "--debug" arg show the QT QPA platform name in the main window's # title if logger.DEBUG: qapp.setApplicationName( f'{qapp.applicationName()} ' f'[QT QPA platform: "{qapp.platformName()}"]') return qapp def initiate_translator(language_code: str) -> QTranslator: """Creating an Qt related translator. Args: language_code: Language code to use (based on ISO-639-1). This is done beside the primarily used GNU gettext because Qt need to translate its own default elements like Yes/No-buttons. The systems current local is used when no language code is provided. Translation is deactivated if language code is unknown. """ translator = QTranslator() if language_code: logger.debug(f'Language code "{language_code}".') else: logger.debug('No language code. Use systems current locale.') language_code = QLocale.system().name() rc = translator.load( f'qt_{language_code}', QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath)) if rc is False: logger.warning( 'PyQt (the GUI library) could not install a translator for the ' f'language code "{language_code}". Standard GUI elements will ' 'fall back to the source language (English). This does not ' 'affect the translation of Back In Time-specific GUI elements.') tools.set_locale_by_language_code(language_code) return translator @contextmanager def block_signals(widget: QWidget) -> None: """Context manager to temporary block Qt signals""" widget.blockSignals(True) yield widget.blockSignals(False) backintime-1.6.1/qt/qttools_path.py000066400000000000000000000026251514264426600173630ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Helper functions extracted from qt/qttools.py file. Extraction happened of problems with import dependencies. The whole path manipulation will become obsolete when migrating to state of the art Python packaging standards. This module is a workaround and will get refactored in the future. """ import sys from pathlib import Path def as_backintime_path(*path: str) -> str: """Get path inside ``backintime`` install folder. Args: *path (str): Paths that should be joined to ``backintime``. Returns: str: Child path of ``backintime`` child path e.g. ``/usr/share/backintime/common``or ``/usr/share/backintime/qt``. """ result = Path(__file__).parent.parent / Path(*path) result = result.resolve() return str(result) def register_backintime_path(*path: str): """Find duplicate in common/tools.py """ path = as_backintime_path(*path) if path not in sys.path: sys.path.insert(0, path) backintime-1.6.1/qt/restoreconfigdialog.py000066400000000000000000000410351514264426600206710ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2008-2022 Taylor Raak # SPDX-FileCopyrightText: © 2024 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """A dialog to identify and import old Back In Time configs. """ import os import datetime import getpass import threading import subprocess from typing import Any, Generator from pathlib import Path from queue import Queue import logger import bitbase from config import Config from snapshots import SID from PyQt6.QtGui import (QBrush, QColor, QFont, QFileSystemModel, QPalette, QShortcut) from PyQt6.QtWidgets import (QDialog, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QLayout, QPushButton, QSizePolicy, QToolButton, QTreeView, QVBoxLayout, QWidget) from PyQt6.QtCore import (Qt, QDir, QModelIndex, QTimer) import qttools from bitwidgets import Spinner # pylint: disable-next=too-many-instance-attributes class RestoreConfigDialog(QDialog): """ Show a dialog that will help to restore BITs configuration. User can select a config from previous snapshots. Dev note (2025-07, buhtz): Experiencing the dialog as slow or temporary freezing is usual, because the QFileSystemModel is resource consuming and blocking the rest of the event loop. Unfold directories in the tree and the directories parents is very time consuming because QFileSystemModel access the file system each time. """ def __init__(self, config: Config): super().__init__() self.config = config # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 self.setWindowIcon(icon.SETTINGS_DIALOG) self.setWindowTitle(_('Import configuration')) self.setSizePolicy( QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding ) main_layout = QVBoxLayout(self) top_layout = QVBoxLayout() self._create_hint(top_layout, config) self._lbl_spinner, self._spinner, self._btn_scan \ = self._create_scan_controls(top_layout) self._btn_scan.clicked.connect(self.start_scanning) main_layout.addLayout(top_layout, 0) self._tree_view, self._tree_model = self._create_tree() tree_layout = QVBoxLayout() tree_layout.addWidget(self._tree_view) main_layout.addLayout(tree_layout, 1) # expand users home self._expand_with_parents(self._index_from_path(Path.home())) # colors self._color_red, self._color_green = __class__._red_and_green() bottom_layout = QVBoxLayout() # show where a snapshot with config was found self._lbl_found = QLabel(_('No directory selected'), self) self._lbl_found.setWordWrap(True) self._lbl_found.setPalette(self._color_red) bottom_layout.addWidget(self._lbl_found) # show profiles inside the config self._wdg_profiles = QWidget(self) self._wdg_profiles.setContentsMargins(0, 0, 0, 0) self._wdg_profiles.hide() self._grid_layout = QGridLayout() self._grid_layout.setContentsMargins(0, 0, 0, 0) self._grid_layout.setHorizontalSpacing(20) self._wdg_profiles.setLayout(self._grid_layout) bottom_layout.addWidget(self._wdg_profiles) self._config_to_restore = None self._tree_view.selectionModel().currentChanged.connect( self._slot_index_changed) btn_box = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, self ) btn_box.accepted.connect(self.accept) btn_box.rejected.connect(self.reject) self._btn_restore = btn_box.button(QDialogButtonBox.StandardButton.Ok) self._btn_restore.setText(_('Import')) self._btn_restore.setEnabled(False) bottom_layout.addWidget(btn_box) main_layout.addLayout(bottom_layout, 0) self._queue = Queue() self._pool_timer = QTimer(self) self._pool_timer.timeout.connect(self._process_found_queue) self._scan_fs_thread = None self.start_scanning() def start_scanning(self): """Start the file system scanning thread and prepare the GUI""" self._btn_scan.setVisible(False) self._pool_timer.start(1500) # milliseconds self._lbl_spinner.setText(_('Searching…')) self._spinner.start(interval_ms=200) self._scan_fs_thread = _ScanFileSystem(queue=self._queue) self._scan_fs_thread.start() def _create_tree(self) -> tuple[QTreeView, QFileSystemModel]: model = _CfgFileSystemModel(self) model.setRootPath(QDir().rootPath()) model.setReadOnly(True) model.setFilter(QDir.Filter.AllDirs | QDir.Filter.NoDotAndDotDot) view = QTreeView(self) view.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding ) view.setModel(model) view.setAnimated(False) # Hide all columns (size, typ, mod date) except the first (name) for col in range(1, view.header().count()+1): view.setColumnHidden(col, True) view.header().hide() return view, model @staticmethod def _red_and_green() -> tuple[QColor, QColor]: red = QPalette() red.setColor(QPalette.ColorRole.WindowText, QColor(205, 0, 0)) green = QPalette() green.setColor(QPalette.ColorRole.WindowText, QColor(0, 160, 0)) return red, green def _create_hint(self, parent_layout: QLayout, config: Config) -> None: """Create the label to explain how and where to find existing config file. Returns: (QLabel): The label """ sample_path = os.path.join( 'backintime', config.host(), getpass.getuser(), '1', SID(datetime.datetime.now(), config).sid ) sample_path = f'{sample_path}' text_a = _( 'Select the backup directory from which the configuration ' 'file should be imported. The path may look like: {samplePath}' ).format(samplePath=sample_path) text_b = _( 'If the directory is located on an external or remote drive, ' 'it must be manually mounted beforehand.' ) label = QLabel(f'

{text_a}

{text_b}

', self) label.setWordWrap(True) layout = QHBoxLayout() layout.addWidget(qttools.create_icon_label_info(icon_scale_factor=2)) layout.addWidget(label, stretch=1) parent_layout.addLayout(layout) def _create_scan_controls(self, parent_layout: QLayout ) -> tuple[QLabel, Spinner, QPushButton]: # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 lbl_spinner = QLabel(_('Searching…'), self) spinner = Spinner(self, font_scale=2) btn_scan = QPushButton(_('Scan again'), self) btn_scan.setIcon(icon.REFRESH) hbox = QHBoxLayout() hbox.addWidget(lbl_spinner) hbox.addWidget(spinner) hbox.addWidget(btn_scan) hbox.addStretch() hbox.addWidget(self._create_button_show_hidden()) parent_layout.addLayout(hbox) return lbl_spinner, spinner, btn_scan def _create_button_show_hidden(self) -> QToolButton: # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 btn = QToolButton(self) btn.setText(_('Show hidden directories')) btn.setIcon(icon.SHOW_HIDDEN) btn.setToolTip(_('Show/hide hidden directories (Ctrl+H)')) btn.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) btn.setCheckable(True) shortcut = QShortcut('Ctrl+H', self) shortcut.activated.connect(btn.toggle) btn.setChecked(False) btn.toggled.connect(self._slot_show_hidden) return btn def _path_from_index(self, index: QModelIndex) -> Path: """ return a path string for a given treeView index """ return Path(self._tree_model.filePath(index)) def _index_from_path(self, path: str | Path) -> QModelIndex: """ return the index for path which can be used in treeView """ idx = self._tree_model.index( str(path) if isinstance(path, Path) else path) return idx def _slot_index_changed(self, current, _previous): """Called every time a new item is chosen in treeView. If there was a config found inside the selected folder, show available information about the config. """ # pylint: disable=protected-access fp = self._path_from_index(current) cfg = _get_valid_config(fp / bitbase.FILENAME_CONFIG) if cfg: self._expand_with_parents(current) self._lbl_found.setText(str(fp)) self._lbl_found.setPalette(self._color_green) self._show_profile(cfg) self._config_to_restore = cfg else: self._lbl_found.setText(_('No config found in this directory')) self._lbl_found.setPalette(self._color_red) self._wdg_profiles.hide() self._config_to_restore = None self._btn_restore.setEnabled(bool(cfg)) def _expand_with_parents(self, index: QModelIndex): stack = [] # Remember index's of the entry and all its parents current = index while current.isValid(): stack.insert(0, current) current = current.parent() def expand_next(): try: self._tree_view.expand(stack.pop(0)) # Sligthely reduce slowdown/freeze because of resource # hungry QFileSystemModel QTimer.singleShot(50, expand_next) except IndexError: pass expand_next() def _show_profile(self, cfg): child = self._grid_layout.takeAt(0) while child: child.widget().deleteLater() child = self._grid_layout.takeAt(0) for row, pid in enumerate(cfg.profiles()): for col, txt in enumerate(( _('Profile:') + str(pid), cfg.profileName(pid), _('Mode:') + cfg.SNAPSHOT_MODES[ cfg.snapshotsMode(pid)][1] )): self._grid_layout.addWidget(QLabel(txt, self), row, col) self._grid_layout.setColumnStretch(col, 1) self._wdg_profiles.show() def _process_found_queue(self) -> None: self._tree_view.setUpdatesEnabled(False) while not self._queue.empty(): path = self._queue.get() self._tree_model.highlight_this(Path(path)) self._expand_with_parents(self._index_from_path(path)) self._tree_view.setUpdatesEnabled(True) # stop spinner and queue pooling if thread is empty if not self._scan_fs_thread.is_alive(): self._spinner.stop() self._lbl_spinner.setText(_('Search complete.')) self._pool_timer.stop() self._btn_scan.setVisible(True) def _slot_show_hidden(self, checked): if checked: flags = QDir.Filter.AllDirs \ | QDir.Filter.NoDotAndDotDot \ | QDir.Filter.Hidden else: flags = QDir.Filter.AllDirs \ | QDir.Filter.NoDotAndDotDot \ self._tree_model.setFilter(flags) def accept(self): """ handle over the dict from the selected config. The dict contains all settings from the config. """ if self._config_to_restore: self.config.dict = self._config_to_restore.dict super().accept() def exec(self): """ stop the scan thread if it is still running after dialog was closed. """ ret = super().exec() self._scan_fs_thread.stop() return ret class _CfgFileSystemModel(QFileSystemModel): """A sub-classed file-system model to visually highlight some of its entries.""" def __init__(self, parent: QWidget): super().__init__(parent) self._paths = [] font = QFont() font.setBold(True) # See data() for details self._role_result = { Qt.ItemDataRole.ForegroundRole: QBrush( parent.palette().color(QPalette.ColorRole.Highlight)), Qt.ItemDataRole.FontRole: font } def highlight_this(self, path: Path) -> None: """Remember the path to draw with different font""" self._paths.append(path) # notify (redraw) the view self.layoutChanged.emit() def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> Any: """Draw an entry with bold font and highlted font color if in `self._paths`. """ if role in self._role_result: file_path = Path(self.filePath(index)) # Return font or brush if file_path in self._paths: return self._role_result[role] return super().data(index, role) class _ScanFileSystem(threading.Thread): """A thread scanning the file system for config files related to BIT.""" # foundConfig = pyqtSignal(str) def __init__(self, queue: Queue, stop_event=None): super().__init__() self._queue = queue self._stop_event = stop_event or threading.Event() def run(self): """Run several searches for config files""" search_paths = [ str(Path.home()), '/media', '/mnt', '/', # keep root at the end! ] for path_to_scan in search_paths: # Exclude the other dirs if searching in root if path_to_scan == search_paths[-1]: excludes = search_paths[:-1][:] else: excludes = [] for found in self._scan(path_to_scan, excludes): if self._stop_event.is_set(): return # print(f'queue.put({found=}') self._queue.put(found) def _scan(self, search_path: Path, excludes: list[str] ) -> Generator[Path, None, None]: """Use `find` on shell to search for `config` files.""" logger.debug(f'Scanning in {search_path} for config files', self) cmd = ['find', str(search_path)] # exclude directories: defaults + extras for exclude in ['/proc', '/var', '/sys', '/tmp', '/run'] + excludes: cmd = cmd + ['(', '-path', exclude, '-prune', ')', '-o'] cmd = cmd + [ '(', '-type', 'f', '-name', bitbase.FILENAME_CONFIG, '-print', ')' ] with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True) as proc: for line in proc.stdout: if self._stop_event.is_set(): return path = Path(line.strip()) if _get_valid_config(path): yield path.parent def stop(self): """Prepare stop and wait for finish.""" self._stop_event.set() self.join() def _get_valid_config(path: Path) -> Config | None: try: cfg = Config(str(path)) if cfg.isConfigured(): return cfg except (FileNotFoundError, UnicodeDecodeError): pass # pylint: disable-next=broad-exception-caught except Exception as exc: logger.critical(f'Unhandled branch in code!\n{exc}\n{__file__}') return None backintime-1.6.1/qt/restoredialog.py000066400000000000000000000111711514264426600175010ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module offering RestoreDialog""" from pathlib import Path from PyQt6.QtGui import QDesktopServices from PyQt6.QtWidgets import (QDialog, QDialogButtonBox, QPlainTextEdit, QVBoxLayout) from PyQt6.QtCore import QMutex, QThread, QTimer, QUrl from inhibitsuspend import InhibitSuspend import messagebox class RestoreDialog(QDialog): """A dialog showing a live log of a restore process.""" # pylint: disable=too-many-instance-attributes def __init__(self, parent, sid, what, where='', **kwargs): super().__init__(parent) self.resize(600, 500) self.config = parent.config self.snapshots = parent.snapshots self.sid = sid self.what = what self.where = where self.kwargs = kwargs # pylint: disable-next=import-outside-toplevel import icon # noqa: PLC0415 self._log_file = Path(self.config.restoreLogFile()) if self._log_file.exists(): self._log_file.unlink() self.setWindowIcon(icon.RESTORE_DIALOG) self.setWindowTitle(_('Restore')) self._main_layout = QVBoxLayout(self) self._txt_log_view = QPlainTextEdit(self) self._txt_log_view.setReadOnly(True) self._txt_log_view.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap) self._txt_log_view.setMaximumBlockCount(100000) self._main_layout.addWidget(self._txt_log_view) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) btn_show_log = button_box.addButton( _('Show full Log'), QDialogButtonBox.ButtonRole.ActionRole) self._main_layout.addWidget(button_box) self._btn_close = button_box.button( QDialogButtonBox.StandardButton.Close) self._btn_close.setEnabled(False) button_box.rejected.connect(self.close) btn_show_log.clicked.connect(self._slot_show_log) # restore in separate thread self.thread = RestoreThread(self) self.thread.finished.connect(self._slot_thread_finished) # refresh log every 200ms self._refesh_timer = QTimer(self) self._refesh_timer.setInterval(200) self._refesh_timer.setSingleShot(False) self._refesh_timer.timeout.connect(self._slot_refresh_log) def _slot_show_log(self): if not self._log_file.exists(): messagebox.critical( self, f'Log file ("{self._log_file}") not found.') return QDesktopServices.openUrl(QUrl(str(self._log_file))) def _slot_refresh_log(self): """ get new log from thread """ new_log = self.thread.buffer[:] size = len(new_log) if size: self.thread.mutex.lock() self.thread.buffer = self.thread.buffer[size:] self.thread.mutex.unlock() self._txt_log_view.appendPlainText(new_log.rstrip('\n')) def exec(self): """Show dialog and run underlying threads""" self.show() self._refesh_timer.start() self.thread.start() super().exec() self._refesh_timer.stop() self.thread.wait() def _slot_thread_finished(self): self._btn_close.setEnabled(True) class RestoreThread(QThread): """ run restore in a separate Thread to prevent GUI freeze and speed up restore """ def __init__(self, parent): super().__init__() self.parent = parent self.log = parent._log_file.open('wt', encoding='utf-8') self.mutex = QMutex() self.buffer = '' def run(self): """Run the thread""" with InhibitSuspend(reason='restoring'): self.parent.snapshots.restore( self.parent.sid, self.parent.what, self.callback, self.parent.where, **self.parent.kwargs) self.log.close() def callback(self, line, *_args): """ write into log file and provide thread save string for log window """ line += '\n' self.log.write(line) self.mutex.lock() self.buffer += line self.mutex.unlock() backintime-1.6.1/qt/serviceHelper.py000066400000000000000000000352041514264426600174410ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2004-2006 Red Hat Inc. # SPDX-FileCopyrightText: © 2005-2007 Collabora Ltd. # SPDX-FileCopyrightText: © 2008 Canonical Ltd. # SPDX-FileCopyrightText: © 2009 David D. Lowe # SPDX-FileCopyrightText: © 2015-2022 Germar Reitze # SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: MIT # SPDX-License-Identifier: CC0-1.0 # # This file is released under several licenses mentioned above. The file is # part of the program "Back In Time". The program as a whole is released under # GNU General Public License v2 (GPLv2). See LICENSES directory or go to # - . # - # - # # Note about the licenses by Christian Buhtz (2024-09): # Despite extensive research and attempts to contact the aforementioned # individuals and institutions, it was not possible to definitively determine # which of the mentioned licenses and copyright notices apply to which parts of # the code contained in this file. The situation could not be clarified even # with the git commit history. # It should be noted that, in case of doubt, preference should be given to the # strongest or most restrictive license. # # Before SPDX meta data was added to the file it originally had some comments # that are summarized as follows: # - Germar Reitze claimed GPL-2.0-or-later in context of Back In Time. # - Unknown person claimed GPL-2.0-or-later in context of "jockey". # - Read Hat Inc. and Collabora Ltd. claimed MIT License in context of # "python-dbus-docs" # - David D. Lowe claimed CC0-1.0 (public domain) in unknown context. # # Because of MIT License the following permission notice need to be included # in this file and should not be removed: # --- Begin of MIT License permission notice --- # 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. # --- End of MIT License permission notice --- """Handling udev rules via DBUS service""" import os import re from subprocess import Popen, PIPE try: import pwd except ImportError: pwd = None import dbus import dbus.service import dbus.mainloop # pylint: disable-next=import-error,useless-suppression import dbus.mainloop.pyqt6 # pylint: disable-next=import-error,useless-suppression from dbus.mainloop.pyqt6 import DBusQtMainLoop from PyQt6.QtCore import QCoreApplication UDEV_RULES_PATH = '/etc/udev/rules.d/99-backintime-%s.rules' class InvalidChar(dbus.DBusException): """Exception about invalid characters""" _dbus_error_name = 'net.launchpad.backintime.InvalidChar' class InvalidCmd(dbus.DBusException): """EXception about an invalid command""" _dbus_error_name = 'net.launchpad.backintime.InvalidCmd' class LimitExceeded(dbus.DBusException): """Exception about a reached limit in several contexts""" _dbus_error_name = 'net.launchpad.backintime.LimitExceeded' class PermissionDeniedByPolicy(dbus.DBusException): """Exception about denied permissions""" _dbus_error_name = 'com.ubuntu.DeviceDriver.PermissionDeniedByPolicy' class UdevRules(dbus.service.Object): """DBus object to manage Udev rules""" def __init__(self, conn=None, object_path=None, bus_name=None): super(UdevRules, self).__init__(conn, object_path, bus_name) # the following variables are used by _checkPolkitPrivilege self.polkit = None self.enforce_polkit = True self.tmpDict = {} self.su = self._which('su', '/bin/su') self.backintime = self._which('backintime', '/usr/bin/backintime') self.max_rules = 100 self.max_users = 20 self.max_cmd_len = 120 # was 100 before but was too small (see #1027) def _which(self, exe, fallback): proc = Popen(['which', exe], stdout=PIPE) ret = proc.communicate() # ret = proc.communicate()[0].strip().decode() ret = ret[0].strip().decode() if proc.returncode or not ret: return fallback return ret def _validateCmd(self, cmd): """ ??? """ if cmd.find("&&") != -1: raise InvalidCmd("Parameter 'cmd' contains '&&' concatenation") # make sure it starts with an absolute path if not cmd.startswith(os.path.sep): raise InvalidCmd( f'Parameter "cmd" does not start with "{os.path.sep}"') # make sure only well known commands and switches are used whitelist = ( ( # command itself self._which('nice', '/usr/bin/nice'), # command options/switches beginning with "-n" r'^-n' ), ( # command itself self._which('ionice', '/usr/bin/ionice'), # command options/switches beginning with "-c" or "-n" r'(^-c|^-n)' ), ) parts = cmd.split() # Remove whitelisted commands and their options/switches while parts: for c, switches in whitelist: # whitelist command? if parts[0] == c: # remove from parts list parts.pop(0) # every whitelisted option/switch while parts and re.match(switches, parts[0]): # remove from parts list parts.pop(0) break else: break # See what's left in parts if not parts: msg = "Parameter 'cmd' does not contain the backintime command" msg = f'{msg}\n{cmd=}\nrest of {parts=}' raise InvalidCmd(msg) if parts[0] != self.backintime: msg = "Parameter 'cmd' contains non-whitelisted cmd/parameter " \ f"({parts[0]})" msg = f'{msg}\n{cmd=}\nrest of {parts=}' raise InvalidCmd(msg) def _checkLimits(self, owner, cmd): if len(self.tmpDict.get(owner, [])) >= self.max_rules: raise LimitExceeded("Maximum number of cached rules reached (%d)" % self.max_rules) elif len(self.tmpDict) >= self.max_users: raise LimitExceeded("Maximum number of cached users reached (%d)" % self.max_users) elif len(cmd) > self.max_cmd_len: raise LimitExceeded("Maximum length of command line reached (%d)" % self.max_cmd_len) @dbus.service.method("net.launchpad.backintime.serviceHelper.UdevRules", in_signature='ss', out_signature='', sender_keyword='sender', connection_keyword='conn') def addRule(self, cmd, uuid, sender=None, conn=None): """Receive command and uuid and create an Udev rule out of this. This is done on the service side to prevent malicious code to run as root. """ # prevent breaking out of su command chars = re.findall(r'[^a-zA-Z0-9-/\.>& ]', cmd) if chars: raise InvalidChar( "Parameter 'cmd' contains invalid character(s) %s" % '|'.join(set(chars))) # only allow relevant chars in uuid chars = re.findall(r'[^a-zA-Z0-9-]', uuid) if chars: raise InvalidChar( "Parameter 'uuid' contains invalid character(s) %s" % '|'.join(set(chars))) self._validateCmd(cmd) info = SenderInfo(sender, conn) user = info.connectionUnixUser() owner = info.nameOwner() self._checkLimits(owner, cmd) # create su command sucmd = f"{self.su} - '{user}' -c '{cmd}'" # create Udev rule rule = 'ACTION=="add|change", ENV{ID_FS_UUID}=="' \ + uuid \ + '", RUN+="' \ + sucmd \ + '"\n' print(f'{sucmd=} {rule=}') # store rule if not owner in self.tmpDict: self.tmpDict[owner] = [] self.tmpDict[owner].append(rule) @dbus.service.method("net.launchpad.backintime.serviceHelper.UdevRules", in_signature='', out_signature='b', sender_keyword='sender', connection_keyword='conn') def save(self, sender=None, conn=None): """Save rules to destination file after user authenticated as admin. This will first check if there are any changes between temporary added rules and current rules in destination file. Returns False if files are identical or no rules to be installed. """ info = SenderInfo(sender, conn) user = info.connectionUnixUser() owner = info.nameOwner() # delete rule if no rules in tmp if not owner in self.tmpDict or not self.tmpDict[owner]: self.delete(sender, conn) return False # return False if rule already exist. if os.path.exists(UDEV_RULES_PATH % user): with open(UDEV_RULES_PATH % user, 'r') as f: if self.tmpDict[owner] == f.readlines(): self._clean(owner) return False # auth to save changes self._checkPolkitPrivilege( sender, conn, 'net.launchpad.backintime.UdevRuleSave') with open(UDEV_RULES_PATH % user, 'w') as f: f.writelines(self.tmpDict[owner]) self._clean(owner) return True @dbus.service.method("net.launchpad.backintime.serviceHelper.UdevRules", in_signature='', out_signature='', sender_keyword='sender', connection_keyword='conn') def delete(self, sender=None, conn=None): """Delete existing Udev rule""" info = SenderInfo(sender, conn) user = info.connectionUnixUser() owner = info.nameOwner() self._clean(owner) if os.path.exists(UDEV_RULES_PATH % user): # auth to delete rule self._checkPolkitPrivilege( sender, conn, 'net.launchpad.backintime.UdevRuleDelete') os.remove(UDEV_RULES_PATH % user) @dbus.service.method("net.launchpad.backintime.serviceHelper.UdevRules", in_signature='', out_signature='', sender_keyword='sender', connection_keyword='conn') def clean(self, sender=None, conn=None): """clean up previous cached rules""" info = SenderInfo(sender, conn) self._clean(info.nameOwner()) def _clean(self, owner): if owner in self.tmpDict: del self.tmpDict[owner] def _initPolkit(self): if self.polkit is None: self.polkit = dbus.Interface(dbus.SystemBus().get_object( 'org.freedesktop.PolicyKit1', '/org/freedesktop/PolicyKit1/Authority', False), 'org.freedesktop.PolicyKit1.Authority') def _checkPolkitPrivilege(self, sender, conn, privilege): # from jockey """ Verify that sender has a given PolicyKit privilege. sender is the sender's (private) D-BUS name, such as ":1:42" (sender_keyword in @dbus.service.methods). conn is the dbus.Connection object (connection_keyword in @dbus.service.methods). privilege is the PolicyKit privilege string. This method returns if the caller is privileged, and otherwise throws a PermissionDeniedByPolicy exception. """ if sender is None and conn is None: # called locally, not through D-BUS return if not self.enforce_polkit: # that happens for testing purposes when running on the session # bus, and it does not make sense to restrict operations here return # query PolicyKit self._initPolkit() try: # We don't need is_challenge return here, since we call # with AllowUserInteraction (is_auth, _unknown, _details) = self.polkit.CheckAuthorization( ( 'system-bus-name', {'name': dbus.String(sender, variant_level=1)} ), privilege, {'': ''}, dbus.UInt32(1), '', timeout=3000 ) except dbus.DBusException as exc: err_name = exc._dbus_error_name if err_name == 'org.freedesktop.DBus.Error.ServiceUnknown': # polkitd timed out, connect again self.polkit = None return self._checkPolkitPrivilege(sender, conn, privilege) else: raise if not is_auth: raise PermissionDeniedByPolicy(privilege) class SenderInfo: """Data structure containing info about a sender using DBus""" def __init__(self, sender, conn): self.sender = sender self.dbus_info = dbus.Interface( conn.get_object( 'org.freedesktop.DBus', '/org/freedesktop/DBus/Bus', False), 'org.freedesktop.DBus' ) def connectionUnixUser(self): uid = self.dbus_info.GetConnectionUnixUser(self.sender) if pwd: return pwd.getpwuid(uid).pw_name return uid def nameOwner(self): return self.dbus_info.GetNameOwner(self.sender) def connectionPid(self): return self.dbus_info.GetConnectionUnixProcessID(self.sender) if __name__ == '__main__': DBusQtMainLoop(set_as_default=True) app = QCoreApplication([]) bus = dbus.SystemBus() name = dbus.service.BusName("net.launchpad.backintime.serviceHelper", bus) object = UdevRules(bus, '/UdevRules') app.exec() backintime-1.6.1/qt/shutdowndlg.py000066400000000000000000000057651514264426600172140ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Huaide Jiang # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about showing a confirmation dialog before shutting down.""" import gettext from PyQt6.QtWidgets import (QDialog, QLabel, QPushButton, QVBoxLayout, QHBoxLayout) from PyQt6.QtCore import QTimer, Qt class ConfirmShutdownDlg(QDialog): """A dialog ask for confirmation to shutdown the system and assuming confirmation after finish a countdown.""" # pylint: disable=too-few-public-methods def __init__(self, countdown: int): super().__init__() self.countdown = countdown # Initialize UI components self.setWindowTitle(_('Countdown to Shutdown')) self.label1 = QLabel(_('The backup has finished.'), self) self.label2 = QLabel('', self) self._update_countdown() # Center the label texts self.label1.setAlignment(Qt.AlignmentFlag.AlignCenter) self.label2.setAlignment(Qt.AlignmentFlag.AlignCenter) self.cancel_button = QPushButton(_('Cancel Shutdown'), self) self.shutdown_button = QPushButton(_('Shutdown Now'), self) self.cancel_button.clicked.connect(self._cancel_shutdown) # Immediately accept on shutdown now self.shutdown_button.clicked.connect(self.accept) # Layout setup layout = QVBoxLayout() layout.addWidget(self.label1, alignment=Qt.AlignmentFlag.AlignHCenter) layout.addWidget(self.label2, alignment=Qt.AlignmentFlag.AlignHCenter) # Button layout button_layout = QHBoxLayout() button_layout.addWidget(self.cancel_button) button_layout.addWidget(self.shutdown_button) layout.addLayout(button_layout) self.setLayout(layout) # Initialize timer self.timer = QTimer(self) self.timer.timeout.connect(self._update_countdown) self.timer.start(1000) def _update_countdown(self): self.countdown -= 1 if self.countdown <= 0: self.timer.stop() self.accept() self.label2.setText(gettext.ngettext( 'The system will shut down in {n} second.', 'The system will shut down in {n} seconds.', self.countdown).format(n=self.countdown)) def _cancel_shutdown(self): self.timer.stop() self.reject() def get_shutdown_confirmation(countdown: int = 31) -> bool: """Ask user to confirm the shutdown while running a countdown. Args: countdown: Countdown in seconds. Returns: Confirm shutdown if user has not answered, or users answer. """ dialog = ConfirmShutdownDlg(countdown) result = dialog.exec() return result == QDialog.DialogCode.Accepted backintime-1.6.1/qt/snapshotsdialog.py000066400000000000000000000416051514264426600200450ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Stuff around the snapshots dialog. That dialog will be removed and its functionality integrated into the main window and its timeline widget.""" import os import subprocess import shlex from PyQt6.QtGui import QDesktopServices from PyQt6.QtWidgets import (QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, QPushButton, QToolBar, QVBoxLayout) from PyQt6.QtCore import (Qt, QThread, QUrl) from timeline import TimeLine from bitwidgets import SnapshotCombo import tools import restoredialog import messagebox import snapshots import logger from inhibitsuspend import InhibitSuspend DIFF_PARAMS = '%1 %2' if tools.checkCommand('meld'): DIFF_CMD = 'meld' elif tools.checkCommand('kompare'): DIFF_CMD = 'kompare' else: DIFF_CMD = '' class DiffOptionsDialog(QDialog): """Dialog to setup diff options""" def __init__(self, parent): super(DiffOptionsDialog, self).__init__(parent) self.config = parent.config import icon self.setWindowIcon(icon.DIFF_OPTIONS) self.setWindowTitle(_('Options about comparing backups')) self.mainLayout = QGridLayout(self) cmd = self.config.strValue('qt.diff.cmd', DIFF_CMD) params = self.config.strValue('qt.diff.params', DIFF_PARAMS) self.mainLayout.addWidget(QLabel(_('Command:')), 0, 0) self.editCmd = QLineEdit(cmd, self) self.mainLayout.addWidget(self.editCmd, 0, 1) self.mainLayout.addWidget(QLabel(_('Parameters:')), 1, 0) self.editParams = QLineEdit(params, self) self.mainLayout.addWidget(self.editParams, 1, 1) self.mainLayout.addWidget( QLabel(_('Use %1 and %2 for path parameters')), 2, 1) buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) self.mainLayout.addWidget(buttonBox, 3, 0, 3, 2) def accept(self): """OK was clicked""" # Get values from text dialogs fields cmd = self.editCmd.text() params = self.editParams.text() # Any value? if not cmd: messagebox.info(_('Please set a diff command or press Cancel.')) return # Command exists? if not tools.checkCommand(cmd): messagebox.info(_( 'The command "{cmd}" cannot be found on this system. Please ' 'try something else or press Cancel.').format(cmd=cmd)) return if not params: params = DIFF_PARAMS messagebox.critical( self, _('No parameters set for the diff command. Using ' 'default value "{params}".').format(params=params)) # save new values self.config.setStrValue('qt.diff.cmd', cmd) self.config.setStrValue('qt.diff.params', params) self.config.save() super(DiffOptionsDialog, self).accept() class SnapshotsDialog(QDialog): """The main snapshots dialog Dev note (buhtz, 2025-07-29): Scheduled to removed and replaced be features in the main window. """ def __init__(self, parent, sid, path): super(SnapshotsDialog, self).__init__(parent) self.parent = parent self.config = parent.config self.snapshots = parent.snapshots self.snapshotsList = parent.snapshotsList self.qapp = parent.qapp import icon self.sid = sid self.path = path self.setWindowIcon(icon.SNAPSHOTS) self.setWindowTitle(_('Backups')) self.mainLayout = QVBoxLayout(self) # path self.editPath = QLineEdit(self.path, self) self.editPath.setReadOnly(True) self.mainLayout.addWidget(self.editPath) # list different snapshots only self.cbOnlyDifferentSnapshots = QCheckBox( _('Differing backups only'), self) self.mainLayout.addWidget(self.cbOnlyDifferentSnapshots) self.cbOnlyDifferentSnapshots.stateChanged.connect( self.cbOnlyDifferentSnapshotsChanged) # list equal snapshots only layout = QHBoxLayout() self.mainLayout.addLayout(layout) self.cbOnlyEqualSnapshots = QCheckBox( _('List only backups that are equal to:'), self) self.cbOnlyEqualSnapshots.stateChanged.connect( self.cbOnlyEqualSnapshotsChanged) layout.addWidget(self.cbOnlyEqualSnapshots) self.comboEqualTo = SnapshotCombo(self) self.comboEqualTo.currentIndexChanged.connect(self.comboEqualToChanged) self.comboEqualTo.setEnabled(False) layout.addWidget(self.comboEqualTo) # deep check self.cbDeepCheck = QCheckBox( _('Deep check (more accurate, but slow)'), self) self.mainLayout.addWidget(self.cbDeepCheck) self.cbDeepCheck.stateChanged.connect(self.cbDeepCheckChanged) # toolbar self.toolbar = QToolBar(self) self.toolbar.setFloatable(False) self.mainLayout.addWidget(self.toolbar) # toolbar restore menuRestore = QMenu(self) action = menuRestore.addAction(icon.RESTORE, _('Restore')) action.triggered.connect(self.restoreThis) action = menuRestore.addAction(icon.RESTORE_TO, _('Restore to …')) action.triggered.connect(self.restoreThisTo) self.btnRestore = self.toolbar.addAction(icon.RESTORE, _('Restore')) self.btnRestore.setMenu(menuRestore) self.btnRestore.triggered.connect(self.restoreThis) # btn delete self.btnDelete = self.toolbar.addAction(icon.DELETE_FILE, _('Delete')) self.btnDelete.triggered.connect(self.btnDeleteClicked) # btn select_all self.btnSelectAll = self.toolbar.addAction( icon.SELECT_ALL, _('Select All')) self.btnSelectAll.triggered.connect(self.btnSelectAllClicked) # snapshots list self.timeLine = TimeLine(self) self.mainLayout.addWidget(self.timeLine) self.timeLine.itemSelectionChanged.connect(self.timeLineChanged) self.timeLine.itemActivated.connect(self.timeLineExecute) # Diff layout = QHBoxLayout() self.mainLayout.addLayout(layout) self.btnDiff = QPushButton(_('Compare'), self) layout.addWidget(self.btnDiff) self.btnDiff.clicked.connect(self.btnDiffClicked) self._update_btn_diff() self.comboDiff = SnapshotCombo(self) layout.addWidget(self.comboDiff, 2) # buttons buttonBox = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) self.btnGoto = buttonBox.button(QDialogButtonBox.StandardButton.Ok) self.btnCancel = buttonBox.button( QDialogButtonBox.StandardButton.Cancel) self.btnGoto.setText(_('Go To')) btnDiffOptions = buttonBox.addButton( _('Options'), QDialogButtonBox.ButtonRole.HelpRole) btnDiffOptions.setIcon(icon.DIFF_OPTIONS) self.mainLayout.addWidget(buttonBox) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) btnDiffOptions.clicked.connect(self.btnDiffOptionsClicked) self.cbDeepCheck.setEnabled(False) full_path = self.sid.pathBackup(self.path) if os.path.islink(full_path): self.cbDeepCheck.hide() elif os.path.isdir(full_path): self.cbOnlyDifferentSnapshots.hide() self.cbOnlyEqualSnapshots.hide() self.comboEqualTo.hide() self.cbDeepCheck.hide() # update list and combobox self.UpdateSnapshotsAndComboEqualTo() def addSnapshot(self, sid): self.timeLine.addSnapshot(sid) # add to combo self.comboDiff.add_snapshot_id(sid) if self.sid == sid: self.comboDiff.set_current_snapshot_id(sid) self.comboDiff.check_selection() def updateSnapshots(self): self.timeLine.clear() self.comboDiff.clear() equal_to_sid = self.comboEqualTo.current_snapshot_id() if self.cbOnlyEqualSnapshots.isChecked() and equal_to_sid: equal_to = equal_to_sid.pathBackup(self.path) else: equal_to = False snapshotsFiltered = self.snapshots.filter( base_sid=self.sid, base_path=self.path, snapshotsList=self.snapshotsList, list_diff_only=self.cbOnlyDifferentSnapshots.isChecked(), flag_deep_check=self.cbDeepCheck.isChecked(), list_equal_to=equal_to ) for sid in snapshotsFiltered: self.addSnapshot(sid) self.updateToolbar() def UpdateComboEqualTo(self): self.comboEqualTo.clear() snapshotsFiltered = self.snapshots.filter( self.sid, self.path, self.snapshotsList) for sid in snapshotsFiltered: self.comboEqualTo.add_snapshot_id(sid) if sid == self.sid: self.comboEqualTo.set_current_snapshot_id(sid) self.comboEqualTo.check_selection() def UpdateSnapshotsAndComboEqualTo(self): self.updateSnapshots() self.UpdateComboEqualTo() def cbOnlyDifferentSnapshotsChanged(self): enabled = self.cbOnlyDifferentSnapshots.isChecked() self.cbOnlyEqualSnapshots.setEnabled(not enabled) self.cbDeepCheck.setEnabled(enabled) self.updateSnapshots() def cbOnlyEqualSnapshotsChanged(self): enabled = self.cbOnlyEqualSnapshots.isChecked() self.comboEqualTo.setEnabled(enabled) self.cbOnlyDifferentSnapshots.setEnabled(not enabled) self.cbDeepCheck.setEnabled(enabled) self.updateSnapshots() def cbDeepCheckChanged(self): self.updateSnapshots() def updateToolbar(self): sids = self.timeLine.selected_snapshot_ids() if not sids: enable_restore = False enable_delete = False elif len(sids) == 1: enable_restore = not sids[0].isRoot enable_delete = not sids[0].isRoot else: enable_restore = False enable_delete = True for sid in sids: if sid.isRoot: enable_delete = False self.btnRestore.setEnabled(enable_restore) self.btnDelete.setEnabled(enable_delete) def restoreThis(self): # See #1485 as related bug report sid = self.timeLine.current_snapshot_id() if not sid.isRoot: # pylint: disable-next=E1101 restoredialog.restore(self, sid, self.path) def restoreThisTo(self): # See #1485 as related bug report sid = self.timeLine.current_snapshot_id() if not sid.isRoot: # pylint: disable-next=E1101 restoredialog.restore(self, sid, self.path, None) def timeLineChanged(self): self.updateToolbar() def timeLineExecute(self, _item, _column): # Ctrl button pressed, indicates ongoing multiselection? modifiers = self.qapp.keyboardModifiers() if Qt.KeyboardModifier.ControlModifier in modifiers: return sid = self.timeLine.current_snapshot_id() if not sid: return full_path = sid.pathBackup(self.path) if not os.path.exists(full_path): return # prevent backup data from being accidentally overwritten # by create a temporary local copy and only open that one if not isinstance(self.sid, snapshots.RootSnapshot): full_path = self.parent._create_temporary_copy(full_path, sid) QDesktopServices.openUrl(QUrl(full_path)) def btnDiffClicked(self): sid1 = self.timeLine.current_snapshot_id() sid2 = self.comboDiff.current_snapshot_id() if not sid1 or not sid2: return path1 = sid1.pathBackup(self.path) path2 = sid2.pathBackup(self.path) # check if the 2 paths are different if path1 == path2: messagebox.critical( self, _('It is not possible to compare a backup to ' 'itself, as the comparison would be redundant.') ) return diffCmd = self.config.strValue('qt.diff.cmd', DIFF_CMD) diffParams = self.config.strValue('qt.diff.params', DIFF_PARAMS) # prevent backup data from being accidentally overwritten # by create a temporary local copy and only open that one if not isinstance(sid1, snapshots.RootSnapshot): path1 = self.parent._create_temporary_copy(path1, sid1) if not isinstance(sid2, snapshots.RootSnapshot): path2 = self.parent._create_temporary_copy(path2, sid2) params = diffParams params = params.replace('%1', '"%s"' % path1) params = params.replace('%2', '"%s"' % path2) cmd = diffCmd + ' ' + params logger.debug(f'Compare two backups with command {cmd}.') subprocess.Popen(shlex.split(cmd)) def _update_btn_diff(self): """Enable the Compare button if diff command is set otherwise Disable it.""" cmd = self.config.strValue('qt.diff.cmd', DIFF_CMD) self.btnDiff.setDisabled(not cmd) def btnDiffOptionsClicked(self): DiffOptionsDialog(self).exec() self._update_btn_diff() def comboEqualToChanged(self, _index): self.updateSnapshots() def btnDeleteClicked(self): items = self.timeLine.selectedItems() if not items: return if len(items) == 1: msg = _( 'Really delete {file_or_dir} in backup {backup_id}?').format( file_or_dir=f'"{self.path}"', backup_id=f'"{items[0].snapshot_id}"') else: msg = _('Really delete {file_or_dir} in {count} backups?').format( file_or_dir=f'"{self.path}"', count=len(items)) msg = msg + '\n' + _('WARNING: This cannot be revoked.') if messagebox.question(msg): for item in items: item.setFlags(Qt.ItemFlag.NoItemFlags) thread = RemoveFileThread(self, items) thread.started.connect(lambda: self.btnGoto.setDisabled(True)) thread.finished.connect(lambda: self.btnGoto.setDisabled(False)) thread.started.connect(lambda: self.btnDelete.setDisabled(True)) thread.finished.connect(lambda: self.btnDelete.setDisabled(False)) thread.finished.connect(self.UpdateSnapshotsAndComboEqualTo) self.btnCancel.clicked.connect(thread.terminate) thread.start() exclude = self.config.exclude() msg = _('Exclude {path} from future backups?').format( path=f'"{self.path}"') if self.path not in exclude: if messagebox.question(msg): exclude.append(self.path) self.config.setExclude(exclude) def btnSelectAllClicked(self): """ select all expect 'Now' """ self.timeLine.clearSelection() for item in self.timeLine.iter_snapshot_items(): if not isinstance(item.snapshot_id, snapshots.RootSnapshot): item.setSelected(True) def accept(self): sid = self.timeLine.current_snapshot_id() if sid: self.sid = sid super(SnapshotsDialog, self).accept() class RemoveFileThread(QThread): """ remove files in background thread so GUI will not freeze """ def __init__(self, parent, items): self.parent = parent # self.config = parent.config self.snapshots = parent.snapshots self.items = items super(RemoveFileThread, self).__init__(parent) def run(self): with InhibitSuspend(reason='deleting files'): for item in self.items: self.snapshots.deletePath(item.snapshot_id, self.parent.path) try: item.setHidden(True) except RuntimeError: # item has been deleted # probably because user refreshed treeview pass backintime-1.6.1/qt/statedata.py000066400000000000000000000352311514264426600166130ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Management of the state file.""" # pylint: disable=wrong-import-position,wrong-import-order from __future__ import annotations import os import json from pathlib import Path from datetime import datetime, timezone from copy import deepcopy from qttools_path import register_backintime_path register_backintime_path('common') import singleton # noqa: E402 import logger # noqa: E402 import tools # noqa: E402 from version import __version__ # noqa: E402 # pylint: disable-next=too-many-public-methods class StateData(dict, metaclass=singleton.Singleton): """Manage state data for Back In Time. Dev note (buhtz, 2024-12): It is usually recommended and preferred to derive from `collections.UserDict` instead of just `dict`. But this conflicts with the ``metaclass=``. To my current knowledge this is not a big deal and won't introduce any problems. """ # pylint: disable=too-many-instance-attributes # The default structure. All properties do rely on them and assuming # it is there. _EMPTY_STRUCT = { 'gui': { 'mainwindow': { 'files_view': {}, 'last_path': {}, 'places_sorting': {}, }, 'manage_profiles': { 'incl_sorting': {}, 'excl_sorting': {}, 'dims': {}, }, 'logview': {}, 'user_callback_edit': {}, }, 'message': { 'encfs': {} }, } class Profile: """A surrogate to access profile-specific state data.""" def __init__(self, profile_id: str, state: StateData): self._state = state self._profile_id = profile_id @property def msg_encfs(self) -> int: """Stage of EncFS deprecation warning shown as last.""" try: return self._state['message']['encfs'][self._profile_id] except KeyError: self.msg_encfs = 0 return self.msg_encfs @msg_encfs.setter def msg_encfs(self, val: int) -> None: self._state['message']['encfs'][self._profile_id] = val @property def last_path(self) -> Path: """Last path used in the GUI. Raises: KeyError """ return Path(self._state['gui']['mainwindow'][ 'last_path'][self._profile_id]) @last_path.setter def last_path(self, path: Path) -> None: self._state['gui']['mainwindow'][ 'last_path'][self._profile_id] = str(path) @property def places_sorting(self) -> tuple[int, int]: """Column index and sort order. Returns: Tuple with column index and its sorting order (0=ascending). """ return self._state['gui']['mainwindow'][ 'places_sorting'][self._profile_id] @places_sorting.setter def places_sorting(self, vals: tuple[int, int]) -> None: self._state['gui']['mainwindow'][ 'places_sorting'][self._profile_id] = vals @property def exclude_sorting(self) -> tuple[int, int]: """Column index and sort order. Returns: Tuple with column index and its sorting order (0=ascending). """ return self._state['gui']['manage_profiles'][ 'excl_sorting'][self._profile_id] @exclude_sorting.setter def exclude_sorting(self, vals: tuple[int, int]) -> None: self._state['gui']['manage_profiles'][ 'excl_sorting'][self._profile_id] = vals @property def include_sorting(self) -> tuple[int, int]: """Column index and sort order. Returns: Tuple with column index and its sorting order (0=ascending). """ return self._state['gui']['manage_profiles'][ 'incl_sorting'][self._profile_id] @include_sorting.setter def include_sorting(self, vals: tuple[int, int]) -> None: self._state['gui']['manage_profiles'][ 'incl_sorting'][self._profile_id] = vals @staticmethod def file_path() -> Path: """Returns the state file path.""" xdg_state = os.environ.get('XDG_STATE_HOME', None) if xdg_state: xdg_state = Path(xdg_state) else: xdg_state = Path.home() / '.local' / 'state' fp = xdg_state / 'backintime-qt.json' logger.debug(f'State file path: {fp}') return fp def __init__(self, data: dict = None): """Constructor.""" # default full = deepcopy(self._EMPTY_STRUCT) if data: full = tools.nested_dict_update(full, data) super().__init__(full) def __str__(self): return json.dumps(self, indent=4) def _set_save_meta_data(self): meta = { 'saved': datetime.now().isoformat(), 'saved_utc': datetime.now(timezone.utc).isoformat(), 'bitversion': __version__, } self['_meta'] = meta def save(self): """Store application state data to a file.""" logger.debug('Save state data.') self._set_save_meta_data() fp = self.file_path() fp.parent.mkdir(parents=True, exist_ok=True) with fp.open('w', encoding='utf-8') as handle: handle.write(str(self)) def profile(self, profile_id: str) -> StateData.Profile: """Return a `Profile` object related to the given id. Args: profile_id: A profile_id of a snapshot profile. Returns: A profile surrogate. Raises: KeyError: If profile does not exists. """ return StateData.Profile(profile_id=profile_id, state=self) def manual_starts_countdown(self) -> int: """Countdown value about how often the users started the Back In Time GUI. At the end of the countown the `ApproachTranslatorDialog` is presented to the user. """ return self.get('manual_starts_countdown', 10) def decrement_manual_starts_countdown(self): """Counts down to -1. See :py:func:`manual_starts_countdown()` for details. """ val = self.manual_starts_countdown() if val > -1: self['manual_starts_countdown'] = val - 1 @property def msg_release_candidate(self) -> str: """Last version of Back In Time in which the release candidate message box was displayed. """ try: return self['message']['release_candidate'] except KeyError: self.msg_release_candidate = None return self.msg_release_candidate @msg_release_candidate.setter def msg_release_candidate(self, val: str) -> None: self['message']['release_candidate'] = val @property def msg_language_remove(self) -> bool: """Language planned for removal message shown.""" try: return self['message']['language_remove'] except KeyError: self.msg_language_remove = False return self.msg_language_remove @msg_language_remove.setter def msg_language_remove(self, val: bool) -> None: self['message']['language_remove'] = val @property def msg_cipher_deprecation(self) -> bool: """Cipher deprecation message shown.""" try: return self['message']['cipher_deprecation'] except KeyError: self.msg_cipher_deprecation = False return self.msg_cipher_deprecation @msg_cipher_deprecation.setter def msg_cipher_deprecation(self, val: bool) -> None: self['message']['cipher_deprecation'] = val @property def msg_encfs_global(self) -> int: """Last stage of global EncFS deprecation message that was shown.""" try: return self['message']['encfs']['global'] except KeyError: self.msg_encfs_global = 0 return self.msg_encfs_global @msg_encfs_global.setter def msg_encfs_global(self, val: int) -> None: self['message']['encfs']['global'] = val @property def mainwindow_show_hidden(self) -> bool: """Show hidden files in files view.""" try: return self['gui']['mainwindow']['show_hidden'] except KeyError: self.mainwindow_show_hidden = False return self.mainwindow_show_hidden @mainwindow_show_hidden.setter def mainwindow_show_hidden(self, val: bool) -> None: self['gui']['mainwindow']['show_hidden'] = val @property def mainwindow_maximized(self) -> bool: """Main window maximized state""" return self.mainwindow_dims == [-1, -1] def set_mainwindow_maximized(self): """Main window is maximized state""" self.mainwindow_dims = [-1, -1] @property def mainwindow_dims(self) -> tuple[int, int]: """Dimensions of the main window. Raises: KeyError """ return self['gui']['mainwindow']['dims'] @mainwindow_dims.setter def mainwindow_dims(self, vals: tuple[int, int]) -> None: self['gui']['mainwindow']['dims'] = vals @property def mainwindow_coords(self) -> tuple[int, int]: """Coordinates (position) of the main window. Raises: KeyError """ return self['gui']['mainwindow']['coords'] @mainwindow_coords.setter def mainwindow_coords(self, vals: tuple[int, int]) -> None: self['gui']['mainwindow']['coords'] = vals @property def logview_dims(self) -> tuple[int, int]: """Dimensions of the log view dialog. Raises: KeyError """ try: return self['gui']['logview']['dims'] except KeyError: self.logview_dims = (800, 500) return self.logview_dims @logview_dims.setter def logview_dims(self, vals: tuple[int, int]) -> None: self['gui']['logview']['dims'] = vals @property def files_view_sorting(self) -> tuple[int, int]: """Column index and sort order. Returns: Tuple with column index and its sorting order (0=ascending). """ try: return self['gui']['mainwindow']['files_view']['sorting'] except KeyError: self.files_view_sorting = (0, 0) return self.files_view_sorting @files_view_sorting.setter def files_view_sorting(self, vals: tuple[int, int]) -> None: self['gui']['mainwindow']['files_view']['sorting'] = vals @property def files_view_col_widths(self) -> tuple: """Widths of columns in the files view.""" return self['gui']['mainwindow']['files_view']['col_widths'] @files_view_col_widths.setter def files_view_col_widths(self, widths: tuple) -> None: self['gui']['mainwindow']['files_view']['col_widths'] = widths @property def mainwindow_main_splitter_widths(self) -> tuple[int, int]: """Left and right width of main splitter in main window. Returns: Two entry tuple with right and left widths. """ try: return self['gui']['mainwindow']['splitter_main_widths'] except KeyError: self.mainwindow_main_splitter_widths = (150, 450) return self.mainwindow_main_splitter_widths @mainwindow_main_splitter_widths.setter def mainwindow_main_splitter_widths(self, vals: tuple[int, int]) -> None: self['gui']['mainwindow']['splitter_main_widths'] = vals @property def mainwindow_second_splitter_widths(self) -> tuple[int, int]: """Left and right width of second splitter in main window. Returns: Two entry tuple with right and left widths. """ try: return self['gui']['mainwindow']['splitter_second_widths'] except KeyError: self.mainwindow_second_splitter_widths = (150, 300) return self.mainwindow_second_splitter_widths @mainwindow_second_splitter_widths.setter def mainwindow_second_splitter_widths(self, vals: tuple[int, int]) -> None: self['gui']['mainwindow']['splitter_second_widths'] = vals @property def toolbar_button_style(self) -> int: """Style of icons for the main toolbar. Returns: Style value as integer (default: 0 as ``ToolButtonIconOnly``) """ try: return self['gui']['mainwindow']['toolbar_button_style'] except KeyError: self.toolbar_button_style = 0 return self.toolbar_button_style @toolbar_button_style.setter def toolbar_button_style(self, value) -> None: self['gui']['mainwindow']['toolbar_button_style'] = value def get_manageprofiles_dims_coords(self, profile_mode: str ) -> tuple[tuple[int, int], tuple[int, int]]: """Dimension and coordinates of the Manage Profiles dialog window""" return ( self['gui']['manage_profiles']['dims'][profile_mode], self['gui']['manage_profiles']['coords'] ) def set_manageprofiles_dims_coords(self, profile_mode: str, dims: tuple[int, int], coords: tuple[int, int]): """Dimension and coordinates of the Manage Profiles dialog window""" self['gui']['manage_profiles']['dims'][profile_mode] = dims self['gui']['manage_profiles']['coords'] = coords @property def user_callback_edit_dims(self) -> tuple[int, int]: """Dimensions of the user-callback edit dialog. Raises: KeyError """ return self['gui']['user_callback_edit']['dims'] @user_callback_edit_dims.setter def user_callback_edit_dims(self, vals: tuple[int, int]) -> None: self['gui']['user_callback_edit']['dims'] = vals @property def user_callback_edit_coords(self) -> tuple[int, int]: """Coordinates (position) of the user-callback edit dialog. Raises: KeyError """ return self['gui']['user_callback_edit']['coords'] @user_callback_edit_coords.setter def user_callback_edit_coords(self, vals: tuple[int, int]) -> None: self['gui']['user_callback_edit']['coords'] = vals backintime-1.6.1/qt/statusbar.py000066400000000000000000000103101514264426600166400ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """A module offering a status bar widget """ from PyQt6.QtWidgets import (QFrame, QHBoxLayout, QLabel, QMainWindow, QProgressBar, QSizePolicy, QStatusBar, QWidget, ) from PyQt6.QtCore import QEvent from PyQt6.QtGui import QPalette, QColor import bitbase import qttools _PROGRESS_BAR_WIDTH_FX = 10 class StatusBar(QStatusBar): """A status bar widget""" def __init__(self, main_window: QMainWindow): super().__init__(parent=main_window) self.main_window = main_window # Root mode indicator self._root = self._root_mode_indicator() # A container widget give us more control about layout details container = QWidget(self) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) container.setLayout(layout) # Status text self._status = QLabel(container) self._status.setWordWrap(False) self._status.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) # Progress bar self._progress = QProgressBar(container) self._progress.setRange(0, 100) self._progress.setValue(0) self._progress.setTextVisible(False) self._progress.setVisible(False) # Layout if self._root: layout.addWidget(self._root) layout.addWidget(self._status, stretch=_PROGRESS_BAR_WIDTH_FX-1) layout.addStretch(0) layout.addWidget(self._progress, stretch=1) self.addPermanentWidget(container, 1) container.resizeEvent = self._on_resize def _on_resize(self, event: QEvent) -> None: """Set the status label with in pixels, but relative. The width is a fraction of the statusbar full width, considering the width of the progressbar, which is also defined by a fraction. """ width = self._status.parentWidget().width() width = width * (1 - (1 / _PROGRESS_BAR_WIDTH_FX)) self._status.setMaximumWidth(int(width)) event.accept() def _root_mode_indicator(self) -> QLabel: if not bitbase.IS_IN_ROOT_MODE: return None root = QLabel(_('Root mode')) root.setToolTip(_( 'Back In Time is currently running with root ' 'privileges (full system access)')) root.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken) font = root.font() font.setBold(True) root.setFont(font) if qttools.in_dark_mode(root): # dark red & white bg_color = '#aa0000' text_color = '#ffffff' else: # light pink & dark red bg_color = '#ffdddd' text_color = '#aa0000' palette = root.palette() palette.setColor(QPalette.ColorRole.Window, QColor(bg_color)) palette.setColor(QPalette.ColorRole.WindowText, QColor(text_color)) root.setAutoFillBackground(True) root.setPalette(palette) return root def set_status_message(self, message: str) -> None: """Set status label text.""" self._status.setText(message) def progress_show(self, show: bool = True) -> None: """Set progress bar widget visible.""" self._progress.setVisible(show) def progress_hide(self) -> None: """Set progress bar widget unvisible.""" self.progress_show(show=False) def set_progress_value(self, val: int) -> None: """Set numeric value of progress bar.""" self._progress.setValue(val) backintime-1.6.1/qt/test/000077500000000000000000000000001514264426600152425ustar00rootroot00000000000000backintime-1.6.1/qt/test/__init__.py000066400000000000000000000000001514264426600173410ustar00rootroot00000000000000backintime-1.6.1/qt/test/test_lint.py000066400000000000000000000356371514264426600176370ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2023 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Tests using several linters. See file common/test/test_lint.py for details. """ import unittest import os import pathlib import subprocess import shutil from typing import Iterable from packaging import version BASE_REASON = ('Using package {0} is mandatory on TravisCI, on ' 'other systems it runs only if `{0}` is available.') ON_TRAVIS = os.environ.get('TRAVIS', '') == 'true' TRAVIS_REASON = ('Running linter tests is mandatory on TravisCI only. On ' 'other machines they will run only if linters available.') PYLINT_AVAILABLE = shutil.which('pylint') is not None RUFF_AVAILABLE = shutil.which('ruff') is not None FLAKE8_AVAILABLE = shutil.which('flake8') is not None ANY_LINTER_AVAILABLE = any(( PYLINT_AVAILABLE, RUFF_AVAILABLE, FLAKE8_AVAILABLE, )) # "qt" directory _base_dir = pathlib.Path(__file__).resolve().parent.parent """ """ # Files in this lists will get the full battery of linters and rule sets. full_test_files = [_base_dir / fp for fp in ( 'aboutdlg.py', # 'app.py', 'bitwidgets.py', 'confirmrestoredialog.py', 'editusercallback.py', 'encfsmsgbox.py', 'filedialog.py', # 'icon.py', 'languagedialog.py', 'logviewdialog.py', 'manageprofiles/__init__.py', 'manageprofiles/combobox.py', 'manageprofiles/copylinkswidget.py', 'manageprofiles/excludesuggestions.py', 'manageprofiles/schedulewidget.py', 'manageprofiles/sectionedchecklist.py', 'manageprofiles/sshkeyselector.py', 'manageprofiles/spinboxunit.py', 'manageprofiles/statebindcheckbox.py', 'manageprofiles/storagesizewidget.py', 'manageprofiles/sshproxywidget.py', 'manageprofiles/tab_exclude.py', 'manageprofiles/tab_expert_options.py', 'manageprofiles/tab_general.py', 'manageprofiles/tab_include.py', 'manageprofiles/tab_options.py', 'manageprofiles/tab_remove_retention.py', 'messagebox.py', 'placeswidget.py', 'plugins/notifyplugin.py', 'plugins/systrayiconplugin.py', # 'qtsystrayicon.py', 'qttools.py', 'qttools_path.py', 'restoreconfigdialog.py', 'restoredialog.py', # 'serviceHelper.py', 'shutdowndlg.py', # 'snapshotsdialog.py', 'statedata.py', 'statusbar.py', 'test/__init__.py', 'test/test_lint.py', 'test/test_statedata.py', 'textdlg.py', 'timeline.py', 'usermessagedialog.py', )] # Not all linters do respect PEP8 (e.g. ruff, PyLint) PEP8_MAX_LINE_LENGTH = 79 def create_pylint_cmd(include_error_codes=None): """Create the pylint base command for later use with subprocess.run(). Args: include_error_codes: List of exclusive rules to check for. If empty all default rules are checked. """ cmd = [ 'pylint', # Make sure BIT modules can be imported (to detect "no-member") '--init-hook=import sys;' 'sys.path.insert(0, "./../qt");' 'sys.path.insert(0, "./../common");', # Storing results in a pickle file is unnecessary '--persistent=n', # autodetec number of parallel jobs '--jobs=0', # Disable scoring ("Your code has been rated at xx/10") '--score=n', # prevent false-positive no-module-member errors '--extension-pkg-allow-list=PyQt6,PyQt6.QtCore', # Because of globally installed GNU gettext functions '--additional-builtins=_,ngettext', # PEP8 conform line length (see PyLint Issue #3078) f'--max-line-length={PEP8_MAX_LINE_LENGTH}', # Whitelist variable names '--good-names=idx,fp,closeEvent', ] if include_error_codes: # Deactivate all checks by default cmd.append('--disable=all') # Include specific codes only cmd.append('--enable=' + ','.join(include_error_codes)) return cmd @unittest.skipUnless(ON_TRAVIS or ANY_LINTER_AVAILABLE, TRAVIS_REASON) class MirrorMirrorOnTheWall(unittest.TestCase): """Check all py-files in the package (incl. test files) for lints, potential bugs and if they are compliant to the coding styles (e.g. PEP8). """ @classmethod def _collect_py_files(cls) -> Iterable[pathlib.Path]: """All py-files related to that distribution package. Dev note (2023-11): Use package metadata after migration to pyproject.toml. """ path = pathlib.Path.cwd() # Make sure we are inside the test folder if path.name in ['qt', 'common']: # happens e.g. on TravisCI path = path / 'test' if not path.name.startswith('test'): raise RuntimeError('Something went wrong. The test should run ' 'inside the test folder but the current folder ' f'is {path}.') # Workaround path = path.parent # Find recursive all py-files. py_files = path.rglob('*.py') # Exclude full test files return filter(lambda fp: fp not in full_test_files, py_files) @classmethod def setUpClass(cls): cls.collected_py_files = cls._collect_py_files() def test005_ensure_linter_versions(self): """Workaround to ensure the correct linter versions are used. For sure there are better ways to solve this. But migration to a standard python package format need to be done first. See #1575. Until then this test will spare some hours of work, e.g. fixing linter errors (from out-dated linters) that are not relevant anymore in modern lintern versions. Another location where linter versions are relevant is CONTRIBUTING.md. """ if PYLINT_AVAILABLE: version_target = version.parse('3.3.0') proc = subprocess.run( ['pylint', '--version'], capture_output=True, text=True, check=True) version_string = proc.stdout.split('\n')[0].replace('pylint ', '') version_actual = version.parse(version_string) self.assertTrue( version_actual >= version_target, f'PyLint version is {version_actual} but need to ' f'be {version_target} or higher.') if RUFF_AVAILABLE: version_target = version.parse('0.15.0') proc = subprocess.run( ['ruff', '--version'], capture_output=True, text=True, check=True) version_string = proc.stdout.split('\n')[0].replace('ruff ', '') version_actual = version.parse(version_string) self.assertTrue( version_actual >= version_target, f'Ruff version is {version_actual} but need to ' f'be {version_target} or higher.') @unittest.skipUnless(RUFF_AVAILABLE, BASE_REASON.format('ruff')) def test010_ruff_default_ruleset(self): """Ruff in default mode.""" # ATTENTIION: Some settings are found in pyproject.toml cmd = [ 'ruff', 'check', # Additionally activate subset of special rules: # - PyLint (PL) # - PyCodestyle (E, W) # - flake8-gettext (INT) # - useless noqua (RUF100) # - pep8-naming (N) # Consider UP, ANN, D, DOC (upgrade, annotation, pydocstyle, # pydoclint) '--extend-select=PL,E,W,INT,RUF100,N', # Ignore: redefined-loop-name '--ignore=PLW2901', '--line-length', str(PEP8_MAX_LINE_LENGTH), # Because of globally installed GNU gettext functions '--config', 'builtins=["_", "ngettext"]', # Ruff counting branches different from PyLint. # See: '--config', 'pylint.max-branches=13', '--config', 'flake8-quotes.inline-quotes = "single"', # one error per line (no context lines) '--output-format=concise', '--quiet', ] cmd.extend(full_test_files) proc = subprocess.run( cmd, check=False, universal_newlines=True, capture_output=True ) # No errors other then linter rules self.assertIn(proc.returncode, [0, 1], proc.stderr) error_n = len(proc.stdout.splitlines()) if error_n > 0: print(proc.stdout) self.assertEqual(0, error_n, f'Ruff found {error_n} problem(s).') # any other errors? self.assertEqual(proc.stderr, '') @unittest.skipUnless(FLAKE8_AVAILABLE, BASE_REASON.format('flake8')) def test020_flake8_default_ruleset(self): """Flake8 in default mode.""" cmd = [ 'flake8', f'--max-line-length={PEP8_MAX_LINE_LENGTH}', '--builtins=_,ngettext', # '--enable-extensions=' ] cmd.extend(full_test_files) proc = subprocess.run( cmd, check=False, universal_newlines=True, capture_output=True ) error_n = len(proc.stdout.splitlines()) if error_n > 0: print(proc.stdout) self.assertEqual(0, error_n, f'Flake8 found {error_n} problem(s).') # any other errors? self.assertEqual(proc.stderr, '') @unittest.skipUnless(PYLINT_AVAILABLE, BASE_REASON.format('PyLint')) def test030_pylint_default_ruleset(self): """Use Pylint with all default rules to check specific files. """ cmd = create_pylint_cmd() # Add py-files cmd.extend(full_test_files) r = subprocess.run( cmd, check=False, universal_newlines=True, capture_output=True) # Count lines except module headings error_n = len(list(filter(lambda line: not line.startswith('*****'), r.stdout.splitlines()))) print(r.stdout) self.assertEqual(0, error_n, f'PyLint found {error_n} problems.') # any other errors? self.assertEqual(r.stderr, '') @unittest.skipUnless(PYLINT_AVAILABLE, BASE_REASON.format('PyLint')) def test050_pylint_reduced_ruleset(self): """Use Pylint to check for specific rules only. Some facts about PyLint - It is one of the slowest available linters. - It is able to catch lints other linters miss. """ # Explicit activate checks err_codes = [ # 'C0103', # invalid-name 'C0114', # missing-module-docstring 'C0115', # missing-class-docstring # 'C0116', # missing-function-docstring 'C0200', # consider-using-enumerate 'C0201', # consider-iterating-dictionary 'C0301', # line-too-long 'C0303', # trailing-whitespace 'C0305', # trailing-newlines 'C0321', # multiple-statements 'C0325', # superfluous-parens 'C0410', # multiple-imports # 'C0411', # wrong-import-order # 'C0412', # ungouped-imports # 'C0413', # wrong-import-position 'E0100', # init-is-generator 'E0101', # return-in-init 'E0102', # function-redefined 'E0103', # not-in-loop 'E0106', # return-arg-in-generator 'E0213', # no-self-argument 'E0401', # import-error 'E0602', # undefined-variable 'E1101', # no-member 'E1120', # no-value-for-parameter 'E1121', # too-many-function-args 'E1123', # unexpected-keyword-arg 'E1129', # not-context-manager 'I0021', # useless-suppression 'R0202', # no-classmethod-decorator 'R0203', # no-staticmethod-decorator 'R0801', # duplicate-code # 'R0902', # too-many-instance-attributes 'R0904', # too-many-public-methods 'R0912', # too-many-branches 'R0913', # too-many-arguments # 'R0915', # too-many-statements 'W0101', # unreachable # 'W0102', # dangerous-default-value 'W0105', # pointless-string-statement 'W0106', # expression-not-assigned 'W0107', # unnecessary-pass # 'W0120', # useless-else-on-loop 'w0122', # exec-used 'W0123', # eval-used 'W0150', # lost-exception 'W0201', # attribute-defined-outside-init 'W0221', # arguments-differ 'W0237', # arguments-renamed 'W0311', # bad-indentation 'W0404', # reimported 'W0603', # global-statement 'W0611', # unused-import 'W0612', # unused-variable 'W0613', # unused-argument 'W0614', # unused-wildcard-import # 'W0621', # redefined-outer-name # 'W0622', # redefined-builtin 'W0631', # undefinied-loop-variable # 'W0640', # cell-var-from-loop 'W0702', # bare-except # 'W0703', # broad-except 'W0707', # raise-missing-from 'W0711', # binary-op-exception 'W1115', # bad-format-string-key 'W1301', # unused-format-string-key 'W1401', # anomalous-backslash-in-string (invalid escape sequence) 'W1511', # bad-thread-instantiation 'W1515', # forgotten-debug-statement # 'W4902', # deprecated-method # 'W4903', # deprecated-argument # 'W4904', # deprecated-class 'R0202', # no-classmethod-decorator 'R0203', # no-staticmethod-decorator # 'R0911', # too-many-return-statements # 'R0914', # too-many-locals 'R1701', # simplifiable-if-statement 'R1702', # too-many-nested-blocks 'R1703', # simplifiable-if-expression # 'R1705', # no-else-return # 'R1720', # no-else-raise ] cmd = create_pylint_cmd(err_codes) # Add py-files cmd.extend(self._collect_py_files()) r = subprocess.run( cmd, check=False, universal_newlines=True, capture_output=True) # Count lines except module headings and output about duplicate code error_n = len(list(filter( lambda line: line[:2] not in ('**', ' ', '==', ' (', ''), r.stdout.splitlines()))) print(r.stdout) self.assertEqual(0, error_n, f'PyLint found {error_n} problems.') # any other errors? self.assertEqual(r.stderr, '') backintime-1.6.1/qt/test/test_statedata.py000066400000000000000000000060271514264426600206320ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Tests about statefile module.""" # pylint: disable=wrong-import-position,wrong-import-order import unittest from qttools_path import register_backintime_path register_backintime_path('common') import statedata # noqa: E402 class IsSingleton(unittest.TestCase): """StateData instance is a singleton.""" @classmethod def tearDownClass(cls): # Delete existing StateData instance try: # pylint: disable-next=protected-access del statedata.StateData._instances[statedata.StateData] except KeyError: pass def setUp(self): # Clean up all instances try: # pylint: disable-next=protected-access del statedata.StateData._instances[statedata.StateData] except KeyError: pass def test_identity(self): """Identical identity.""" one = statedata.StateData() two = statedata.StateData() self.assertEqual(id(one), id(two)) def test_content(self): """Identical values.""" one = statedata.StateData() two = statedata.StateData() one['foobar'] = 7 self.assertEqual(one, two) class Properties(unittest.TestCase): """Property access without errors.""" @classmethod def tearDownClass(cls): # Delete existing StateData instance try: # pylint: disable-next=protected-access del statedata.StateData._instances[statedata.StateData] except KeyError: pass def setUp(self): # Delete existing StateData instance try: # pylint: disable-next=protected-access del statedata.StateData._instances[statedata.StateData] except KeyError: pass def test_read_empty_global(self): """Read properties from empty state data""" sut = statedata.StateData() self.assertEqual(sut.msg_release_candidate, None) self.assertEqual(sut.msg_encfs_global, False) self.assertEqual(sut.mainwindow_show_hidden, False) self.assertEqual(sut.files_view_sorting, (0, 0)) self.assertEqual(sut.mainwindow_main_splitter_widths, (150, 450)) self.assertEqual(sut.mainwindow_second_splitter_widths, (150, 300)) with self.assertRaises(KeyError): # pylint: disable=pointless-statement sut.mainwindow_coords sut.mainwindow_dims sut.logview_dims sut.files_view_col_widths def test_profile_not_exist(self): """Profile does not exists.""" sut = statedata.StateData() profile = sut.profile(42) with self.assertRaises(KeyError): # pylint: disable=pointless-statement profile.last_path backintime-1.6.1/qt/textdlg.py000066400000000000000000000116411514264426600163130ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2025 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """A dialog containing a QTextBrowser""" from PyQt6.QtWidgets import QDialog, QTextBrowser, QVBoxLayout from PyQt6.QtGui import (QFontDatabase, QGuiApplication, QIcon, QTextCursor) from PyQt6.QtCore import QRegularExpression, QTimer class TextDialog(QDialog): """A dialog containing a QTextBrowser capable of markdown and plain text Dev note: Consider joining the center-resize-feature with RestoreConfigDialog. """ # pylint: disable=too-few-public-methods DEFAULT_WIDTH_FRACTION = 0.5 DEFAULT_HEIGHT_FRACTION = 0.75 # pylint: disable-next=too-many-arguments,too-many-positional-arguments def __init__(self, # noqa: PLR0913 content: str, markdown: bool = True, scroll_to: str = None, title: str = '', icon: QIcon = None, width_fraction: float = DEFAULT_WIDTH_FRACTION, height_fraction: float = DEFAULT_HEIGHT_FRACTION): """ Args: width_fraction: Fraction of screen width (0.0 to 1.0) height_fraction: Fraction of screen height (0.0 to 1.0) """ super().__init__() self.setWindowTitle(title) self._scroll_to_pattern = scroll_to self._markdown = markdown self._resize_tries = -1 self._height_fraction = height_fraction self._width_fraction = width_fraction if icon: self.setWindowIcon(icon) self._browser = QTextBrowser() font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont) self._browser.setFont(font) layout = QVBoxLayout(self) layout.addWidget(self._browser) self.set_content(content) @property def width_fraction(self) -> float: """Fraction of screen width""" return self._width_fraction @property def browser_widget(self) -> QTextBrowser: """The primary widget""" return self._browser def set_content(self, content: str): """Set content to the primary widget. """ if self._markdown: self._browser.setMarkdown(content) else: self._browser.setPlainText(content) # See _resize_to_full_height() for details. self._resize_tries = 10 QTimer.singleShot(1, self._center_and_resize) def _center_and_resize(self) -> None: """Center the dialog and resize it to fractions of the screen size. """ # pylint: disable=duplicate-code # Determine the height of the dialog's title bar and border. This # value is unknown or incorrect until the dialg is fully drawn. # That is the reason why we use this workaround. deco_height = self.frameGeometry().height() - self.geometry().height() if deco_height == 0 and self._resize_tries > 0: self._resize_tries -= 1 QTimer.singleShot(1, self._center_and_resize) return handle = self.windowHandle() screen = handle.screen() if handle else QGuiApplication.primaryScreen() geom = screen.availableGeometry() new_width = int(geom.width() * self._width_fraction) new_height = int((geom.height() - deco_height) * self._height_fraction) self.move( # center horizontal geom.center().x() - (new_width // 2), # center vertical geom.center().y() - (new_height // 2) ) self.resize( # desired width new_width, # desired height (incl. window decoration) on available screen new_height) self._scroll_to() def _scroll_to(self): if self._scroll_to_pattern is None: return cursor = self._browser.document().find( QRegularExpression(self._scroll_to_pattern), QTextCursor() ) if cursor.isNull(): return # Sets the cursor to the text position. self._browser.setTextCursor(cursor) # Scroll until the selected text is visible. self._browser.ensureCursorVisible() # The selected text appears at the end of the widget not at the top. # This adjusts the position accordingly via scrolling one page up. scrollbar = self._browser.verticalScrollBar() cursor_rect = self._browser.cursorRect(cursor) margin = 10 new_value = scrollbar.value() + cursor_rect.top() - margin new_value = max( scrollbar.minimum(), min(scrollbar.maximum(), new_value)) scrollbar.setValue(new_value) backintime-1.6.1/qt/timeline.py000066400000000000000000000237041514264426600164510ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan # SPDX-FileCopyrightText: © 2008-2022 Bart de Koning # SPDX-FileCopyrightText: © 2008-2022 Richard Bailey # SPDX-FileCopyrightText: © 2008-2022 Germar Reitze # SPDX-FileCopyrightText: © 2024 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # # File was split from "qt/qttools.py". """Time line widget. """ from datetime import (datetime, date, timedelta) from calendar import monthrange from PyQt6.QtGui import QFont, QPalette from PyQt6.QtCore import (Qt, pyqtSlot, pyqtSignal) from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QTreeWidget, QTreeWidgetItem) import snapshots from qttools_path import register_backintime_path register_backintime_path('common') class TimeLine(QTreeWidget): """A list like widget containing existing backups. The widget is placed on the right side of the main window. """ update_files_view = pyqtSignal(int) def __init__(self, parent): super().__init__(parent) self.setRootIsDecorated(False) self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setSelectionMode( QAbstractItemView.SelectionMode.ExtendedSelection) self.setHeaderLabels([_('Backups'), 'foo']) self.setSortingEnabled(True) self.sortByColumn(1, Qt.SortOrder.DescendingOrder) self.hideColumn(1) self.header().setSectionsClickable(False) self.parent = parent self.snapshots = parent.snapshots self._root_item = None self._reset_header_data() def clear(self): """Clear all entries from the widget.""" self._reset_header_data() return super().clear() def _reset_header_data(self): self.now = date.today() # list of tuples with (text, startDate, endDate) self._header_data = [] # Today today_min = datetime.combine(self.now, datetime.min.time()) today_max = datetime.combine(self.now, datetime.max.time()) self._header_data.append((_('Today'), today_min, today_max)) # Yesterday yesterday_min = datetime.combine( self.now - timedelta(days=1), datetime.min.time()) yesterday_max = datetime.combine( today_min - timedelta(hours=1), datetime.max.time()) self._header_data.append( (_('Yesterday'), yesterday_min, yesterday_max)) # This week this_week_min = datetime.combine( self.now - timedelta(self.now.weekday()), datetime.min.time()) this_week_max = datetime.combine( yesterday_min - timedelta(hours=1), datetime.max.time()) if this_week_min < this_week_max: self._header_data.append( (_('This week'), this_week_min, this_week_max)) # Last week last_week_min = datetime.combine( self.now - timedelta(self.now.weekday() + 7), datetime.min.time()) last_week_max = datetime.combine( self._header_data[-1][1] - timedelta(hours=1), datetime.max.time()) self._header_data.append( (_('Last week'), last_week_min, last_week_max)) # Rest of current month. Otherwise this months header would be # above today. this_month_min = datetime.combine( self.now - timedelta(self.now.day - 1), datetime.min.time()) this_month_max = datetime.combine( last_week_min - timedelta(hours=1), datetime.max.time()) if this_month_min < this_month_max: self._header_data.append(( this_month_min.strftime('%B').capitalize(), this_month_min, this_month_max)) # Rest of last month last_month_max = datetime.combine( self._header_data[-1][1] - timedelta(hours=1), datetime.max.time()) last_month_min = datetime.combine( date(last_month_max.year, last_month_max.month, 1), datetime.min.time() ) self._header_data.append(( last_month_min.strftime('%B').capitalize(), last_month_min, last_month_max)) def add_root(self, sid): """Dev note: What is 'root' in this context? Args: sid: Snapshot ID Returns: The root item itself. """ self._root_item = self.addSnapshot(sid) return self._root_item @pyqtSlot(snapshots.SID) # pylint: disable-next=invalid-name def addSnapshot(self, sid): # noqa: N802 """Slot to handle selection of snapshots.""" item = SnapshotItem(sid) self.addTopLevelItem(item) # Select the snapshot that was selected before if sid == self.parent.sid: self._set_current_item(item) if not sid.isRoot: self.add_header(sid) return item def add_header(self, sid): """Add an entry as a header item.""" for text, start_date, end_date in self._header_data: if start_date <= sid.date <= end_date: self._create_header_item(text, end_date) return # Any previous months year = sid.date.year month = sid.date.month if year == self.now.year: text = date(year, month, 1).strftime('%B').capitalize() else: text = date(year, month, 1).strftime('%B, %Y').capitalize() start_date = datetime.combine( date(year, month, 1), datetime.min.time()) end_date = datetime.combine( date(year, month, monthrange(year, month)[1]), datetime.max.time()) if self._create_header_item(text, end_date): self._header_data.append((text, start_date, end_date)) def _create_header_item(self, text, end_date): for item in self._iter_header_items(): if item.snapshot_id.date == end_date: return False item = HeaderItem(text, snapshots.SID(end_date, self.parent.config)) self.addTopLevelItem(item) return True @pyqtSlot() # pylint: disable-next=invalid-name def checkSelection(self): # noqa: N802 """Slot handling selection events.""" if self.currentItem() is None: self.select_root_item() def select_root_item(self): """Dev note: Don't know what 'root' means in this context.""" self._set_current_item(self._root_item) if not self.parent.sid.isRoot: self.parent.sid = self._root_item.snapshot_id self.update_files_view.emit(2) def selected_snapshot_ids(self): """Snapshot IDs of all selected entries.""" return [i.snapshot_id for i in self.selectedItems()] def current_snapshot_id(self): """Snapshot ID of current selected entry.""" item = self.currentItem() return item.snapshot_id if item else None def set_current_snapshot_id(self, sid): """Select entry related to the snapshot ID.""" for item in self._iter_items(): if item.snapshot_id == sid: self._set_current_item(item) break def _set_current_item(self, item, *args, **kwargs): self.setCurrentItem(item, *args, **kwargs) if self.parent.sid != item.snapshot_id: self.parent.sid = item.snapshot_id self.update_files_view.emit(2) def _iter_items(self): for index in range(self.topLevelItemCount()): yield self.topLevelItem(index) def iter_snapshot_items(self): """Iterate over all items.""" for item in self._iter_items(): if isinstance(item, SnapshotItem): yield item def _iter_header_items(self): for item in self._iter_items(): if isinstance(item, HeaderItem): yield item class TimeLineItem(QTreeWidgetItem): """Base class for TimeLine entry widgets. Dev note (buhtz, 2025-03): I don't see a need for this. SnapshotItem and HeaderItem can directly derive from QTreeWidgetItem. """ def __lt__(self, other): return self.snapshot_id < other.snapshot_id @property def snapshot_id(self): """Id of the related snapshot.""" return self.data(0, Qt.ItemDataRole.UserRole) class SnapshotItem(TimeLineItem): """Snapshot entry widget used in TimeLine.""" def __init__(self, sid): super().__init__() self.setText(0, sid.displayName) self.setData(0, Qt.ItemDataRole.UserRole, sid) if sid.isRoot: self.setToolTip( 0, _('This is NOT a backup but a live view ' 'of the local files.')) else: self.setToolTip( 0, _('Last check {time}').format(time=sid.lastChecked)) def update_text(self): """Update the widgets text with its snapshots displayName.""" sid = self.snapshot_id self.setText(0, sid.displayName) class HeaderItem(TimeLineItem): # pylint: disable=too-few-public-methods """Header entry widget used in TimeLine.""" def __init__(self, name, sid): """ Dev note (buhtz, 2024-01-14): Parts of that code are redundant with app.py::MainWindow.addPlace(). """ super().__init__() self.setText(0, name) font = self.font(0) font.setWeight(QFont.Weight.Bold) self.setFont(0, font) palette = QApplication.instance().palette() self.setForeground( 0, palette.color(QPalette.ColorRole.PlaceholderText)) self.setBackground( 0, palette.color(QPalette.ColorRole.AlternateBase)) self.setFlags(Qt.ItemFlag.NoItemFlags) self.setData(0, Qt.ItemDataRole.UserRole, sid) backintime-1.6.1/qt/usermessagedialog.py000066400000000000000000000100201514264426600203310ustar00rootroot00000000000000# SPDX-FileCopyrightText: © 2023 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """Module about UserMessageDialog""" from typing import Optional from PyQt6.QtCore import Qt, QSize, QTimer from PyQt6.QtGui import QCursor, QGuiApplication from PyQt6.QtWidgets import (QDialog, QLayout, QVBoxLayout, QDialogButtonBox, QLabel, QToolTip, QWidget) class UserMessageDialog(QDialog): """Present a large messages to the users with extra features. Different from QMessageBox this dialog is intended to display large amount of text. The dialog is able to wrap the text while being resized. Hyperlinks in this text do display their URL as tooltip. HTML tags supported because of Qt rich text feature. Text between Newline characters ``\n`` will be converted into ``

`` paragraphs. The dialog is centered relative to its parent if present, otherwise to the screen. """ def __init__( self, parent: Optional[QWidget], title: str, full_label: str, ): super().__init__(parent) # screen_width = QApplication.primaryScreen().size().width() # min_width = 300 if screen_width <= 1080 else 450 self.setMinimumWidth(400) self.setWindowTitle(title) self.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, True) # Wrap paragraphs in

tags. if '\n' in full_label: result = '' for t in full_label.split('\n'): result = f'{result}

{t}

' else: result = full_label widget = QLabel(result, self) widget.setWordWrap(True) widget.setOpenExternalLinks(True) widget.linkHovered.connect(self.slot_link_hovered) button = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok, self) button.clicked.connect(self.accept) layout = QVBoxLayout(self) layout.addWidget(widget) layout.addWidget(button) self._fix_size() def _fix_size(self): """The dialog is resized so it fits the content of the QLabel. Credits: https://stackoverflow.com/a/77012305/4865723 """ best = QLayout.closestAcceptableSize(self, QSize(self.width(), 1)) if self.height() < best.height(): self.resize(best) QTimer.singleShot(0, self._center) def _center(self): if self.parentWidget(): self._center_to_parent() else: self._center_to_screen() def _center_to_parent(self): geo = self.frameGeometry() geo.moveCenter(self.parentWidget().frameGeometry().center()) self.move(geo.topLeft()) def _center_to_screen(self): """Center the dialog to screen""" handle = self.windowHandle() screen = handle.screen() if handle else QGuiApplication.primaryScreen() if not screen: return geom = screen.availableGeometry() self.move( # center horizontal geom.center().x() - (self.geometry().width() // 2), # center vertical geom.center().y() - (self.geometry().height() // 2), ) # pylint: disable-next=invalid-name def resizeEvent(self, event): # noqa: N802 """See `_fixSize()` for details.""" super().resizeEvent(event) if event.oldSize().width() != event.size().width(): QTimer.singleShot(0, self._fix_size) elif event.spontaneous(): self._fix_size() def slot_link_hovered(self, url): """Show URL in tooltip without anoing http-protocol prefixf.""" QToolTip.showText(QCursor.pos(), url.replace('https://', '')) backintime-1.6.1/update_language_files.py000077500000000000000000001007551514264426600205330ustar00rootroot00000000000000#!/usr/bin/env python3 # SPDX-FileCopyrightText: © 2023 Christian BUHTZ # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In Time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . """This helper script does manage transferring translations to and from the translation platform (currently Weblate). """ import sys import datetime import re import tempfile import string import shutil import json from pathlib import Path from subprocess import run, check_output from lxml import etree from common import languages, version try: import polib print(f'polib version: {polib.__version__}') except ImportError: # pylint: disable-next=raise-missing-from raise ImportError('Can not import package "polib". Please install it.') # In usual GNU gettext environments it would be "locale" (sometimes plurarl # "locales") LOCAL_DIR = Path('common') / 'po' TEMPLATE_PO = LOCAL_DIR / 'messages.pot' LANGUAGE_NAMES_PY = Path('common') / 'languages.py' GUI_DIR = Path('qt') DESKTOP_FILE_FIELDS = ['GenericName', 'Comment'] WEBLATE_URL = 'https://translate.codeberg.org/git/backintime/common' PACKAGE_NAME = 'Back In Time' PACKAGE_VERSION = version.__version__ BUG_ADDRESS = 'https://github.com/bit-team/backintime' # RegEx pattern: Character & followed by a word character (extract as group) REX_SHORTCUT_LETTER = re.compile(r'&(\w)') TRANSLATION_PLACEHOLDER_MSGID = 'translator-credits-placeholder' DEFAULT_COPYRIGHT = '© 2008 Back In Time Team ' MISSING_TRANSLATORS_TXT = "Strict and accurate recording of translators' " \ "names began around 2022. As\n" \ "the project started in 2008, some earlier translators' names " \ 'may not have\n' \ 'been documented and could be lost.' def dict_as_code(a_dict: dict, indent_level: int) -> list[str]: """Convert a (nested) Python dict into its PEP8 conform as-in-code representation. """ tab = ' ' * 4 * indent_level result = [] for key in a_dict: # single quotes? quote_key = "'" if isinstance(key, str) else "" quote_val = "'" if isinstance(a_dict[key], str) else "" # A nested dict if isinstance(a_dict[key], dict): result.append(f"{tab}{quote_key}{key}{quote_key}: {{") result.extend( dict_as_code(a_dict[key], indent_level+1)) result.append(f"{tab}}},") continue # Regular key: value pair result.append(f"{tab}{quote_key}{key}{quote_key}: " f"{quote_val}{a_dict[key]}{quote_val},") return result def update_po_template(): """The po template file is update via `xgettext`. All files with extension `*.py` are scanned for translatable strings. Unittest files and folders are excluded. xgettext is used instead of pygettext because the latter is deprecated since xgettext is able to handle Python files. """ print(f'Updating PO template file "{TEMPLATE_PO}" …') # Recursive search of Python files excluding unittest files and folders find_cmd = [ 'find', # folders to search in 'common', 'qt', # look for py-files '-name', '*.py', # exclude files/folders related to unittests '-not', '-name', 'test_*', '-not', '-path', '*/test/*', '-not', '-path', '*/tests/*' ] print(f'Execute "{find_cmd}".') py_files = check_output(find_cmd, text=True).split() print('Scan following files for translatable strings:\n{}' .format('\n'.join(py_files))) cmd = [ 'xgettext', '--verbose', '--language=Python', f'--package-name="{PACKAGE_NAME}"', f'--package-version="{PACKAGE_VERSION}"', f'--msgid-bugs-address={BUG_ADDRESS}', f'--output={TEMPLATE_PO}', '--sort-by-file', # '--sort-output', ] cmd.extend(py_files) print(f'Execute "{cmd}".') run(cmd, check=True) _update_po_template_from_polkit_policies() _update_po_template_from_desktop_files() _add_spdx_header_to_po_template() def _add_spdx_header_to_po_template(): print(f'Add SPDX Header to PO template file "{TEMPLATE_PO}" …') # Header comment with SPDX data spdx_base = get_spdx_metadata_lines(ignore_copyright=True, without_comment_prefix=True) copyright = f'SPDX-FileCopyrightText: {DEFAULT_COPYRIGHT}' pof = polib.pofile(TEMPLATE_PO) print(f'\n{len(pof)} entries in {TEMPLATE_PO}') pof.header = f'{DEFAULT_COPYRIGHT}\n{spdx_base}\n{MISSING_TRANSLATORS_TXT}' pof.save() def _update_po_template_from_polkit_policies(): """Extract translatable strings from polkit related policy files. Policy files are XML content. Translatable strings are marked by an "gettext-domain" attribute. That strings are used in the password request dialogs used by polkit agents; e.g. when starting BIT in root mode or modifying Udev rules. """ path = Path.cwd() / 'qt' for policy_fp in path.glob('*.policy'): print( f'Update PO template file with policy strings from {policy_fp} …') parser = etree.XMLParser(remove_comments=False) tree = etree.parse(policy_fp, parser) root = tree.getroot() # All tags containing attribute "gettext-domin='backintime'" for elem in root.xpath(".//*[@gettext-domain='backintime']"): # ignore empty fields if not elem.text: continue # Add to messages.pot, consider duplicates and location/occurrence _add_entry_to_po_template( msgid=elem.text.strip(), fp=policy_fp.relative_to(Path.cwd()), linenr=elem.sourceline ) def _update_po_template_from_desktop_files(): # Each qt/*.desktop file for desktop_fp in all_desktop_files_in_qt_dir(): print(f'Update PO template file with strings from {desktop_fp} …') content = desktop_fp.read_text(encoding='utf-8') for idx, line in enumerate(content.split('\n'), start=1): # ignore comments if line.startswith('#'): continue try: field, value = line.split('=', 1) except ValueError: continue if field not in DESKTOP_FILE_FIELDS: continue _add_entry_to_po_template( msgid=value, fp=desktop_fp, linenr=idx ) def _add_entry_to_po_template(msgid: str, fp: Path, linenr: int): po_file = polib.pofile(TEMPLATE_PO) entry = po_file.find(msgid) location = (fp, linenr) if entry: # Update location if location not in entry.occurrences: entry.occurrences.append(location) else: # Add new entry po_file.append( polib.POEntry( msgid=msgid, msgstr='', occurrences=[location], ) ) po_file.save(TEMPLATE_PO) def update_po_language_files(remove_obsolete_entries: bool = False): """The po files are updated with the source strings from the pot-file (the template for each po-file). The GNU gettext utility ``msgmerge`` is used for that. Make sure that the function `update_po_template()` is called beforehand. """ print( 'Update language (po) files' + ' and remove obsolete entries' if remove_obsolete_entries else '' ) spdx_base = get_spdx_metadata_lines(ignore_copyright=True, without_comment_prefix=True) # Recursive all po-files for po_path in LOCAL_DIR.rglob('**/*.po'): lang = po_path.stem cmd = [ 'msgmerge', '--verbose', f'--lang={lang}', '--update', '--sort-by-file', '--backup=off', # don't create *.po~ files f'{po_path}', f'{TEMPLATE_PO}' ] run(cmd, check=True) if remove_obsolete_entries: # remove obsolete entries ("#~ msgid) cmd = [ 'msgattrib', '--no-obsolete', f'--output-file={po_path}', f'{po_path}' ] run(cmd, check=True) _set_header(po_path, spdx_base) def update_desktop_files(): for desktop_fp in all_desktop_files_in_qt_dir(): print(f'Update desktop file {desktop_fp} with translations …') content = desktop_fp.read_text(encoding='utf-8') content = content.split('\n') to_translate = {key: None for key in DESKTOP_FILE_FIELDS} # iterate from the end to the start for idx, line in reversed(list(enumerate(content[:]))): # ignore comments if line.startswith('#'): continue # blank line? if not line: content = content[:idx] + content[idx+1:] continue try: field, value = line.split('=', 1) except ValueError: continue # each translatable or translated field for target_field in DESKTOP_FILE_FIELDS: if not field.startswith(target_field): continue # translated field if field.startswith(f'{target_field}['): # remove translation content = content[:idx] + content[idx+1:] continue # remember original string to_translate[target_field] = value continue # PLAUSI if field != target_field: raise RuntimeError( f'Unexpected situation. {target_field=} {field=} ' f'{value=} {line=}' ) for field, value in to_translate.items(): print(f'{field=} {value=}') translations = _get_translation_for_desktop_string(value) if field == 'Comment': _check_value_length(translations, field) translations = [ f'{field}[{lang}]={translated}' for lang, translated in translations.items() ] content = content + translations # ensure newline at end of file content = content + ['\n'] desktop_fp.write_text('\n'.join(content), encoding='utf-8') def _check_value_length(translations, field): """Debian GNU/Linux (lintian) limit the length of this field to 80 chars. """ LIMIT = 79 for lang, val in translations.items(): if len(val) <= LIMIT: continue print( f'WARNING: Length of {field}[{lang}] reached the ' f'limit of {LIMIT} and is {len(val)}. "{val}"' ) def _set_header(po_path: Path, spdx_base: str): """Setup the header and comments header of the given po-file to the current state. """ pof = polib.pofile(po_path) # Version string pof.metadata['Project-Id-Version'] = f'{PACKAGE_NAME} {PACKAGE_VERSION}' copyright = [DEFAULT_COPYRIGHT] # Extract authors e = pof.find(TRANSLATION_PLACEHOLDER_MSGID) if e: copyright = copyright + list(filter( lambda val: len(val) > 0, e.msgstr.split('\n') )) for idx, centry in enumerate(copyright): if not ('(c)' in centry or '©' in centry): copyright[idx] = f'© {copyright[idx]}' copyright = [ f'SPDX-FileCopyrightText: {centry}' for centry in copyright] copyright = '\n'.join(copyright) pof.header = f'{copyright}\n{spdx_base}\n{MISSING_TRANSLATORS_TXT}' # Remove someday try: del pof.metadata['X-Launchpad-Export-Date'] except KeyError: pass pof.save() def check_existence(): """Check for existence of essential files. Returns: Nothing if everything is fine. Raises: FileNotFoundError """ paths_to_check = [ LOCAL_DIR, TEMPLATE_PO ] for file_path in paths_to_check: if not file_path.exists(): raise FileNotFoundError(file_path) def update_from_weblate(): """Translations done on Weblate platform are integrated back into the repository. The Weblate translations live on https://translate.codeberg.org and has its own internal git repository. This repository is cloned and the po-files copied into the current local (upstream) repository. See comments in code about further details. """ tmp_dir = tempfile.mkdtemp() # "Clone" weblate repo into a temporary folder. # The folder is kept (nearly) empty. No files are transferred except # the hidden ".git" folder. cmd = [ 'git', 'clone', '--no-checkout', WEBLATE_URL, tmp_dir ] print(f'Execute "{cmd}".') run(cmd, check=True) # Now checkout po-files from that temporary repository but redirect # them into the current folder (which is our local upstream repo) instead # of the temporary repositories folder. cmd = [ 'git', # Use temporary/Weblate repo as checkout source '--git-dir', f'{tmp_dir}/.git', 'checkout', # branch 'dev', '--', 'common/po/*.po' ] print(f'Execute "{cmd}".') run(cmd, check=True) shutil.rmtree(tmp_dir, ignore_errors=True) def check_syntax_of_po_files(): """Check all po files of known syntax violations. """ # Match every character except open/closing curly brackets rex_reduce = re.compile(r'[^\{\}]') # Match every pair of curly brackets rex_curly_pair = re.compile(r'\{\}') # Extract placeholder/variable names rex_names = re.compile(r'\{(.*?)\}') def _curly_brackets_balanced(to_check): """Check if curly brackes for variable placeholders are balanced.""" # Remove all characters that are not curly brackets reduced = rex_reduce.sub('', to_check) # Remove valid pairs of curly brackets invalid = rex_curly_pair.sub('', reduced) # Catch nested curly brackest like this # "{{{}}}", "{{}}" # This is valid Python code and won't cause Exceptions. So errors here # might be false negative. But despite rare cases where this might be # used it is a high possibility that there is a typo in the translated # string. BIT won't use constructs like this in strings, so it is # handled as an error. if rex_curly_pair.findall(invalid): print(f'\nERROR ({lang_code}): Curly brackets nested: {to_check}') return False if invalid: print(f'\nERROR ({lang_code}): Curly brackets not balanced : {to_check}') return False return True def _potential_harmful_strings(to_check): """Check if the translated string contain harmful content. URLs indicated by 'href' can be harmful if the string is used in a QLabel with activated HTML interpretation. """ if re.search('href', to_check, re.IGNORECASE): print(f'CRITICAL - Potential harmful string: "{to_check}"') return False return True def _other_errors(to_check): """Check if there are any other errors that could be thrown via printing this string.""" try: # That is how print() internally parse placeholders and other # things. list(string.Formatter().parse(format_string=to_check)) except Exception as exc: # pylint: disable=broad-exception-caught print(f'\nERROR ({lang_code}): {exc} in translation: {to_check}') return False return True def _place_holders(trans_string, src_string, tcomments): """Check if the placeholders between original source string and the translated string are identical. Order is ignored. To disable this check for a specific string add the translation comment(!) on top of the entry in the po file like this: # ignore-placeholder-compare #: qt/app.py:1961 #, python-brace-format msgid "foo" msgstr "bar" Keep in mind that this is a regular comment. It is not a flag (``#, ``) or a user defined flag (``#. ``). The later two are removed by msgmerge when updating the po files from the pot file. """ if 'ignore-placeholder-compare' in tcomments: return True flagmsg = 'To disable this check add the comment (not flag!) on ' \ 'top of the entry in the po-file: ' \ '"# ignore-placeholder-compare"' # Compare number of curly brackets. for bracket in tuple('{}'): if src_string.count(bracket) != trans_string.count(bracket): print(f'\nERROR ({lang_code}): Number of "{bracket}" between ' 'original source and translated string is different.\n' f'\nTranslation: {trans_string}\n\n{flagmsg}') return False # Compare variable names org_names = rex_names.findall(src_string) trans_names = rex_names.findall(trans_string) if sorted(org_names) != sorted(trans_names): print(f'\nERROR ({lang_code}): Names of placeholders between ' 'original source and translated string are different.\n' f'\nNames in original : {org_names}\n' f'\nNames in translation : {trans_names}\n' f'\nFull translation: {trans_string}\n{flagmsg}') return False return True print('Checking syntax of po files…') # collect translator-credit string translators = {} # Each po file for po_path in all_po_files_in_local_dir(): error_count = 0 # Language code determined by po-filename lang_code = po_path.with_suffix('').name pof = polib.pofile(po_path) # Each translated entry for entry in pof.translated_entries(): # Plural form? if entry.msgstr_plural or entry.msgid_plural: # Ignoring plural form because this is to complex, not logical # in all cases and also not worth the effort. continue if (not _curly_brackets_balanced(entry.msgstr) or not _potential_harmful_strings(entry.msgstr) or not _other_errors(entry.msgstr) or not _place_holders(entry.msgstr, entry.msgid, entry.tcomment)): print(f'\nSource string: {entry.msgid}\n') error_count += 1 # translator string? if entry.msgid == 'translator-credits-placeholder': translators[languages.names[lang_code]['en']] \ = entry.msgstr.split('\n') if error_count: print(f' {lang_code} >> {error_count} errors') # else: # print(f' {lang_code} >> OK') translators = { key: translators[key] for key in sorted(translators.keys())} print('\nTRANSLATORS:') print(json.dumps(translators, indent=4, ensure_ascii=False)) print('') def all_po_files_in_local_dir(): """All po files (recursive).""" return LOCAL_DIR.rglob('**/*.po') def all_desktop_files_in_qt_dir(): return sorted(GUI_DIR.glob('*.desktop')) def show_completeness_info(compl_dict, names_dict): sorted_dict = dict( sorted( compl_dict.items(), key=lambda items: items[1], reverse=True ) ) for code, completeness in sorted_dict.items(): lang = names_dict[code]['en'] print(f'{completeness:3} % - {lang} ({code})') def create_completeness_dict(): """Create a simple dictionary indexed by language code and value that indicate the completeness of the translation in percent. """ print('Calculate completeness for each language in percent…') result = {} # each po file in the repository for po_path in all_po_files_in_local_dir(): pof = polib.pofile(po_path) result[po_path.stem] = pof.percent_translated() pof.save() # "en" is the source language result['en'] = 100 return result def create_languages_py_file(): """Create the languages.py file containing language names and the completeness of their translation. See the following functions for further details. - ``update_language_names()`` - ``create_completeness_dict()`` """ # Convert language names dict to python code as a string names_dict = update_language_names() content = ['names = {'] content.extend(dict_as_code(names_dict, 1)) content.append('}') # the same with completeness dict compl_dict = create_completeness_dict() show_completeness_info(compl_dict, names_dict) content.append('') content.append('') content.append('completeness = {') content.extend(dict_as_code(compl_dict, 1)) content.append('}') with LANGUAGE_NAMES_PY.open('w', encoding='utf8') as handle: date_now = datetime.datetime.now().strftime('%c') handle.write(get_spdx_metadata_lines()) handle.write( f'#\n# Generated at {date_now} with help\n# of package "babel" ' 'and "polib".\n') handle.write('# https://babel.pocoo.org\n') handle.write('# https://github.com/python-babel/babel\n') handle.write( '# pylint: disable=too-many-lines,missing-module-docstring\n') handle.write('\n'.join(content)) handle.write('\n') print(f'Result written to {LANGUAGE_NAMES_PY}.') # Completeness statistics (English is excluded) compl = list(compl_dict.values()) compl.remove(100) # exclude English statistic = { 'compl': round(sum(compl) / len(compl)), 'n': len(compl), '99_100': len(list(filter(lambda val: val >= 99, compl))), '90_98': len(list(filter(lambda val: 90 <= val < 99, compl))), '50_89': len(list(filter(lambda val: 50 <= val <= 89, compl))), 'lt50': len(list(filter(lambda val: val < 50, compl))) } print('STATISTICS') print(f'\tTotal completeness: {statistic["compl"]}%') print(f'\tNumber of languages (excl. English): {statistic["n"]}') print(f'\t100-99% complete: {statistic["99_100"]} languages') print(f'\t90-98% complete: {statistic["90_98"]} languages') print(f'\t50-89% complete: {statistic["50_89"]} languages') print(f'\tless than 50% complete: {statistic["lt50"]} languages') def create_language_names_dict(language_codes: list) -> dict: """Create dict of language names in different flavors. The dict is used in the LanguageDialog to display the name of each language in the UI's current language and the language's own native representation. """ # We keep this import local because it is a rare case that this function # will be called. This happens only if a new language is added to BIT. try: # pylint: disable-next=import-outside-toplevel import babel except ImportError as exc: raise ImportError( 'Can not import package "babel". Please install it.') from exc # Babel minimum version (because language code "ie") from packaging.version import Version if Version(babel.__version__) < Version('2.15'): raise ImportError( f'Babel version 2.15 required. But {babel.__version__} ' 'is installed.') # Source language (English) should be included if 'en' not in language_codes: language_codes.append('en') # Don't use defaultdict because pprint can't handle it result = {} for code in sorted(language_codes): # print(f'Processing language code "{code}"…') lang = babel.Locale.parse(code) result[code] = {} # Native name of the language # e.g. 日本語 result[code]['_native'] = lang.get_display_name(code) # Name of the language in all other foreign languages # e.g. Japanese, Japanisch, ... for foreign in language_codes: result[code][foreign] = lang.get_display_name(foreign) return result def update_language_names() -> dict: """See `create_language_names_dict() for details.""" # Languages code based on the existing po-files langs = [po_path.stem for po_path in LOCAL_DIR.rglob('**/*.po')] # Some languages missing in the list of language names? try: missing_langs = set(langs) - set(languages.names) except AttributeError: # Under circumstances the languages file is empty missing_langs = ['foo'] if missing_langs: print('Create new language name list because of missing ' f'languages: {missing_langs}') return create_language_names_dict(langs) return languages.names def get_shortcut_entries(po_file: polib.POFile) -> list[polib.POEntry]: """Return list of po-file entries using a shortcut indicator ("&") and are not obsolete. """ result = filter(lambda entry: entry.obsolete == 0 and REX_SHORTCUT_LETTER.search(entry.msgid), po_file) return list(result) def get_shortcut_groups() -> dict[str, list]: """Return the currently used "shortcut groups" and validate if they are up to date with the source strings in "messages.pot". Returns: A dictionarie indexed by group names with list of source strings. Raises: ValueError: If the shortcut indicator using source strings are modified. """ # Get all entries using a shortcut indicator real = get_shortcut_entries(polib.pofile(TEMPLATE_PO)) # Reduce to their source strings real = [entry.msgid for entry in real] # Later this list is sliced into multiple groups expect = [ # Main window (menu bar) '&Backup', '&Restore', '&Help', 'Back In &Time', # Manage profiles dialog (tabs) '&General', '&Include', '&Exclude', '&Remove & Retention', '&Options', 'E&xpert Options', ] # Plausibility check: # Difference between the real and expected strings indicate # modifications in the GUI and in the shortcut groups. if not sorted(real) == sorted(expect): # This will happen when the source strings are somehow modified or # some strings add or removed. # SOLUTION: Look again into the GUI and its commit history what was # modified. Update the "expect" list to it. raise ValueError( f'Source strings with GUI shortcuts in {TEMPLATE_PO} are not as ' 'expected.\n' f' Expected: {sorted(expect)}\n' f' Real: {sorted(real)}') return {'mainwindow': expect[:4], 'manageprofile': expect[4:]} def check_shortcuts(): """Check for redundant used letters as shortcut indicators in translated GUI strings. Keyboard shortcuts are indicated via the & in front of a character in a GUI string (e.g. a button or tab). For example "B&ackup" can be activated with pressing ALT+A. As another example the strings '&Exclude' and '&Export' used in the same area of the GUI won't work because both of them indicate the 'E' as a shortcut. They need to be unique. These situation can happen in translated strings in most cases translators are not aware of that feature or problem. It is nearly impossible to control this on the level of the translation platform. """ groups = get_shortcut_groups() # each po file in the repository for po_path in list(LOCAL_DIR.rglob('**/*.po')): print(f'******* {po_path} *******') # Remember shortcut relevant entries. real = {key: [] for key in groups} # # WORKAROUND. See get_shortcut_groups() for details. # real['mainwindow'].append('Back In &Time') # Entries using shortcut indicators shortcut_entries = get_shortcut_entries(polib.pofile(po_path)) # Group the entries to their shortcut groups for entry in shortcut_entries: for groupname in real: if entry.msgid in groups[groupname]: real[groupname].append(entry.msgstr) # Each shortcut group... for groupname in real: # All shortcut letters used in that group letters = '' # Collect letters for trans in real[groupname]: try: letters = letters \ + REX_SHORTCUT_LETTER.search(trans).groups()[0] except AttributeError: pass # Redundant shortcuts? set() do remove duplicates if len(letters) > len(set(letters)): err_msg = f'Maybe redundant shortcuts in "{po_path}".' # Missing shortcuts in translated strings? if len(letters) < len(real[groupname]): err_msg = err_msg + ' Maybe missing ones.' err_msg = f'{err_msg} Please take a look.\n' \ f' Group: {groupname}\n' \ f' Source: {groups[groupname]}\n' \ f' Translation: {real[groupname]}' print(err_msg) def get_spdx_metadata_lines(ignore_copyright: bool = False, without_comment_prefix: bool = False) -> str: """Extract the SPDX meta data lines from the current source file.""" result = '' with Path(__file__).open('r') as handle: for line in handle: # ignore shebang if line.startswith('#!'): continue # ignore copyright if ignore_copyright and 'SPDX-FileCopyrightText' in line: continue # stop if line.startswith('"""') or line.startswith('import'): break # remove comments prefix "# " if without_comment_prefix and line.startswith('#'): line = line[1:] result = result + line.strip() + '\n' return result def _get_translation_for_desktop_string(value: str) -> dict[str, str]: """Check all po files for a translation of 'value' and create a list of the results fitting to a desktop file. e.g. GenericName[de]=Foo GenericName[vi]=Bar Returns: A dictionary indexed by language code and the translation as value. """ translations: dict[str, str] = {} for po_path in LOCAL_DIR.rglob('**/*.po'): po = polib.pofile(po_path) entry = po.find(value) # Nothing found or no translation if entry is None or not entry.msgstr: continue # Translation finished? if 'fuzzy' in entry.flags or entry.obsolete: continue translations[po_path.stem] = entry.msgstr return translations if __name__ == '__main__': check_existence() FIN_MSG = 'Please check the result via "git diff" before committing.' # Scan python source files for translatable strings if 'source' in sys.argv: update_po_template() update_po_language_files('--remove-obsolete-entries' in sys.argv) update_desktop_files() create_languages_py_file() print(FIN_MSG) sys.exit() # Download translations (as po-files) from Weblate and integrate them # into the repository. if 'weblate' in sys.argv: update_from_weblate() check_syntax_of_po_files() create_languages_py_file() print(FIN_MSG) sys.exit() # Check for redundant &-shortcuts if 'shortcuts' in sys.argv: check_shortcuts() sys.exit() # Check for syntax problems (also implicit called via "weblate") if 'syntax' in sys.argv: check_syntax_of_po_files() sys.exit() print('Use one of the following argument keywords:\n' ' source - Update the pot and po files with translatable ' 'strings extracted from py files. (Prepare upload to Weblate). ' 'Optional use --remove-obsolete-entries\n' ' weblate - Update the po files with translations from ' 'external translation service Weblate. (Download from Weblate)\n' ' shortcuts - Check po files for redundant keyboard shortcuts ' 'using "&"\n' ' syntax - Check syntax of po files. (Also done via "weblate" ' 'command)') sys.exit(1) backintime-1.6.1/updateversion.sh000077500000000000000000000046311514264426600170720ustar00rootroot00000000000000#!/bin/bash # SPDX-FileCopyrightText: © 2008 Oprea Dan # SPDX-FileCopyrightText: © 2012 Germar Reitze # SPDX-FileCopyrightText: © 2022 Jürgen Altfeld (aryoda) # SPDX-FileCopyrightText: © 2023 Christian Buhtz # # SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of the program "Back In time" which is released under GNU # General Public License v2 (GPLv2). See LICENSES directory or go to # . # Updates all version numbers using the VERSION file # and creates a new DEBIAN changelog file for this version # by extracting the changes of this version from the # CHANGES file. # # Development notes (May '23, Buhtz): # Should be treated as a workaround that will get replaced in the future. # Handling of version numbers and other package metadata can be done very # elegant and centralized within the Python Packaging process (e.g. using # pyproject.toml and additional tools. # Handling of Debian (and PPA) related stuff will be separated from that # upstream repo because it is distro specific. # Outdated TODOs: # TODO Requires refactoring and adjustments to separate # - the update of version numbers # - from the preparation of a new DEBIAN package release # since version updates must be possible without # a DEBIAN package release. # # TODO The version number must still be maintained in two places # (despite this script): # 1. File "VERSION" # 2. As headline in the file "CHANGES" # If those two numbers do not match the script does # not extract the correct changes of the version from the CHANGES file. # # TODO The name of this script file is misleading (find a better one) # TODO Make sure this script works idempotent (multiple calls = same result) # TODO This script does not update release dates scattered around in # different files (eg. common/man/C/backintime.1 line 1) VERSION=`cat VERSION` VERSION_WITHOUT_BRANCH=$VERSION if [[ $VERSION == *-dev ]] then VERSION+="."`git rev-parse --short HEAD` fi echo VERSION: $VERSION echo VERSION_WITHOUT_BRANCH: $VERSION_WITHOUT_BRANCH # MAINTAINER="Germar Reitze " # MAINTAINER="BIT Team " MAINTAINER="BIT Team " update_app_version () { echo "Update '$1'" sed --expression="s/^\(\s*\)__version__ = '.*'$/\1__version__ = '$VERSION'/" --in-place $1 } update_app_version common/version.py