mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
Merge remote-tracking branch 'origin/develop' into HEAD
# Conflicts: # .github/scripts/tests/test_command_descriptions.py
This commit is contained in:
@@ -80,169 +80,74 @@ class CommandDescriptionsTests(unittest.TestCase):
|
||||
self.assertEqual(catalog("sv")["terminal"]["commandDescriptions"][index],
|
||||
FIXTURE["locales"]["sv"][index])
|
||||
|
||||
def test_workflow_default_catalogs_rerun_without_provider_or_writes(self):
|
||||
def assert_completed_catalogs_are_stable(self, *, future_messages=None):
|
||||
workflow = (ROOT / ".github/workflows/build-i18n-messages.yml").read_text()
|
||||
languages = re.search(r'LANGS="\$\{LANGS:-(.*?)\}"', workflow).group(1)
|
||||
self.assertEqual(languages.split(","), list(MODULE.DEFAULT_LANGUAGES))
|
||||
locales = ["en", *languages.split(",")]
|
||||
shipped = {ROOT / f"AppImage/messages/{lang}/common.json": catalog(lang) for lang in locales}
|
||||
original_bytes = {path: path.read_bytes() for path in shipped}
|
||||
|
||||
def strings(node, path=()):
|
||||
# Independent traversal: every existing nonempty string, including
|
||||
# explicit English and obsolete human keys, must survive completion.
|
||||
if isinstance(node, str) and node:
|
||||
yield path, node
|
||||
elif isinstance(node, dict):
|
||||
for key, value in node.items():
|
||||
yield from strings(value, (*path, key))
|
||||
elif isinstance(node, list):
|
||||
for index, value in enumerate(node):
|
||||
yield from strings(value, (*path, index))
|
||||
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
for lang in ["en", *languages.split(",")]:
|
||||
path = root / lang / "common.json"
|
||||
path.parent.mkdir()
|
||||
shutil.copyfile(ROOT / f"AppImage/messages/{lang}/common.json", path)
|
||||
# This steady-state fixture assumes generation already finished.
|
||||
# Seed only intentional message additions; keep the
|
||||
# recovered command arrays and the repo catalogs exact. Runtime
|
||||
# missing-key fallback is covered by the JSX seam tests and by
|
||||
# test_storage_messages.cjs and test_health_text.cjs.
|
||||
if lang != "en":
|
||||
temporary = json.loads(path.read_text())
|
||||
for section, key in (
|
||||
("archives", "emptyMessage"),
|
||||
("archives", "formerJob"),
|
||||
("archives", "formerJobTitle"),
|
||||
("archives", "hiddenOtherNodes"),
|
||||
("archives", "scopeAllNodes"),
|
||||
("archives", "scopeAriaLabel"),
|
||||
("archives", "scopeShowAll"),
|
||||
("archives", "scopeThisNode"),
|
||||
("destinations", "backupsKeptMessage"),
|
||||
("destinations", "localAttachHelpMessage"),
|
||||
):
|
||||
temporary["backup"][section].setdefault(
|
||||
key, catalog("en")["backup"][section][key])
|
||||
temporary["storage"].setdefault(
|
||||
"savedSmartData", catalog("en")["storage"]["savedSmartData"])
|
||||
report = temporary["storage"]["smartReport"]
|
||||
source_report = catalog("en")["storage"]["smartReport"]
|
||||
for key in ("passedAssessment", "noReallocatedSectorsReported",
|
||||
"passedMeaningTitle", "passedMeaning"):
|
||||
report.setdefault(key, source_report[key])
|
||||
for key in ("passedTitle", "passedText"):
|
||||
report["recommendations"].setdefault(
|
||||
key, source_report["recommendations"][key])
|
||||
# New health-popup messages deliberately use runtime English
|
||||
# fallback until each locale is translated. Model generator
|
||||
# steady state only in this disposable copy, as for thermal keys.
|
||||
for key in (
|
||||
'certificateExpired',
|
||||
'certificateExpiresDays',
|
||||
'certificateInconclusive',
|
||||
'cpuCheckFailed',
|
||||
'cpuHighSustained',
|
||||
'cpuSustained',
|
||||
'fail2banCheckUnavailable',
|
||||
'fail2banInactive',
|
||||
'failedLoginsWithinThreshold',
|
||||
'kernelPackagesMore',
|
||||
'kernelPveUpdates',
|
||||
'loginCheckUnavailable',
|
||||
'memoryCheckFailed',
|
||||
'memoryPressure',
|
||||
'noFailedLogins',
|
||||
'noSwapConfigured',
|
||||
'noTemperatureSensor',
|
||||
'nonRunningKernelUpdates',
|
||||
'pendingPackageUpdates',
|
||||
'pendingSecurityUpdates',
|
||||
'pendingSecurityUpdatesDays',
|
||||
'pendingSecurityUpdatesUnpatched',
|
||||
'pveVersionAvailable',
|
||||
'ramHighSustained',
|
||||
'ramSustained',
|
||||
'runningKernelUpdate',
|
||||
'securityCheckUnavailable',
|
||||
'sensorHighSamplesSpan',
|
||||
'swapRamPressure',
|
||||
'systemNotUpdatedMonths',
|
||||
'systemNotUpdatedYear',
|
||||
'temperatureElevated',
|
||||
'unknownDetail',
|
||||
'updatesAptError',
|
||||
'updatesAptTimeout',
|
||||
'updatesCheckUnavailable',
|
||||
'uptimeKernelAdvice',
|
||||
'uptimeUnavailable',
|
||||
):
|
||||
temporary["healthStatus"]["details"].setdefault(
|
||||
key, catalog("en")["healthStatus"]["details"][key])
|
||||
# New thermal messages also await automatic translation.
|
||||
# Seed only these intentional additions in the temporary copy.
|
||||
for key in (
|
||||
"temperatureNoDisks", "temperatureNormal", "temperatureHighCount",
|
||||
"temperatureCriticalCount", "temperatureUnavailable",
|
||||
"temperatureIncomplete", "temperatureUnavailableCount",
|
||||
):
|
||||
temporary["storage"].setdefault(key, catalog("en")["storage"][key])
|
||||
# Every shipped locale carries the temperature alert fallback
|
||||
# keys; the seed only guards a catalog that lacks them. The
|
||||
# runtime fallback is tested separately.
|
||||
source_fallback = catalog("en")["runtime"]["notifications"]["fallback"]
|
||||
fallback = temporary["runtime"]["notifications"]["fallback"]
|
||||
for key in ("temperatureAlertTitle", "temperatureAlertBody",
|
||||
"recordedReason", "recordedDetails"):
|
||||
fallback.setdefault(key, source_fallback[key])
|
||||
# Slovak remains the exact upstream catalog; model the
|
||||
# pending outcome-key generator additions in disposable
|
||||
# copies rather than modifying its curated values.
|
||||
if lang == 'sk':
|
||||
local = temporary['runtime']['notifications']
|
||||
source = catalog('en')['runtime']['notifications']
|
||||
for key, value in source['backup'].items():
|
||||
local.setdefault('backup', {}).setdefault(key, value)
|
||||
local['channels']['email']['status'].setdefault(
|
||||
'unconfirmed', source['channels']['email']['status']['unconfirmed'])
|
||||
local['channels']['email']['status'].setdefault(
|
||||
'completed_with_warnings', source['channels']['email']['status']['completed_with_warnings'])
|
||||
path.write_text(json.dumps(temporary, ensure_ascii=False))
|
||||
# Model steady state after the bot fills these intentional new
|
||||
# messages; keep repository locales and all other leaves intact.
|
||||
if lang != "en":
|
||||
messages = json.loads(path.read_text())
|
||||
english = catalog("en")
|
||||
# Storage-retention labels await the translation bot. Seed
|
||||
# only those new leaves in this steady-state fixture.
|
||||
for key, value in english["backup"]["storageRetention"].items():
|
||||
messages["backup"].setdefault("storageRetention", {}).setdefault(key, value)
|
||||
for section, key in (("encryption", "pbsHelp"),
|
||||
("keyfileActions", "pveKeyDescription")):
|
||||
messages["backup"][section].setdefault(key, english["backup"][section][key])
|
||||
for key in ("sshUserHelpMessage", "sshKeyHelpMessage", "sshKeySetupTitle",
|
||||
"sshKeySetupHelp", "sshAuthorizedKeyHelp"):
|
||||
messages["backup"]["destinations"].setdefault(
|
||||
key, english["backup"]["destinations"][key])
|
||||
messages["backup"]["actions"].setdefault(
|
||||
"prepareSshKey", english["backup"]["actions"]["prepareSshKey"])
|
||||
# New LXC observation labels intentionally ship only EN/SK.
|
||||
# Model the bot's future output in temporary catalogs, just
|
||||
# like the other pending keys above; never rewrite locales.
|
||||
messages["scriptTerminal"].setdefault("endOfInput", english["scriptTerminal"]["endOfInput"])
|
||||
for key in ("noShell", "enterFailed"):
|
||||
messages["lxcTerminal"]["errors"].setdefault(key, english["lxcTerminal"]["errors"][key])
|
||||
# The notification history panel texts await the bot as well.
|
||||
for key, value in english["settings"]["notifications"]["history"].items():
|
||||
messages["settings"]["notifications"].setdefault("history", {}).setdefault(key, value)
|
||||
for key in ("checkNow", "checkReadOnlyHelp", "checkCooldown",
|
||||
"checkStale", "checkStaleHelp", "checkBeforeUpdate",
|
||||
"startBeforeCheck", "notCheckedYet",
|
||||
"checkStillRunning", "refreshCheckHelp",
|
||||
"checkInProgress", "checkSystemPackages", "runCustomCommand",
|
||||
"installedVersionUnverified", "versionStatusUnknown"):
|
||||
messages["vmLxc"]["updates"].setdefault(
|
||||
key, english["vmLxc"]["updates"][key])
|
||||
for key in ("startPending", "shutdownPending", "rebootPending", "stopPending"):
|
||||
messages["vmLxc"]["actions"].setdefault(
|
||||
key, english["vmLxc"]["actions"][key])
|
||||
for key in ("osDockerScope", "dockerImageMethod", "unverifiedTargetsHelp"):
|
||||
messages["vmLxc"]["bulkUpdate"].setdefault(
|
||||
key, english["vmLxc"]["bulkUpdate"][key])
|
||||
messages["vmLxc"]["errors"].setdefault(
|
||||
"controlNotConfirmed", english["vmLxc"]["errors"]["controlNotConfirmed"])
|
||||
path.write_text(json.dumps(messages, ensure_ascii=False))
|
||||
before = {p: p.read_bytes() for p in root.glob("*/common.json")}
|
||||
root = Path(directory).resolve()
|
||||
for path in shipped:
|
||||
destination = root / path.parent.name / "common.json"
|
||||
destination.parent.mkdir()
|
||||
shutil.copyfile(path, destination)
|
||||
if future_messages is not None:
|
||||
source = json.loads((root / "en/common.json").read_text())
|
||||
source["futureFeatureFixture"] = future_messages
|
||||
(root / "en/common.json").write_text(json.dumps(source))
|
||||
|
||||
argv = [str(SCRIPT), "--source", str(root / "en/common.json"),
|
||||
"--messages-dir", str(root), "--languages", languages, "--sleep", "0"]
|
||||
output = io.StringIO()
|
||||
# Establish steady state with the real generator and a deterministic
|
||||
# offline provider. Translation happens only in disposable catalogs;
|
||||
# adding an EN-only feature never needs a hand-maintained seed list.
|
||||
with mock.patch.object(sys, "argv", argv), \
|
||||
mock.patch.object(MODULE, "translate_one", side_effect=lambda text, lang, *_: f"TEST {lang} {text}") as seed, \
|
||||
mock.patch.object(MODULE, "write_json", wraps=MODULE.write_json) as initial_writer, \
|
||||
redirect_stdout(output), redirect_stderr(output):
|
||||
self.assertEqual(MODULE.main(), 0, output.getvalue())
|
||||
self.assertNotRegex(output.getvalue(), r"(?m)^Completed with [0-9]+ translation failures")
|
||||
self.assertTrue(all(call.args[0].is_relative_to(root) for call in initial_writer.call_args_list))
|
||||
for path, original in shipped.items():
|
||||
completed = json.loads((root / path.parent.name / "common.json").read_text())
|
||||
for keys, value in strings(original):
|
||||
actual = completed
|
||||
for key in keys:
|
||||
actual = actual[key]
|
||||
self.assertEqual(actual, value, f"{path.parent.name}: {keys}")
|
||||
# The recovered arrays remain exact, including frozen English.
|
||||
if path.parent.name != "en":
|
||||
self.assertEqual(completed["terminal"]["commandDescriptions"],
|
||||
FIXTURE["locales"].get(path.parent.name,
|
||||
original["terminal"]["commandDescriptions"]))
|
||||
if future_messages is not None and path.parent.name != "en":
|
||||
self.assertEqual(completed["futureFeatureFixture"], {
|
||||
"title": f"TEST {path.parent.name} Future feature {{count}}",
|
||||
"items": [f"TEST {path.parent.name} First item", {"label": f"TEST {path.parent.name} Second item"}],
|
||||
"enabled": False, "count": 2, "empty": [],
|
||||
})
|
||||
if future_messages is not None:
|
||||
self.assertGreaterEqual(seed.call_count, 3 * len(languages.split(",")))
|
||||
before = {p: p.read_bytes() for p in root.glob("*/common.json")}
|
||||
output = io.StringIO()
|
||||
# Keep the original strict assertion: once completed, any provider
|
||||
# call or catalog write is a regression. No production locale edits.
|
||||
with mock.patch.object(sys, "argv", argv), \
|
||||
mock.patch.object(MODULE, "translate_one", side_effect=AssertionError("provider forbidden")) as provider, \
|
||||
mock.patch.object(MODULE, "write_json", side_effect=AssertionError("writes forbidden")) as writer, \
|
||||
@@ -254,6 +159,17 @@ class CommandDescriptionsTests(unittest.TestCase):
|
||||
self.assertEqual(before, {p: p.read_bytes() for p in before})
|
||||
for lang in languages.split(","):
|
||||
self.assertIn(f"{lang}: nothing to translate", output.getvalue())
|
||||
self.assertEqual(original_bytes, {path: path.read_bytes() for path in shipped})
|
||||
|
||||
def test_workflow_default_catalogs_rerun_without_provider_or_writes(self):
|
||||
self.assert_completed_catalogs_are_stable()
|
||||
|
||||
def test_new_english_feature_preserves_curated_values_and_reruns_without_writes(self):
|
||||
self.assert_completed_catalogs_are_stable(future_messages={
|
||||
"title": "Future feature {count}",
|
||||
"items": ["First item", {"label": "Second item"}],
|
||||
"enabled": False, "count": 2, "empty": [],
|
||||
})
|
||||
|
||||
def test_actual_consumer_lookup_null_fallback_and_explicit_english(self):
|
||||
node = require_node()
|
||||
|
||||
@@ -17,13 +17,15 @@ MENU = ROOT / 'oci/src/proxmenux_oci/management.py'
|
||||
CHOICE = 'Recover the previous installation'
|
||||
BEFORE = 'The operation stopped halfway. Choose "{choice}" for this container in the OCI management menu.'
|
||||
AFTER = 'The recovery did not complete. Review the log and choose "{choice}" again for this container in the OCI management menu.'
|
||||
REGISTRY_ADVICE = ('Check the image reference and registry access. If the registry is unavailable, '
|
||||
'try again later. For a private image, sign in from Registry accounts in the OCI menu.')
|
||||
NEW_KEYS = (
|
||||
'The Compose file describes several services:',
|
||||
'Only one service at a time can be installed this way.',
|
||||
'No docker run command was given',
|
||||
'Image selection was cancelled',
|
||||
'Could not inspect the image in its registry:',
|
||||
'Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.',
|
||||
REGISTRY_ADVICE,
|
||||
BEFORE, AFTER,
|
||||
)
|
||||
|
||||
@@ -117,16 +119,16 @@ class OciWordingTests(TestCase):
|
||||
self.assertEqual(report('example:latest'), (True, 'The image is in its registry: amd64'))
|
||||
self.assertEqual(run.call_count, 1)
|
||||
|
||||
def test_failed_registry_inspection_has_neutral_advice(self):
|
||||
def test_failed_registry_inspection_points_to_registry_accounts(self):
|
||||
ui = SimpleNamespace(message=Mock())
|
||||
fn = function(CUSTOM, 'explore', read_definition=lambda _: ('definition', 'source'),
|
||||
ignored_settings=lambda _: [], template_from_compose=lambda _: {
|
||||
'container_contract': {'image': {'reference': 'example:latest'}}},
|
||||
describe=lambda _: 'SUMMARY', registry_report=lambda _: (False, 'INSPECTION FAILED'))
|
||||
describe=lambda _: 'SUMMARY', registry_report=lambda _: (False, 'INSPECTION FAILED'),
|
||||
_registry_refused=lambda _: False)
|
||||
fn(ui)
|
||||
self.assertEqual(ui.message.call_args.args[0], 'SUMMARY\n\nINSPECTION FAILED\n\n'
|
||||
'Check the image reference and registry access. If the registry is unavailable, '
|
||||
'try again later. A private registry needs credentials, which are not supported yet.')
|
||||
self.assertEqual(ui.message.call_args.args[0], 'SUMMARY\n\nINSPECTION FAILED\n\n' + REGISTRY_ADVICE)
|
||||
self.assertNotIn('not supported yet', ui.message.call_args.args[0])
|
||||
|
||||
def test_recovery_hint_quotes_translated_choice_in_all_locales(self):
|
||||
# Pin the real translated management choice, not an English AST constant alone.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Apprise Slack and Matrix
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/test-apprise-services.yml'
|
||||
- 'AppImage/scripts/notification_channels.py'
|
||||
- 'AppImage/components/apprise-service-help.tsx'
|
||||
- 'AppImage/components/notification-settings.tsx'
|
||||
- 'tests/test_apprise_services.py'
|
||||
- 'tests/test_apprise_service_help.cjs'
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- 'AppImage/scripts/notification_channels.py'
|
||||
- 'AppImage/components/apprise-service-help.tsx'
|
||||
- 'tests/test_apprise_services.py'
|
||||
- 'tests/test_apprise_service_help.cjs'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
apprise-services:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
apprise: ['1.7.0', '2.0.1']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22.14.0'
|
||||
- name: Install fixture dependencies
|
||||
run: |
|
||||
python -m pip install 'apprise==${{ matrix.apprise }}'
|
||||
npm ci --prefix .github/ci/offline-node --ignore-scripts --no-audit --no-fund
|
||||
- name: Test real provider plugins with mocked HTTP
|
||||
run: python -B -m unittest discover -s tests -p test_apprise_services.py -v
|
||||
- name: Render provider help and locale fallback
|
||||
env:
|
||||
NODE_PATH: ${{ github.workspace }}/.github/ci/offline-node/node_modules
|
||||
run: node tests/test_apprise_service_help.cjs
|
||||
@@ -0,0 +1,73 @@
|
||||
name: Figurine installation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/test-figurine.yml'
|
||||
- 'tests/test_figurine_installation.py'
|
||||
- 'scripts/post_install/customizable_post_install.sh'
|
||||
- 'AppImage/scripts/post_install_versions.py'
|
||||
- 'AppImage/scripts/flask_proxmenux_routes.py'
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- '.github/workflows/test-figurine.yml'
|
||||
- 'tests/test_figurine_installation.py'
|
||||
- 'scripts/post_install/customizable_post_install.sh'
|
||||
- 'AppImage/scripts/post_install_versions.py'
|
||||
- 'AppImage/scripts/flask_proxmenux_routes.py'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
installer-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Check shell syntax and isolated installer regressions
|
||||
run: |
|
||||
bash -n scripts/post_install/customizable_post_install.sh
|
||||
python3 -B -m unittest discover -s tests -p test_figurine_installation.py -v
|
||||
- name: Install ARM user-mode emulation for release smoke tests
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y --no-install-recommends qemu-user
|
||||
- name: Verify and run the pinned AMD64, ARM64 and ARMv7 release binaries
|
||||
env:
|
||||
FIGURINE_VERSION: '2.1.1'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
scratch="$(mktemp -d)"
|
||||
trap 'rm -rf "$scratch"' EXIT
|
||||
while read -r arch sha; do
|
||||
archive="figurine_linux_${arch}_v${FIGURINE_VERSION}.tar.gz"
|
||||
target="$scratch/$arch"
|
||||
mkdir -p "$target"
|
||||
curl --fail --location --retry 3 --output "$target/$archive" \
|
||||
"https://github.com/arsham/figurine/releases/download/v${FIGURINE_VERSION}/$archive"
|
||||
printf '%s %s\n' "$sha" "$target/$archive" | sha256sum --check
|
||||
tar -xf "$target/$archive" -C "$target"
|
||||
runner=()
|
||||
case "$arch" in
|
||||
arm64) runner=(qemu-aarch64) ;;
|
||||
arm) runner=(qemu-arm) ;;
|
||||
esac
|
||||
"${runner[@]}" "$target/deploy/figurine" --version | tee "$target/version"
|
||||
grep -F "figurine version v$FIGURINE_VERSION" "$target/version"
|
||||
"${runner[@]}" "$target/deploy/figurine" -f "3d.flf" "ProxMenux-test" > "$target/banner"
|
||||
test -s "$target/banner"
|
||||
printf 'PASS: %s version and login banner\n' "$arch"
|
||||
done <<'ASSETS'
|
||||
amd64 f2b1c076942c94009d133df0f304a234a0994bf590b40f2927668324d578306a
|
||||
arm64 611550ddb31a75437be3f8587bcdd029d0d890f4d820b7f494a2c6615fecba10
|
||||
arm 429e66bded486d49f730c4a6559e728cd1e9a163a0f56a85867e2cbec010171d
|
||||
ASSETS
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Offline i18n tests
|
||||
name: Offline script regressions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -42,6 +42,8 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Preserve this check ID for existing branch protection rules. This suite
|
||||
# includes menu, download and scheduler regressions as well as i18n tests.
|
||||
offline-i18n:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
@@ -61,7 +63,7 @@ jobs:
|
||||
test -x /usr/bin/jq
|
||||
- name: Install OCI wording test dependency
|
||||
run: python3 -m pip install 'PyYAML>=6,<7'
|
||||
- name: Run complete offline script test suite
|
||||
- name: Run offline i18n and script regressions
|
||||
env:
|
||||
PYTHONDONTWRITEBYTECODE: '1'
|
||||
run: python3 -m unittest discover -s .github/scripts/tests -v
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Offline OCI registry tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'oci/**'
|
||||
- '.github/workflows/test-oci-registries.yml'
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- 'oci/**'
|
||||
- '.github/workflows/test-oci-registries.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
registry-accounts:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.13'
|
||||
- name: Install OCI test dependencies
|
||||
run: python3 -m pip install -r oci/requirements.txt
|
||||
- name: Run offline registry account tests
|
||||
env:
|
||||
PYTHONDONTWRITEBYTECODE: '1'
|
||||
run: python3 -m unittest discover -s oci/tests -p 'test_registry_*.py' -v
|
||||
@@ -0,0 +1,32 @@
|
||||
"use client"
|
||||
|
||||
import { ExternalLink } from "lucide-react"
|
||||
import { useT } from "../lib/i18n/provider"
|
||||
|
||||
// These are examples, never defaults: opening help must not replace a saved
|
||||
// destination or put placeholder credentials into the notification settings.
|
||||
export function AppriseServiceHelp() {
|
||||
const t = useT()
|
||||
return <details className="rounded-md border border-border bg-muted/20 p-2 text-xs">
|
||||
<summary className="cursor-pointer font-medium">{t("settings.notifications.ui.appriseServiceHelp")}</summary>
|
||||
<div className="grid gap-3 pt-3 sm:grid-cols-2">
|
||||
<div className="space-y-1.5 min-w-0">
|
||||
<h4 className="font-medium">Slack</h4>
|
||||
<p className="text-muted-foreground">{t("settings.notifications.ui.appriseSlackSteps")}</p>
|
||||
<code className="block break-all rounded bg-background p-2 text-[10px]">https://hooks.slack.com/services/TOKEN_A/TOKEN_B/TOKEN_C</code>
|
||||
<a href="https://appriseit.com/services/slack/" target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-cyan-500 hover:underline">
|
||||
{t("settings.notifications.ui.appriseSlackDocs")} <ExternalLink className="h-3 w-3" />
|
||||
</a>
|
||||
</div>
|
||||
<div className="space-y-1.5 min-w-0">
|
||||
<h4 className="font-medium">Matrix</h4>
|
||||
<p className="text-muted-foreground">{t("settings.notifications.ui.appriseMatrixSteps")}</p>
|
||||
<code className="block break-all rounded bg-background p-2 text-[10px]">matrixs://USER:PASSWORD@matrix.example.com/!ROOM_ID:matrix.example.com</code>
|
||||
<a href="https://appriseit.com/services/matrix/" target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-cyan-500 hover:underline">
|
||||
{t("settings.notifications.ui.appriseMatrixDocs")} <ExternalLink className="h-3 w-3" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-3 text-muted-foreground">{t("settings.notifications.ui.appriseServiceFinish")}</p>
|
||||
</details>
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { AppriseServiceHelp } from "./apprise-service-help"
|
||||
import { useState, useEffect, useCallback } from "react"
|
||||
import { useTheme } from "next-themes"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card"
|
||||
@@ -2061,6 +2062,7 @@ export function NotificationSettings() {
|
||||
Enable toggle + Test button pattern as the other
|
||||
channels. */}
|
||||
<TabsContent value="apprise" className="space-y-3 pt-2">
|
||||
<AppriseServiceHelp />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-xs font-medium">{t("settings.notifications.ui.enableApprise")}</Label>
|
||||
|
||||
@@ -35,6 +35,23 @@ import DOMPurify from "dompurify"
|
||||
import { marked } from "marked"
|
||||
import { getCountFormKey, useI18n, useT } from "@/lib/i18n/provider"
|
||||
|
||||
// A schedule record predating the structured reason code still contains one
|
||||
// of these exact diagnostic messages. Recognise only those known historical
|
||||
// values so an already-recorded safe skip localizes after an upgrade, while
|
||||
// unrelated freeform diagnostics remain verbatim for troubleshooting.
|
||||
const LEGACY_STOPPED_SCHEDULE_REASONS = new Set([
|
||||
"container is stopped; scheduled update was skipped",
|
||||
"container was stopped before scheduled update could begin",
|
||||
])
|
||||
|
||||
const scheduleReasonCodeFromPersisted = (reasonCode: unknown, reason: unknown): string | null => {
|
||||
if (typeof reasonCode === "string" && reasonCode) return reasonCode
|
||||
if (typeof reason === "string" && LEGACY_STOPPED_SCHEDULE_REASONS.has(reason.toLowerCase())) {
|
||||
return "stopped_container"
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Sent by /api/vms only for LXC rows, only when the user has enabled
|
||||
// `lxc_updates_available` notifications. The Monitor populates this
|
||||
// from managed_installs registry → frontend uses it to render the
|
||||
@@ -2077,6 +2094,7 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
const [scheduleLastRunAt, setScheduleLastRunAt] = useState<string | null>(null)
|
||||
const [scheduleLastRunStatus, setScheduleLastRunStatus] = useState<string | null>(null)
|
||||
const [scheduleLastRunReason, setScheduleLastRunReason] = useState<string | null>(null)
|
||||
const [scheduleLastRunReasonCode, setScheduleLastRunReasonCode] = useState<string | null>(null)
|
||||
const [scheduleLastRunLog, setScheduleLastRunLog] = useState<string | null>(null)
|
||||
const [scheduleLastRunRebootRequired, setScheduleLastRunRebootRequired] = useState(false)
|
||||
const [scheduleLastRunRebootPackages, setScheduleLastRunRebootPackages] = useState<string[]>([])
|
||||
@@ -2153,6 +2171,7 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
setScheduleLastRunAt(s.last_run_at || null)
|
||||
setScheduleLastRunStatus(s.last_run_status || null)
|
||||
setScheduleLastRunReason(s.last_run_reason || null)
|
||||
setScheduleLastRunReasonCode(scheduleReasonCodeFromPersisted(s.last_run_reason_code, s.last_run_reason))
|
||||
setScheduleLastRunLog(s.last_run_log || null)
|
||||
setScheduleLastRunRebootRequired(s.last_run_reboot_required === true)
|
||||
setScheduleLastRunRebootPackages(Array.isArray(s.last_run_reboot_packages)
|
||||
@@ -2430,6 +2449,11 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
const renderScheduleRunDetails = (indented = false) => {
|
||||
if (!scheduleLastRunAt || !selectedVM) return null
|
||||
const spacing = indented ? "pl-4" : ""
|
||||
const scheduleLastRunReasonText = scheduleLastRunReasonCode === "stopped_container"
|
||||
? selectedVM.status === "stopped"
|
||||
? t("vmLxc.scheduled.reasonStoppedContainer")
|
||||
: t("vmLxc.scheduled.reasonStoppedContainerHistorical")
|
||||
: scheduleLastRunReason
|
||||
return (
|
||||
<div className={`space-y-1.5 ${spacing}`}>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
@@ -2443,14 +2467,14 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
: scheduleLastRunStatus === "deferred"
|
||||
? t("vmLxc.scheduled.runDeferred")
|
||||
: scheduleLastRunStatus === "skipped"
|
||||
? t("vmLxc.scheduled.runSkipped")
|
||||
? t("vmLxc.scheduled.runSkippedStatus")
|
||||
: t("vmLxc.scheduled.runFailed")}
|
||||
</span></>
|
||||
)}
|
||||
</div>
|
||||
{scheduleLastRunReason && (
|
||||
{scheduleLastRunReasonText && (
|
||||
<div className="text-xs text-muted-foreground break-words">
|
||||
{scheduleLastRunReason}
|
||||
{scheduleLastRunReasonText}
|
||||
</div>
|
||||
)}
|
||||
{scheduleLastRunRebootRequired && (
|
||||
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"Donnerstag",
|
||||
"Freitag",
|
||||
"Samstag"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "Lauf übersprungen",
|
||||
"reasonStoppedContainer": "Container ist gestoppt; das geplante Update wurde übersprungen.",
|
||||
"reasonStoppedContainerHistorical": "Der Container wurde zum geplanten Aktualisierungszeitpunkt gestoppt."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "Host-Cron erkannt",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Aktivieren Sie Benachrichtigungen, um System-, Gesundheits- und Sicherheitswarnungen über die konfigurierten Kanäle zu erhalten.",
|
||||
"notificationLanguage": "Benachrichtigungssprache",
|
||||
"selectNotificationLanguage": "Benachrichtigungssprache auswählen",
|
||||
"notificationLanguageHint": "Wird für deterministische Laufzeitbenachrichtigungen verwendet, auch wenn KI deaktiviert ist."
|
||||
"notificationLanguageHint": "Wird für deterministische Laufzeitbenachrichtigungen verwendet, auch wenn KI deaktiviert ist.",
|
||||
"appriseServiceHelp": "Slack und Matrix einrichten",
|
||||
"appriseSlackSteps": "Erstellen Sie in Ihrer Slack-App einen eingehenden Webhook für den Zielkanal und fügen Sie dessen vollständige HTTPS-URL in das Feld Apprise-URL ein. Eine Umwandlung ist nicht erforderlich.",
|
||||
"appriseSlackDocs": "Slack-URL-Formate und Einrichtung",
|
||||
"appriseMatrixSteps": "Verwenden Sie ein Benachrichtigungskonto, das in den Raum schreiben darf. Ersetzen Sie den Beispielbenutzer, das Passwort, den Homeserver und die vollständige Raum-ID; kodieren Sie Sonderzeichen in Zugangsdaten für URLs. Das Schema matrixs verwendet HTTPS. Informationen zur Unterstützung von Tokens, SSO und verschlüsselten Räumen in Ihrer installierten Apprise-Version finden Sie in der Dokumentation.",
|
||||
"appriseMatrixDocs": "Matrix-URL-Formate und Einrichtung",
|
||||
"appriseServiceFinish": "Aktivieren Sie Apprise, geben Sie Ihre URL ein, wählen Sie Benachrichtigungskategorien oder einzelne Ereignisse aus, speichern Sie und verwenden Sie anschließend Test senden. Diese Beispiele ändern Ihre gespeicherte URL nicht. Dieser Apprise-Kanal hat ein Ziel; verwenden Sie die Apprise-API für mehrere Dienste gleichzeitig."
|
||||
},
|
||||
"ai": {
|
||||
"title": "KI-Verbesserung",
|
||||
|
||||
@@ -1288,6 +1288,9 @@
|
||||
"runFailed": "✗ failed",
|
||||
"runDeferred": "held for safety",
|
||||
"runSkipped": "nothing pending",
|
||||
"runSkippedStatus": "run skipped",
|
||||
"reasonStoppedContainer": "Container is stopped; scheduled update was skipped.",
|
||||
"reasonStoppedContainerHistorical": "Container was stopped at the scheduled update time.",
|
||||
"releaseDelaySummary": "{days}-day release hold",
|
||||
"releaseDelayLabel": "Wait after a new app release",
|
||||
"releaseDelayNone": "No waiting period",
|
||||
@@ -2094,6 +2097,12 @@
|
||||
"pushoverCredentialsHint": "Create an application in Pushover and copy its API token and your user or group key.",
|
||||
"enableApprise": "Enable Apprise",
|
||||
"urlFormats": "+URL formats",
|
||||
"appriseServiceHelp": "Slack and Matrix setup",
|
||||
"appriseSlackSteps": "Create an Incoming Webhook in your Slack app for the target channel, then paste its complete HTTPS URL into Apprise URL. No conversion is needed.",
|
||||
"appriseSlackDocs": "Slack URL formats and setup",
|
||||
"appriseMatrixSteps": "Use a notification account that can post to the room. Replace the example user, password, homeserver and full room ID; URL-encode special characters in credentials. The matrixs scheme uses HTTPS. See the documentation for token, SSO and encrypted-room support in your installed Apprise version.",
|
||||
"appriseMatrixDocs": "Matrix URL formats and setup",
|
||||
"appriseServiceFinish": "Enable Apprise, enter your URL, choose the notification categories or individual events, save, then use Send Test. These examples do not change your saved URL. This Apprise channel has one destination; use Apprise API for several services at once.",
|
||||
"appriseUrl": "Apprise URL",
|
||||
"showUrl": "Show URL",
|
||||
"hideUrl": "Hide URL",
|
||||
|
||||
@@ -607,7 +607,7 @@
|
||||
"controllerBusyTime": "Minutos totales que el controlador pasó procesando comandos de E/S. Los valores altos indican una carga de trabajo pesada y sostenida.",
|
||||
"errorLogEntries": "Número de entradas en el registro de información de errores. A menudo incluye artefactos benignos de autoevaluación; verifique con Errores de Medios.",
|
||||
"warningTempTime": "Total de minutos transcurridos por encima del umbral de temperatura de advertencia. Provoca una limitación del rendimiento. El cero es ideal.",
|
||||
"criticalTempTime": "Minutos totales pasados por encima del umbral de temperatura crítica. La unidad puede apagarse para evitar daños. Siempre debe ser cero.",
|
||||
"criticalTempTime": "Minutos totales pasados por encima del umbral de temperatura crítica. La unidad puede apagarse para evitar daños. Siempre debe ser cero.",
|
||||
"warningCompositeTemperatureTime": "Minutos totales que la temperatura compuesta superó el umbral de advertencia.",
|
||||
"criticalCompositeTemperatureTime": "Minutos totales la temperatura compuesta superó el umbral crítico. Debe ser cero.",
|
||||
"thermalManagementT1TransCount": "Número de veces que la unidad entró en aceleración térmica ligera (T1). Indica problemas de enfriamiento.",
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"jueves",
|
||||
"viernes",
|
||||
"sábado"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "ejecución omitida",
|
||||
"reasonStoppedContainer": "El contenedor está parado; se ha omitido la actualización programada.",
|
||||
"reasonStoppedContainerHistorical": "El contenedor estaba parado a la hora de la actualización programada."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "cron del host detectado",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Habilite notificaciones para recibir alertas del sistema, de salud y de seguridad a través de los canales configurados.",
|
||||
"notificationLanguage": "Idioma de notificación",
|
||||
"selectNotificationLanguage": "Seleccione el idioma de notificación",
|
||||
"notificationLanguageHint": "Se utiliza para notificaciones deterministas en tiempo de ejecución incluso cuando la IA está deshabilitada."
|
||||
"notificationLanguageHint": "Se utiliza para notificaciones deterministas en tiempo de ejecución incluso cuando la IA está deshabilitada.",
|
||||
"appriseServiceHelp": "Configuración de Slack y Matrix",
|
||||
"appriseSlackSteps": "Crea un webhook entrante en tu aplicación de Slack para el canal de destino y pega su URL HTTPS completa en URL de Apprise. No hace falta convertirla.",
|
||||
"appriseSlackDocs": "Formatos de URL y configuración de Slack",
|
||||
"appriseMatrixSteps": "Utiliza una cuenta de notificaciones que pueda publicar en la sala. Sustituye el usuario, la contraseña, el servidor de origen y el ID completo de la sala del ejemplo; codifica para URL los caracteres especiales de las credenciales. El esquema matrixs utiliza HTTPS. Consulta en la documentación la compatibilidad con tokens, SSO y salas cifradas de tu versión de Apprise.",
|
||||
"appriseMatrixDocs": "Formatos de URL y configuración de Matrix",
|
||||
"appriseServiceFinish": "Activa Apprise, introduce tu URL, elige las categorías de notificación o los eventos individuales, guarda y utiliza Enviar prueba. Estos ejemplos no cambian tu URL guardada. Este canal de Apprise tiene un único destino; utiliza la API de Apprise para varios servicios a la vez."
|
||||
},
|
||||
"ai": {
|
||||
"title": "mejora de la IA",
|
||||
@@ -3563,8 +3572,8 @@
|
||||
"short": {
|
||||
"hour": "Pasada 1 hora",
|
||||
"day": "Pasadas 24h",
|
||||
"week": "Pasados los 7 días",
|
||||
"month": "Pasados los 30 días",
|
||||
"week": "Pasados los 7 días",
|
||||
"month": "Pasados los 30 días",
|
||||
"year": "Último 1 año"
|
||||
},
|
||||
"last": {
|
||||
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"Jeudi",
|
||||
"Vendredi",
|
||||
"Samedi"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "exécution ignorée",
|
||||
"reasonStoppedContainer": "Le conteneur est arrêté ; la mise à jour programmée a été ignorée.",
|
||||
"reasonStoppedContainerHistorical": "Le conteneur était arrêté à l'heure de la mise à jour programmée."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "cron hôte détecté",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Activez les notifications pour recevoir des alertes système, de santé et de sécurité via les canaux configurés.",
|
||||
"notificationLanguage": "Langue de notification",
|
||||
"selectNotificationLanguage": "Sélectionnez la langue de notification",
|
||||
"notificationLanguageHint": "Utilisé pour les notifications d'exécution déterministes, même lorsque l'IA est désactivée."
|
||||
"notificationLanguageHint": "Utilisé pour les notifications d'exécution déterministes, même lorsque l'IA est désactivée.",
|
||||
"appriseServiceHelp": "Configuration de Slack et Matrix",
|
||||
"appriseSlackSteps": "Créez un webhook entrant dans votre application Slack pour le canal cible, puis collez son URL HTTPS complète dans le champ URL Apprise. Aucune conversion n'est nécessaire.",
|
||||
"appriseSlackDocs": "Formats d'URL et configuration de Slack",
|
||||
"appriseMatrixSteps": "Utilisez un compte de notification autorisé à publier dans le salon. Remplacez l'utilisateur, le mot de passe, le serveur d'origine et l'identifiant complet du salon de l'exemple ; encodez les caractères spéciaux des identifiants pour les URL. Le schéma matrixs utilise HTTPS. Consultez la documentation pour la prise en charge des jetons, du SSO et des salons chiffrés dans votre version d'Apprise.",
|
||||
"appriseMatrixDocs": "Formats d'URL et configuration de Matrix",
|
||||
"appriseServiceFinish": "Activez Apprise, saisissez votre URL, choisissez les catégories de notification ou les événements individuels, enregistrez, puis utilisez Envoyer un test. Ces exemples ne modifient pas votre URL enregistrée. Ce canal Apprise possède une destination ; utilisez l'API Apprise pour plusieurs services à la fois."
|
||||
},
|
||||
"ai": {
|
||||
"title": "Amélioration de l'IA",
|
||||
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"Giovedì",
|
||||
"Venerdì",
|
||||
"Sabato"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "esecuzione saltata",
|
||||
"reasonStoppedContainer": "Il contenitore è fermo; l'aggiornamento pianificato è stato saltato.",
|
||||
"reasonStoppedContainerHistorical": "Il contenitore era fermo all'ora dell'aggiornamento pianificato."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "cron host rilevato",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Abilita le notifiche per ricevere avvisi di sistema, integrità e sicurezza attraverso i canali configurati.",
|
||||
"notificationLanguage": "Lingua notifiche",
|
||||
"selectNotificationLanguage": "Seleziona lingua notifiche",
|
||||
"notificationLanguageHint": "Usata per le notifiche runtime deterministiche anche quando l’IA è disabilitata."
|
||||
"notificationLanguageHint": "Usata per le notifiche runtime deterministiche anche quando l’IA è disabilitata.",
|
||||
"appriseServiceHelp": "Configurazione di Slack e Matrix",
|
||||
"appriseSlackSteps": "Crea un webhook in ingresso nell'app Slack per il canale di destinazione, quindi incolla il suo URL HTTPS completo nel campo URL di Apprise. Non è necessaria alcuna conversione.",
|
||||
"appriseSlackDocs": "Formati URL e configurazione di Slack",
|
||||
"appriseMatrixSteps": "Usa un account di notifica autorizzato a pubblicare nella stanza. Sostituisci utente, password, homeserver e ID completo della stanza dell'esempio; codifica per URL i caratteri speciali nelle credenziali. Lo schema matrixs usa HTTPS. Consulta la documentazione per il supporto di token, SSO e stanze cifrate nella versione di Apprise installata.",
|
||||
"appriseMatrixDocs": "Formati URL e configurazione di Matrix",
|
||||
"appriseServiceFinish": "Abilita Apprise, inserisci il tuo URL, scegli le categorie di notifica o i singoli eventi, salva e poi usa Invia test. Questi esempi non modificano l'URL salvato. Questo canale Apprise ha una sola destinazione; usa l'API Apprise per più servizi contemporaneamente."
|
||||
},
|
||||
"ai": {
|
||||
"title": "Miglioramento con IA",
|
||||
|
||||
@@ -353,7 +353,7 @@
|
||||
"downloadJson": "Baixar JSON",
|
||||
"delete": "Excluir",
|
||||
"confirmDelete": "Excluir este registro de teste?",
|
||||
"note": "Os resultados dos testes são armazenados localmente e usados para gerar relatórios SMART detalhados."
|
||||
"note": "Os resultados dos testes são armazenados localmente e usados para gerar relatórios SMART detalhados."
|
||||
},
|
||||
"smartReport": {
|
||||
"title": "Relatório de saúde SMART",
|
||||
@@ -595,8 +595,8 @@
|
||||
"availableSpare": "Porcentagem de blocos NAND sobressalentes restantes para substituição de blocos defeituosos. Um alerta é acionado abaixo do limite.",
|
||||
"availableSpareThreshold": "Mínimo definido pelo fabricante para peças sobressalentes disponíveis. Abaixo disso, a unidade sinaliza um aviso crítico.",
|
||||
"percentageUsed": "Impulsione a estimativa da resistência consumida com base nos ciclos de gravação reais versus nominais. 100% significa que o TBW avaliado foi atingido; a unidade pode continuar funcionando além disso.",
|
||||
"mediaErrors": "Erros de leitura/gravação irrecuperáveis no flash NAND. Qualquer valor diferente de zero indica dano celular permanente. Contagem crescente significa substituição em breve.",
|
||||
"mediaIntegrityErrors": "Erros irrecuperáveis detectados pelo controlador. Diferente de zero significa risco de corrupção de dados.",
|
||||
"mediaErrors": "Erros de leitura/gravação irrecuperáveis no flash NAND. Qualquer valor diferente de zero indica dano celular permanente. Contagem crescente significa substituição em breve.",
|
||||
"mediaIntegrityErrors": "Erros irrecuperáveis detectados pelo controlador. Diferente de zero significa risco de corrupção de dados.",
|
||||
"unsafeShutdowns": "Perdas de energia sem descarga ou desligamento adequado. Contagens muito altas correm o risco de corrupção de metadados e problemas de firmware.",
|
||||
"nvmePowerCycles": "Ciclos totais de ligar/desligar. A ciclagem frequente aumenta o desgaste do conector e do capacitor.",
|
||||
"nvmePowerOnHours": "Total de horas acumuladas em que o inversor esteve ligado desde a fabricação.",
|
||||
@@ -624,7 +624,7 @@
|
||||
"reallocatedSectorCount": "Setores defeituosos substituídos por setores sobressalentes do pool de reserva. Uma contagem crescente significa degradação da unidade.",
|
||||
"retiredBlockCount": "Blocos NAND retirados devido a desgaste ou falha (SSD). Semelhante à contagem de setores realocados para HDDs.",
|
||||
"reallocatedEventCount": "Número de operações de remapeamento realizadas. Cada evento significa que um setor defeituoso foi substituído.",
|
||||
"currentPendingSector": "Setores instáveis esperando para serem remapeados na próxima gravação. Eles podem ser resolvidos ou serem realocados permanentemente.",
|
||||
"currentPendingSector": "Setores instáveis esperando para serem remapeados na próxima gravação. Eles podem ser resolvidos ou serem realocados permanentemente.",
|
||||
"pendingSectors": "Setores esperando para serem remapeados. Eles podem ser resolvidos ou realocados.",
|
||||
"offlineUncorrectable": "Setores que falharam durante a verificação offline e não puderam ser corrigidos. Indica possível perda de dados.",
|
||||
"offlineUncorrectableSectorCount": "Setores incorrigíveis encontrados durante a verificação em segundo plano. Os dados sobre estes setores são perdidos.",
|
||||
@@ -667,7 +667,7 @@
|
||||
"endToEndError": "Corrupção de dados detectada entre o cache do controlador e a interface do host. Deve ser sempre zero.",
|
||||
"endToEndErrorDetectionCount": "Número de erros de paridade no caminho de dados. Diferente de zero indica problemas no controlador.",
|
||||
"wearLevelingCount": "Média de ciclos de apagamento por bloco NAND (SSD). VALOR mais baixo significa mais desgaste consumido.",
|
||||
"wearRangeDelta": "Diferença entre blocos mais usados e menos usados (SSD). Valores altos indicam desgaste irregular.",
|
||||
"wearRangeDelta": "Diferença entre blocos mais usados e menos usados (SSD). Valores altos indicam desgaste irregular.",
|
||||
"mediaWearoutIndicator": "Estimativa de vida útil restante do SSD Intel. Começa em 100 e diminui para 0 conforme a resistência é consumida.",
|
||||
"ssdLifeLeft": "Porcentagem estimada de vida útil restante do SSD com base no desgaste da NAND.",
|
||||
"percentLifetimeRemain": "Porcentagem estimada de vida útil restante. 100 significa novo; 0 significa fim da vida útil nominal.",
|
||||
@@ -744,7 +744,7 @@
|
||||
"nvmeWarningTitle": "Aviso crítico NVMe ativo (0x{value})",
|
||||
"nvmeWarningText": "O controlador NVMe gerou um alerta. Faça backup dos dados imediatamente e investigue mais a fundo.",
|
||||
"nvmeMediaTitle": "Erros de mídia NVMe detectados ({count})",
|
||||
"nvmeMediaText": "Erros irrecuperáveis de flash NAND indicam danos físicos. Faça backup dos dados e planeje a substituição.",
|
||||
"nvmeMediaText": "Erros irrecuperáveis de flash NAND indicam danos físicos. Faça backup dos dados e planeje a substituição.",
|
||||
"unsafeTitle": "Contagem alta de desligamentos inseguros ({count})",
|
||||
"unsafeText": "Perdas frequentes de energia aumentam o risco de corrupção do firmware. Garanta energia estável ou use um UPS.",
|
||||
"seagateTitle": "Seagate Raw_Read_Error_Rate - Comportamento normal",
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"Quinta-feira",
|
||||
"Sexta-feira",
|
||||
"Sábado"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "execução ignorada",
|
||||
"reasonStoppedContainer": "O contêiner está parado; a atualização agendada foi ignorada.",
|
||||
"reasonStoppedContainerHistorical": "O contêiner estava parado no horário da atualização agendada."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "cron do host detectado",
|
||||
@@ -1768,7 +1771,7 @@
|
||||
},
|
||||
"healthMonitor": {
|
||||
"title": "Monitor de Saúde",
|
||||
"description": "Configure por quanto tempo os alertas dispensados permanecem ocultos para cada categoria. As alterações se aplicam a alertas ignorados existentes e futuros.",
|
||||
"description": "Configure por quanto tempo os alertas dispensados permanecem ocultos para cada categoria. As alterações se aplicam a alertas ignorados existentes e futuros.",
|
||||
"category": "Categoria",
|
||||
"suppressionDuration": "Duração da Supressão",
|
||||
"hours": "Horas",
|
||||
@@ -1778,7 +1781,7 @@
|
||||
"footerNote": "Essas configurações se aplicam quando você descarta um aviso do Health Monitor. Alertas críticos de temperatura da CPU sempre aparecem para proteger seu hardware.",
|
||||
"activeSuppressions": "Supressões Ativas",
|
||||
"activeSuppressionsDescription": "Alertas que você ocultou do Health Monitor. As demissões permanentes só podem ser revertidas aqui. A edição requer o Health Monitor",
|
||||
"noActiveSuppressions": "Sem supressões ativas. Os alertas dispensados do Health Monitor aparecerão aqui.",
|
||||
"noActiveSuppressions": "Sem supressões ativas. Os alertas dispensados do Health Monitor aparecerão aqui.",
|
||||
"permanent": "Permanente",
|
||||
"daysRemaining": "{count}d restantes",
|
||||
"hoursRemaining": "{count}h restantes",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Habilite notificações para receber alertas de sistema, integridade e segurança por meio dos canais configurados.",
|
||||
"notificationLanguage": "Idioma de notificação",
|
||||
"selectNotificationLanguage": "Selecione o idioma de notificação",
|
||||
"notificationLanguageHint": "Usado para notificações determinísticas de tempo de execução, mesmo quando a IA está desabilitada."
|
||||
"notificationLanguageHint": "Usado para notificações determinísticas de tempo de execução, mesmo quando a IA está desabilitada.",
|
||||
"appriseServiceHelp": "Configuração do Slack e do Matrix",
|
||||
"appriseSlackSteps": "Crie um webhook de entrada na sua aplicação Slack para o canal de destino e cole o seu URL HTTPS completo no campo URL do Apprise. Não é necessária qualquer conversão.",
|
||||
"appriseSlackDocs": "Formatos de URL e configuração do Slack",
|
||||
"appriseMatrixSteps": "Utilize uma conta de notificações que possa publicar na sala. Substitua o utilizador, a palavra-passe, o homeserver e o ID completo da sala do exemplo; codifique os caracteres especiais das credenciais para URL. O esquema matrixs usa HTTPS. Consulte a documentação sobre o suporte de tokens, SSO e salas cifradas na versão do Apprise instalada.",
|
||||
"appriseMatrixDocs": "Formatos de URL e configuração do Matrix",
|
||||
"appriseServiceFinish": "Ative o Apprise, introduza o seu URL, escolha as categorias de notificação ou os eventos individuais, guarde e utilize Enviar teste. Estes exemplos não alteram o URL guardado. Este canal do Apprise tem um destino; utilize a API do Apprise para vários serviços em simultâneo."
|
||||
},
|
||||
"ai": {
|
||||
"title": "Aprimoramento de IA",
|
||||
@@ -3564,7 +3573,7 @@
|
||||
"hour": "Passada 1h",
|
||||
"day": "Passadas 24 horas",
|
||||
"week": "Passado 7 dias",
|
||||
"month": "Passados 30 dias",
|
||||
"month": "Passados 30 dias",
|
||||
"year": "Último 1 ano"
|
||||
},
|
||||
"last": {
|
||||
@@ -4016,7 +4025,7 @@
|
||||
},
|
||||
"backends": {
|
||||
"borgDescription": "Repositório Borg para backups de host desduplicados.",
|
||||
"borgDescriptionTimerOnly": "Os destinos Borg são usados pelos temporizadores do Monitor, não pelos trabalhos PVE vzdump.",
|
||||
"borgDescriptionTimerOnly": "Os destinos Borg são usados pelos temporizadores do Monitor, não pelos trabalhos PVE vzdump.",
|
||||
"borgShortDescription": "Repositório Borg desduplicado",
|
||||
"local": "Local",
|
||||
"localDescription": "Pasta neste host ou em uma unidade USB montada.",
|
||||
@@ -4544,7 +4553,7 @@
|
||||
"customPickDescriptionMiddle": "através do",
|
||||
"destructiveTitle": "A restauração completa REMOVERÁ o seguinte (criado após o backup)",
|
||||
"noPathsMatch": "Nenhum caminho corresponde ao filtro.",
|
||||
"noRestorablePaths": "Este backup não contém caminhos restauráveis — apenas a restauração completa é significativa aqui.",
|
||||
"noRestorablePaths": "Este backup não contém caminhos restauráveis — apenas a restauração completa é significativa aqui.",
|
||||
"olderThanTargetKernel": "é mais antigo que o kernel alvo",
|
||||
"operatorConfigDescription": "As seguintes configurações criadas pelo operador serão mescladas no destino automaticamente, sem alterar os padrões vinculados ao kernel. É executado na restauração completa e personalizada.",
|
||||
"operatorConfigTitle": "Configuração do operador reaplicada por meio de mesclagem independente de kernel",
|
||||
@@ -4926,7 +4935,7 @@
|
||||
},
|
||||
"noIssues": "Nenhum problema detectado",
|
||||
"updateNow": "Atualizar agora",
|
||||
"dismissedItems": "Itens dispensados ({count})",
|
||||
"dismissedItems": "Itens dispensados ({count})",
|
||||
"permanent": "Permanente",
|
||||
"dismissed": "Dispensado",
|
||||
"wasStatus": "era {status}",
|
||||
|
||||
@@ -1288,6 +1288,9 @@
|
||||
"runFailed": "✗ zlyhalo",
|
||||
"runDeferred": "odložené z bezpečnostných dôvodov",
|
||||
"runSkipped": "nič nečaká",
|
||||
"runSkippedStatus": "spustenie bolo preskočené",
|
||||
"reasonStoppedContainer": "Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.",
|
||||
"reasonStoppedContainerHistorical": "Kontajner bol v čase plánovanej aktualizácie vypnutý.",
|
||||
"releaseDelaySummary": "odklad {days} deň/dní",
|
||||
"releaseDelayLabel": "Počkať po novej verzii aplikácie",
|
||||
"releaseDelayNone": "Bez čakacej doby",
|
||||
@@ -2107,7 +2110,13 @@
|
||||
"inactiveFooter": "Zapnite notifikácie a dostávajte upozornenia o systéme, stave a bezpečnosti cez nastavené kanály.",
|
||||
"notificationLanguage": "Jazyk notifikácií",
|
||||
"selectNotificationLanguage": "Vyberte jazyk notifikácií",
|
||||
"notificationLanguageHint": "Používa sa pre spoľahlivé runtime notifikácie aj vtedy, keď je AI vypnutá."
|
||||
"notificationLanguageHint": "Používa sa pre spoľahlivé runtime notifikácie aj vtedy, keď je AI vypnutá.",
|
||||
"appriseServiceHelp": "Nastavenie Slack a Matrix",
|
||||
"appriseSlackSteps": "V aplikácii Slack vytvorte prichádzajúci webhook pre cieľový kanál a vložte jeho úplnú HTTPS URL do poľa URL Apprise. Nie je potrebný žiadny prevod.",
|
||||
"appriseSlackDocs": "Formáty URL a nastavenie Slack",
|
||||
"appriseMatrixSteps": "Použite účet pre oznámenia, ktorý môže odosielať správy do miestnosti. Nahraďte vzorového používateľa, heslo, domovský server a úplné ID miestnosti; špeciálne znaky v prihlasovacích údajoch zakódujte pre URL. Schéma matrixs používa HTTPS. Podporu tokenov, SSO a šifrovaných miestností v nainštalovanej verzii Apprise nájdete v dokumentácii.",
|
||||
"appriseMatrixDocs": "Formáty URL a nastavenie Matrix",
|
||||
"appriseServiceFinish": "Povoľte Apprise, zadajte svoju URL, vyberte kategórie oznámení alebo jednotlivé udalosti, uložte a potom použite Odoslať test. Tieto príklady nemenia uloženú URL. Tento kanál Apprise má jeden cieľ; pre viac služieb naraz použite API Apprise."
|
||||
},
|
||||
"ai": {
|
||||
"title": "AI vylepšenie",
|
||||
|
||||
@@ -1302,7 +1302,10 @@
|
||||
"torsdag",
|
||||
"fredag",
|
||||
"lördag"
|
||||
]
|
||||
],
|
||||
"runSkippedStatus": "körning överhoppad",
|
||||
"reasonStoppedContainer": "Behållaren är stoppad; den schemalagda uppdateringen hoppades över.",
|
||||
"reasonStoppedContainerHistorical": "Behållaren stoppades vid den schemalagda uppdateringstiden."
|
||||
},
|
||||
"cronChip": {
|
||||
"detected": "host cron upptäckt",
|
||||
@@ -2108,7 +2111,13 @@
|
||||
"inactiveFooter": "Aktivera aviseringar för att ta emot system-, hälso- och säkerhetsvarningar via de konfigurerade kanalerna.",
|
||||
"notificationLanguage": "Aviseringsspråk",
|
||||
"selectNotificationLanguage": "Välj språk för meddelanden",
|
||||
"notificationLanguageHint": "Används för deterministiska körtidsmeddelanden även när AI är inaktiverat."
|
||||
"notificationLanguageHint": "Används för deterministiska körtidsmeddelanden även när AI är inaktiverat.",
|
||||
"appriseServiceHelp": "Konfiguration av Slack och Matrix",
|
||||
"appriseSlackSteps": "Skapa en inkommande webhook i din Slack-app för målkanalen och klistra sedan in dess fullständiga HTTPS-URL i fältet Apprise-URL. Ingen omvandling behövs.",
|
||||
"appriseSlackDocs": "URL-format och konfiguration för Slack",
|
||||
"appriseMatrixSteps": "Använd ett aviseringskonto som får skicka meddelanden till rummet. Ersätt exemplets användare, lösenord, hemserver och fullständiga rums-ID; URL-koda specialtecken i inloggningsuppgifterna. Schemat matrixs använder HTTPS. Se dokumentationen för stöd för token, SSO och krypterade rum i din installerade Apprise-version.",
|
||||
"appriseMatrixDocs": "URL-format och konfiguration för Matrix",
|
||||
"appriseServiceFinish": "Aktivera Apprise, ange din URL, välj aviseringskategorier eller enskilda händelser, spara och använd sedan Skicka test. Dessa exempel ändrar inte din sparade URL. Denna Apprise-kanal har ett mål; använd Apprise-API för flera tjänster samtidigt."
|
||||
},
|
||||
"ai": {
|
||||
"title": "AI-förbättring",
|
||||
|
||||
@@ -35,7 +35,7 @@ TOOL_METADATA = {
|
||||
'system_utils': {'name': 'System Utilities', 'function': 'install_system_utils', 'version': '1.0'},
|
||||
'network_optimization': {'name': 'Network Optimizations', 'function': 'apply_network_optimizations', 'version': '1.0'},
|
||||
'bashrc_custom': {'name': 'Bashrc Customization', 'function': 'customize_bashrc', 'version': '1.0'},
|
||||
'figurine': {'name': 'Figurine', 'function': 'configure_figurine', 'version': '1.0'},
|
||||
'figurine': {'name': 'Figurine', 'function': 'configure_figurine', 'version': '1.2'},
|
||||
'fastfetch': {'name': 'Fastfetch', 'function': 'configure_fastfetch', 'version': '1.0'},
|
||||
'log2ram': {'name': 'Log2ram (SSD Protection)', 'function': 'configure_log2ram', 'version': '1.0'},
|
||||
'zfs_autotrim': {'name': 'ZFS Autotrim', 'function': 'enable_zfs_autotrim', 'version': '1.0'},
|
||||
|
||||
@@ -22245,6 +22245,7 @@ def api_proxmenux_self_update_status():
|
||||
# so scheduled and manual applies cannot overlap.
|
||||
|
||||
_APPLY_UPDATES_SCRIPT = _LXC_APPLY_UPDATES_SCRIPT
|
||||
_SCHEDULED_STOPPED_EXIT = 9
|
||||
_DOCKER_ENGINE_INTEGRATED_COMMAND = (
|
||||
'python3 /usr/local/share/proxmenux/monitor-app/usr/bin/'
|
||||
'update_docker_engine.py --vmid "$VMID"'
|
||||
@@ -22286,6 +22287,23 @@ def _append_lxc_update_log(path: str | None, text: str) -> None:
|
||||
print(f'[ProxMenux] scheduler: could not append update log: {exc}', flush=True)
|
||||
|
||||
|
||||
def _scheduled_runner_reported_stopped(result, log_path: str | None, marker: str) -> bool:
|
||||
"""Return true only for the scheduler's own pre-start stopped marker."""
|
||||
if result.returncode != _SCHEDULED_STOPPED_EXIT or not marker:
|
||||
return False
|
||||
if log_path:
|
||||
try:
|
||||
with open(log_path, 'rb') as stream:
|
||||
stream.seek(0, os.SEEK_END)
|
||||
stream.seek(max(0, stream.tell() - 4096))
|
||||
output = stream.read().decode('utf-8', errors='replace')
|
||||
except OSError:
|
||||
return False
|
||||
else:
|
||||
output = (result.stdout or '') + (result.stderr or '')
|
||||
return marker in output
|
||||
|
||||
|
||||
def _prune_lxc_update_logs(vmid: int) -> None:
|
||||
try:
|
||||
candidates = sorted(
|
||||
@@ -22679,8 +22697,10 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
requested_targets = _normalise_schedule_targets(sched)
|
||||
targets = list(requested_targets)
|
||||
before = _lxc_update_snapshot(vmid)
|
||||
requested_target = sched.get("target") or "both"
|
||||
deferred_targets: list[str] = []
|
||||
reasons: list[str] = []
|
||||
reason_code: str | None = None
|
||||
reboot_required: bool | None = None
|
||||
reboot_packages: list[str] = []
|
||||
reboot_check_error: str | None = None
|
||||
@@ -22732,6 +22752,7 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
'status': status,
|
||||
'target': actual_target,
|
||||
'reason': reason,
|
||||
'reason_code': reason_code,
|
||||
'run_id': run_id,
|
||||
'requested_targets': requested_targets,
|
||||
'executed_targets': list(executed),
|
||||
@@ -22743,10 +22764,23 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
'finalization': finalization,
|
||||
}
|
||||
|
||||
requested_target = sched.get("target") or "both"
|
||||
if not originally_running:
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container is stopped; scheduled update was skipped')
|
||||
return finish('skipped', requested_target, [])
|
||||
|
||||
if requested_targets == ['oci_image']:
|
||||
# A container installed by OCI manager Apps is updated by replacing
|
||||
# its image, through the same flow as the OCI menu, unattended.
|
||||
# OCI updates have their own runner rather than apply_updates.sh.
|
||||
# Check once more immediately before handing control to it: a user
|
||||
# may have intentionally stopped the CT after the scheduler's first
|
||||
# observation, and the OCI transaction can start a replacement CT
|
||||
# while validating its new image.
|
||||
if _fast_guest_status(vmid, 'lxc') != 'running':
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container was stopped before scheduled update could begin')
|
||||
return finish('skipped', 'oci_image', [])
|
||||
command = ['bash', '/usr/local/share/proxmenux/scripts/oci/oci_manager_apps.sh',
|
||||
'manage', str(vmid), '--action', 'update', '--unattended']
|
||||
storage = (sched.get('backup_storage') or '').strip()
|
||||
@@ -22887,6 +22921,9 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
target = "both" if has_os_target and has_app_targets else ("os" if has_os_target else "app")
|
||||
env = dict(os.environ)
|
||||
env["VMID"] = str(vmid)
|
||||
env["EXECUTION_MODE"] = "scheduled"
|
||||
scheduled_stopped_marker = f"PROXMENUX_SCHEDULED_STOPPED:{run_id}"
|
||||
env["SCHEDULED_STOPPED_MARKER"] = scheduled_stopped_marker
|
||||
env["TARGET"] = target
|
||||
env["BACKUP"] = "1" if sched.get("backup") else "0"
|
||||
env["BACKUP_STORAGE"] = sched.get("backup_storage") or ""
|
||||
@@ -22952,6 +22989,10 @@ def _run_scheduled_update(vmid: int, sched: dict) -> dict:
|
||||
text=True,
|
||||
timeout=60 * 60,
|
||||
)
|
||||
if _scheduled_runner_reported_stopped(r, log_path, scheduled_stopped_marker):
|
||||
reason_code = 'stopped_container'
|
||||
reasons.append('container was stopped before scheduled update could begin')
|
||||
return finish('skipped', target, [])
|
||||
reboot_required, reboot_packages, reboot_check_error = (
|
||||
_inspect_lxc_reboot_requirement(
|
||||
vmid,
|
||||
@@ -23027,12 +23068,14 @@ def _scheduler_loop():
|
||||
status = outcome.get('status') or 'failure'
|
||||
actual_target = outcome.get('target') or 'both'
|
||||
reason = outcome.get('reason')
|
||||
reason_code = outcome.get('reason_code')
|
||||
try:
|
||||
lxc_apps.record_schedule_run(
|
||||
_vmid,
|
||||
status,
|
||||
actual_target,
|
||||
reason,
|
||||
reason_code=reason_code,
|
||||
log_name=outcome.get('log_name'),
|
||||
reboot_required=outcome.get('reboot_required'),
|
||||
reboot_packages=outcome.get('reboot_packages'),
|
||||
|
||||
@@ -94,6 +94,7 @@ _VALID_UPSTREAM_TYPES = ("github", "http_json", "docker_hub")
|
||||
# `*/N` step, and comma lists — that covers every preset the UI
|
||||
# exposes and the freeform "custom" text field.
|
||||
_VALID_SCHEDULE_TARGETS = ("os", "app", "both")
|
||||
_SCHEDULE_REASON_CODES = frozenset({"stopped_container"})
|
||||
_SCHEDULE_TARGET_ID_RE = re.compile(
|
||||
r"^(?:os|apps|oci_image|app:[A-Za-z0-9_-]{1,64}|docker-engine|docker-(?:compose|container):[A-Za-z0-9][A-Za-z0-9_.-]{0,127}|docker-unit:[a-f0-9]{20})$"
|
||||
)
|
||||
@@ -2081,8 +2082,28 @@ class _DockerNoRedirect(urllib.request.HTTPRedirectHandler):
|
||||
_docker_no_redirect_opener = urllib.request.build_opener(_DockerNoRedirect)
|
||||
|
||||
|
||||
def _registry_bearer_token(challenge: dict) -> tuple[Optional[str], Optional[str]]:
|
||||
"""Exchange a parsed ``WWW-Authenticate`` challenge for a pull token."""
|
||||
_REGISTRY_AUTH_FILE = "/etc/pve/priv/proxmenux/registry-auth.json"
|
||||
_DOCKER_HUB_API_HOSTS = {"docker.io", "index.docker.io", "registry-1.docker.io", "registry.hub.docker.com"}
|
||||
|
||||
|
||||
def _registry_saved_login(api_host: str) -> Optional[str]:
|
||||
"""The login saved in ProxMenux for a registry, as a Basic credential."""
|
||||
try:
|
||||
with open(_REGISTRY_AUTH_FILE, encoding="utf-8") as handle:
|
||||
auths = (json.load(handle) or {}).get("auths") or {}
|
||||
except (OSError, ValueError, AttributeError):
|
||||
return None
|
||||
host = (api_host or "").lower()
|
||||
for key in ([host, "docker.io"] if host in _DOCKER_HUB_API_HOSTS else [host]):
|
||||
entry = auths.get(key) if isinstance(auths, dict) else None
|
||||
if isinstance(entry, dict) and isinstance(entry.get("auth"), str) and entry["auth"]:
|
||||
return f"Basic {entry['auth']}"
|
||||
return None
|
||||
|
||||
|
||||
def _registry_bearer_token(challenge: dict, saved_login: Optional[str] = None) -> tuple[Optional[str], Optional[str]]:
|
||||
"""Exchange a parsed ``WWW-Authenticate`` challenge for a pull token,
|
||||
with the login saved for a private registry when there is one."""
|
||||
query = {
|
||||
key: challenge[key]
|
||||
for key in ("service", "scope") if challenge.get(key)
|
||||
@@ -2090,10 +2111,10 @@ def _registry_bearer_token(challenge: dict) -> tuple[Optional[str], Optional[str
|
||||
token_url = challenge["realm"]
|
||||
if query:
|
||||
token_url += ("&" if "?" in token_url else "?") + urllib.parse.urlencode(query)
|
||||
token_req = urllib.request.Request(
|
||||
token_url,
|
||||
headers={"User-Agent": "ProxMenux-Monitor", "Accept": "application/json"},
|
||||
)
|
||||
token_headers = {"User-Agent": "ProxMenux-Monitor", "Accept": "application/json"}
|
||||
if saved_login:
|
||||
token_headers["Authorization"] = saved_login
|
||||
token_req = urllib.request.Request(token_url, headers=token_headers)
|
||||
try:
|
||||
with urllib.request.urlopen(token_req, timeout=_docker_registry_timeout()) as response:
|
||||
body = response.read(65537)
|
||||
@@ -2160,13 +2181,18 @@ def _registry_request(url: str, headers: dict, method: str = "HEAD",
|
||||
if error:
|
||||
return None, None, token, error
|
||||
if status == 401:
|
||||
challenge = _parse_bearer_challenge((response_headers or {}).get("WWW-Authenticate", ""))
|
||||
if not challenge:
|
||||
authenticate = (response_headers or {}).get("WWW-Authenticate", "")
|
||||
saved_login = _registry_saved_login(urllib.parse.urlsplit(url).netloc)
|
||||
challenge = _parse_bearer_challenge(authenticate)
|
||||
if challenge:
|
||||
token, token_error = _registry_bearer_token(challenge, saved_login)
|
||||
if token_error:
|
||||
return None, None, None, token_error
|
||||
attempt_headers["Authorization"] = f"Bearer {token}"
|
||||
elif saved_login and authenticate.lower().startswith("basic") and url.startswith("https://"):
|
||||
attempt_headers["Authorization"] = saved_login
|
||||
else:
|
||||
return None, None, token, "registry authentication required"
|
||||
token, token_error = _registry_bearer_token(challenge)
|
||||
if token_error:
|
||||
return None, None, None, token_error
|
||||
attempt_headers["Authorization"] = f"Bearer {token}"
|
||||
response_headers, body, status, location, error = _registry_open(
|
||||
url, attempt_headers, method, max_bytes,
|
||||
)
|
||||
@@ -3918,6 +3944,7 @@ def record_schedule_run(
|
||||
target: str,
|
||||
reason: Optional[str] = None,
|
||||
*,
|
||||
reason_code: Optional[str] = None,
|
||||
log_name: Optional[str] = None,
|
||||
reboot_required: Optional[bool] = None,
|
||||
reboot_packages: Optional[list[str]] = None,
|
||||
@@ -3937,6 +3964,10 @@ def record_schedule_run(
|
||||
sidecar["schedule"]["last_run_reason"] = str(reason)[:300]
|
||||
else:
|
||||
sidecar["schedule"].pop("last_run_reason", None)
|
||||
if reason_code in _SCHEDULE_REASON_CODES:
|
||||
sidecar["schedule"]["last_run_reason_code"] = reason_code
|
||||
else:
|
||||
sidecar["schedule"].pop("last_run_reason_code", None)
|
||||
if log_name:
|
||||
sidecar["schedule"]["last_run_log"] = os.path.basename(str(log_name))[:220]
|
||||
else:
|
||||
|
||||
@@ -1564,7 +1564,7 @@ class AppriseChannel(NotificationChannel):
|
||||
return apprise_mod.NotifyType.FAILURE
|
||||
if sev == 'WARNING':
|
||||
return apprise_mod.NotifyType.WARNING
|
||||
if sev == 'SUCCESS':
|
||||
if sev in ('SUCCESS', 'OK'):
|
||||
return apprise_mod.NotifyType.SUCCESS
|
||||
return apprise_mod.NotifyType.INFO
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ class ScheduledUpdateRecordTests(unittest.TestCase):
|
||||
self.vmid,
|
||||
'success',
|
||||
'both',
|
||||
reason='container is stopped; scheduled update was skipped',
|
||||
reason_code='stopped_container',
|
||||
log_name='../9911-scheduled-' + ('a' * 32) + '.log',
|
||||
reboot_required=True,
|
||||
reboot_packages=['linux-image-amd64', 'libc6'],
|
||||
@@ -43,11 +45,31 @@ class ScheduledUpdateRecordTests(unittest.TestCase):
|
||||
'9911-scheduled-' + ('a' * 32) + '.log',
|
||||
)
|
||||
self.assertTrue(schedule['last_run_reboot_required'])
|
||||
self.assertEqual(schedule['last_run_reason_code'], 'stopped_container')
|
||||
self.assertEqual(
|
||||
schedule['last_run_reboot_packages'],
|
||||
['linux-image-amd64', 'libc6'],
|
||||
)
|
||||
|
||||
def test_record_rejects_unknown_reason_code_and_clears_the_previous_one(self):
|
||||
self.assertTrue(lxc_apps.record_schedule_run(
|
||||
self.vmid,
|
||||
'skipped',
|
||||
'os',
|
||||
reason='container is stopped; scheduled update was skipped',
|
||||
reason_code='stopped_container',
|
||||
))
|
||||
self.assertTrue(lxc_apps.record_schedule_run(
|
||||
self.vmid,
|
||||
'failure',
|
||||
'os',
|
||||
reason='update runner exited with code 9',
|
||||
reason_code='untrusted_value',
|
||||
))
|
||||
schedule = lxc_apps._read_sidecar(self.vmid)['schedule']
|
||||
self.assertEqual(schedule['last_run_reason'], 'update runner exited with code 9')
|
||||
self.assertNotIn('last_run_reason_code', schedule)
|
||||
|
||||
def test_lifecycle_clear_preserves_run_and_log(self):
|
||||
lxc_apps.record_schedule_run(
|
||||
self.vmid,
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
"""The update check of a private image uses the login saved in ProxMenux:
|
||||
it is sent to the token service the registry names, or to the registry
|
||||
itself when it asks for Basic authentication, and never anywhere else."""
|
||||
|
||||
import base64
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
import lxc_apps
|
||||
|
||||
CREDENTIAL = base64.b64encode(b"macrimi:ghp_secret").decode()
|
||||
MANIFEST = "https://ghcr.io/v2/macrimi/app/manifests/latest"
|
||||
|
||||
|
||||
class SavedLoginTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.folder = tempfile.TemporaryDirectory()
|
||||
self.auth_file = Path(self.folder.name) / "registry-auth.json"
|
||||
self.auth_file.write_text(json.dumps({"auths": {"ghcr.io": {"auth": CREDENTIAL},
|
||||
"docker.io": {"auth": CREDENTIAL},
|
||||
"registry.example.com:5000": {"auth": CREDENTIAL}}}))
|
||||
patcher = mock.patch.object(lxc_apps, "_REGISTRY_AUTH_FILE", str(self.auth_file))
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
self.addCleanup(self.folder.cleanup)
|
||||
|
||||
def test_the_login_is_found_by_registry_host(self):
|
||||
self.assertEqual(lxc_apps._registry_saved_login("ghcr.io"), f"Basic {CREDENTIAL}")
|
||||
self.assertEqual(lxc_apps._registry_saved_login("registry-1.docker.io"), f"Basic {CREDENTIAL}")
|
||||
self.assertEqual(lxc_apps._registry_saved_login("registry.example.com:5000"), f"Basic {CREDENTIAL}")
|
||||
self.assertIsNone(lxc_apps._registry_saved_login("quay.io"))
|
||||
|
||||
def test_without_the_file_nothing_is_sent(self):
|
||||
self.auth_file.unlink()
|
||||
self.assertIsNone(lxc_apps._registry_saved_login("ghcr.io"))
|
||||
|
||||
def test_a_bearer_challenge_asks_the_token_with_the_saved_login(self):
|
||||
challenge = 'Bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:macrimi/app:pull"'
|
||||
answers = [({"WWW-Authenticate": challenge}, b"", 401, None, None),
|
||||
({"Docker-Content-Digest": "sha256:abc"}, b"", 200, None, None)]
|
||||
sent = []
|
||||
|
||||
def token_service(request, timeout):
|
||||
sent.append(dict(request.header_items()))
|
||||
response = mock.MagicMock()
|
||||
response.__enter__.return_value.read.return_value = b'{"token": "pull-token"}'
|
||||
return response
|
||||
|
||||
with mock.patch.object(lxc_apps, "_registry_open", side_effect=answers) as registry, \
|
||||
mock.patch.object(lxc_apps.urllib.request, "urlopen", side_effect=token_service):
|
||||
headers, _body, token, error = lxc_apps._registry_request(MANIFEST, {"Accept": "*/*"})
|
||||
self.assertIsNone(error)
|
||||
self.assertEqual(token, "pull-token")
|
||||
self.assertEqual(sent[0]["Authorization"], f"Basic {CREDENTIAL}")
|
||||
self.assertEqual(registry.call_args_list[1].args[1]["Authorization"], "Bearer pull-token")
|
||||
|
||||
def test_a_basic_challenge_is_answered_with_the_saved_login(self):
|
||||
answers = [({"WWW-Authenticate": 'Basic realm="registry"'}, b"", 401, None, None),
|
||||
({"Docker-Content-Digest": "sha256:abc"}, b"", 200, None, None)]
|
||||
url = "https://registry.example.com:5000/v2/team/app/manifests/latest"
|
||||
with mock.patch.object(lxc_apps, "_registry_open", side_effect=answers) as registry:
|
||||
_headers, _body, _token, error = lxc_apps._registry_request(url, {"Accept": "*/*"})
|
||||
self.assertIsNone(error)
|
||||
self.assertEqual(registry.call_args_list[1].args[1]["Authorization"], f"Basic {CREDENTIAL}")
|
||||
|
||||
def test_a_basic_challenge_over_http_gets_no_login(self):
|
||||
answers = [({"WWW-Authenticate": 'Basic realm="registry"'}, b"", 401, None, None)]
|
||||
url = "http://registry.example.com:5000/v2/team/app/manifests/latest"
|
||||
with mock.patch.object(lxc_apps, "_registry_open", side_effect=answers) as registry:
|
||||
_headers, _body, _token, error = lxc_apps._registry_request(url, {"Accept": "*/*"})
|
||||
self.assertEqual(error, "registry authentication required")
|
||||
self.assertEqual(registry.call_count, 1)
|
||||
|
||||
def test_a_public_image_asks_its_token_without_a_login(self):
|
||||
challenge = 'Bearer realm="https://auth.example.org/token",service="example",scope="repository:x:pull"'
|
||||
answers = [({"WWW-Authenticate": challenge}, b"", 401, None, None),
|
||||
({"Docker-Content-Digest": "sha256:abc"}, b"", 200, None, None)]
|
||||
sent = []
|
||||
|
||||
def token_service(request, timeout):
|
||||
sent.append(dict(request.header_items()))
|
||||
response = mock.MagicMock()
|
||||
response.__enter__.return_value.read.return_value = b'{"token": "t"}'
|
||||
return response
|
||||
|
||||
with mock.patch.object(lxc_apps, "_registry_open", side_effect=answers), \
|
||||
mock.patch.object(lxc_apps.urllib.request, "urlopen", side_effect=token_service):
|
||||
lxc_apps._registry_request("https://quay.io/v2/x/manifests/latest", {})
|
||||
self.assertNotIn("Authorization", sent[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+14
-1
@@ -818,7 +818,7 @@ Note that the dev server has no Flask backend on the same host by default: the a
|
||||
|
||||
### Testing
|
||||
|
||||
#### Offline i18n script tests
|
||||
#### Offline script regressions (including i18n)
|
||||
|
||||
From the repository root, run the complete script suite:
|
||||
|
||||
@@ -836,6 +836,14 @@ It does not launch React or require `npm install`, `pip install`, a Proxmox host
|
||||
API keys, or a translation provider. Generator tests use isolated temporary
|
||||
catalogs and fake/forbidden providers; repository catalogs are not regenerated.
|
||||
|
||||
The command-description recovery regression first completes disposable copies
|
||||
of the shipped catalogs with the real generator and a deterministic offline
|
||||
provider, then requires a second run to make zero provider calls and zero
|
||||
writes. It checks that all existing nonempty translations and the frozen
|
||||
command-description arrays survive unchanged. A synthetic EN-only feature tests
|
||||
new nested strings, arrays, placeholders and non-text values. New message keys
|
||||
do not need to be added to a test-specific translation seed list.
|
||||
|
||||
Scheduler fixtures discover every shipped `lang/*.json` cache and run the actual
|
||||
`translate` lookup at both empty-job consumers for PBS and local archive backends.
|
||||
They accept English fallback for missing/empty entries; complete translations are
|
||||
@@ -859,6 +867,11 @@ than silently skipping the consumer assertions. `.github/workflows/test-i18n.yml
|
||||
provisions Python and Node and runs this same command on relevant pull requests
|
||||
and main/develop pushes (or manually). It is separate from the translation
|
||||
publication workflow and has read-only repository permissions.
|
||||
Its Actions name is **Offline script regressions** because it also covers menus,
|
||||
downloads, scheduler behavior and other scripts. The `offline-i18n` check ID is
|
||||
retained for compatibility with existing branch protection rules; a failure of
|
||||
that check is not necessarily a translation failure. Read its failing test name
|
||||
and traceback before changing catalogs or translation-provider settings.
|
||||
|
||||
#### Qualified offline `tests/` CI lanes
|
||||
|
||||
|
||||
+96
-5
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Access Bridge für Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "Der Zugriff konnte nicht vollständig gewährt werden; die Anwendung kann möglicherweise nicht schreiben in:",
|
||||
"Access could not be granted; the application cannot write to:": "Der Zugriff konnte nicht gewährt werden; die Anwendung kann nicht schreiben an:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Zugriff von {registry} verweigert. Überprüfen Sie den Bildnamen und melden Sie sich über Registrierungskonten an.",
|
||||
"Access granted to the application on:": "Zugriff auf die Anwendung gewährt am:",
|
||||
"Access password of the web interface (optional)": "Zugangspasswort der Weboberfläche (optional)",
|
||||
"Access profile:": "Zugangsprofil:",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Fortschrittlich",
|
||||
"Advanced Diagnostics": "Erweiterte Diagnose",
|
||||
"Advanced Network Diagnostics": "Erweiterte Netzwerkdiagnose",
|
||||
"Advanced settings": "Erweiterte Einstellungen",
|
||||
"Advanced: every setting of the container": "Fortgeschritten: jede Einstellung des Containers",
|
||||
"Affected LXC containers": "Betroffene LXC-Container",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Nachdem Sie die GPU-Einrichtung abgeschlossen haben, starten Sie die VM manuell, wenn der Host bereit ist.",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Eine andere OCI operation verwendet die Instanzregistrierung. Warten Sie, bis es fertig ist und öffnen Sie dieses Menü erneut; kein Container wird geändert.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Ein weiterer OCI-Vorgang verwendet die Instanzregistrierung. Warten Sie, bis der Vorgang abgeschlossen ist.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Eine weitere OCI operation verwendet die Registry. Diese operation wurde nicht gestartet.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "Ein weiterer ProxMenux OCI-Vorgang wird ausgeführt. Versuchen Sie es erneut, wenn der Vorgang abgeschlossen ist.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Eine andere ZRAM-Konfiguration ist vorhanden oder konnte nicht überprüft werden.systemd-zram-generator wurde beibehalten",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Es existiert eine weitere ZRAM-Generatorkonfiguration; Ich weigere mich, es zu überschreiben:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Es gibt ein weiteres ZRAM-Swap-Setup; weigert sich, es zu ersetzen:",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Eine andere Instanz verwendet",
|
||||
"Another job that writes to the same storage still starts them.": "Ein anderer Job, der in denselben Speicher schreibt, startet sie weiterhin.",
|
||||
"Another node, typed by hand": "Ein weiterer Knoten, von Hand eingegeben",
|
||||
"Another registry account operation is running. Try again when it finishes.": "Ein anderer Registrierungskontovorgang wird ausgeführt. Versuchen Sie es erneut, wenn der Vorgang abgeschlossen ist.",
|
||||
"Another stack operation is pending": "Ein weiterer Stack operation steht aus",
|
||||
"Application": "Antragstellung",
|
||||
"Application registered on this host:": "Auf diesem Host registrierte Anwendung:",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Authentifizierung",
|
||||
"Authentication & Security": "Authentifizierung und Sicherheit",
|
||||
"Authentication Error": "Authentifizierungsfehler",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Authentication failed for {registry}. Check the account and token permissions.",
|
||||
"Authentication failed.": "Die Authentifizierung ist fehlgeschlagen.",
|
||||
"Authentication required:": "Authentifizierung erforderlich:",
|
||||
"Authentication:": "Authentifizierung:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Das Container-Home-Verzeichnis kann nicht aufgelöst werden:",
|
||||
"Cannot validate credentials - no shares available for testing.": "Anmeldeinformationen können nicht validiert werden – keine Freigaben zum Testen verfügbar.",
|
||||
"Cannot verify the reused disk:": "Kann die wiederverwendete Festplatte nicht überprüfen:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Das Bildarchiv kann nicht in {storage} geschrieben werden. Überprüfen Sie den Speicherzugriff und den Bereitstellungsstatus.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Fähigkeiten können nicht gehalten werden und alle gleichzeitig fallen gelassen werden",
|
||||
"Category": "Kategorie",
|
||||
"Caution: Maximum mode generates more heat.": "Achtung: Im Maximalmodus entsteht mehr Wärme.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Überprüfen Sie den Samba-Status",
|
||||
"Check VM disk/PCI slots": "Überprüfen Sie die VM-Festplatten-/PCI-Steckplätze",
|
||||
"Check VM passthrough settings": "Überprüfen Sie die VM-Passthrough-Einstellungen",
|
||||
"Check access to an image": "Überprüfen Sie den Zugriff auf ein Bild",
|
||||
"Check connectivity with another host": "Überprüfen Sie die Konnektivität mit einem anderen Host",
|
||||
"Check container mount points": "Überprüfen Sie die Container-Mount-Punkte",
|
||||
"Check if container is unprivileged:": "Überprüfen Sie, ob der Container nicht privilegiert ist:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Überprüfen Sie Folgendes:",
|
||||
"Check the error messages above for details.": "Weitere Informationen finden Sie in den obigen Fehlermeldungen.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Prüfen Sie die Image-Referenz und den Zugriff auf die Registry. Ist die Registry nicht erreichbar, versuchen Sie es später erneut. Eine private Registry benötigt Zugangsdaten, die noch nicht unterstützt werden.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Überprüfen Sie die Bildreferenz und den Registrierungszugriff. Wenn die Registrierung nicht verfügbar ist, versuchen Sie es später erneut. Für ein privates Image melden Sie sich über Registrierungskonten im Menü OCI an.",
|
||||
"Check the service status manually if needed.": "Überprüfen Sie den Servicestatus bei Bedarf manuell.",
|
||||
"Checking MOTD configuration...": "MOTD-Konfiguration wird überprüft...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Überprüfen des NVIDIA-Treiberstatus mit nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Überprüfen Sie den freien Speicherplatz in /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Überprüfen, ob es sich bei der Systemfestplatte um eine SSD oder M.2 handelt ...",
|
||||
"Checking if the server belongs to OVH...": "Es wird geprüft, ob der Server zu OVH gehört...",
|
||||
"Checking image access and metadata. Please wait...": "Bildzugriff und Metadaten prüfen. Bitte warten...",
|
||||
"Checking kernel headers and build tools...": "Kernel-Header und Build-Tools werden überprüft...",
|
||||
"Checking remaining interfaces": "Überprüfung der verbleibenden Schnittstellen",
|
||||
"Checking that the container keeps running...": "Überprüfen, ob der Container weiter läuft...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Wählen Sie den iperf3-Modus:",
|
||||
"Choose options to configure:": "Wählen Sie die zu konfigurierenden Optionen aus:",
|
||||
"Choose specific VMs/CTs": "Wählen Sie bestimmte VMs/CTs aus",
|
||||
"Choose storage for the downloaded image.": "Wählen Sie den Speicher für das heruntergeladene Bild.",
|
||||
"Choose the driver version for Coral M.2:": "Wählen Sie die Treiberversion für Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Wählen Sie das Dateisystem für die neue Partition:",
|
||||
"Choose the release channel to use:": "Wählen Sie den zu verwendenden Veröffentlichungskanal:",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "Ausstehende Wiederherstellung konnte nicht veröffentlicht werden. Die vorherige ausstehende Wiederherstellung wurde beibehalten.",
|
||||
"Could not push the key. Check the password and that": "Die Taste konnte nicht gedrückt werden. Überprüfen Sie das Passwort und so weiter",
|
||||
"Could not query the image registry": "Konnte die Bildregistrierung nicht abfragen",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "{registry} konnte nicht erreicht werden. Überprüfen Sie die Adresse, den DNS und den Netzwerkzugriff.",
|
||||
"Could not read SMART data from": "Die SMART-Daten konnten nicht gelesen werden",
|
||||
"Could not read VM configuration.": "Die VM-Konfiguration konnte nicht gelesen werden.",
|
||||
"Could not read the CUDA compute capability": "Konnte die CUDA-Rechenfähigkeit nicht lesen",
|
||||
"Could not read the NVIDIA driver version": "Konnte die NVIDIA Treiberversion nicht lesen",
|
||||
"Could not read the host firewall rules": "Die Host-Firewallregeln konnten nicht gelesen werden",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Das Bild von {registry} konnte nicht gelesen werden. Überprüfen Sie die Referenz und melden Sie sich über Registrierungskonten an.",
|
||||
"Could not read this job.": "Dieser Job konnte nicht gelesen werden.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "ZRAM-Seiten konnten nicht veröffentlicht werden; Das bestehende Profil bleibt aktiv",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Konnte nicht automatisch erneut bereitgestellt werden. Versuchen Sie es manuell oder überprüfen Sie die Anmeldeinformationen.",
|
||||
"Could not remove VM automatically. Run manually:": "VM konnte nicht automatisch entfernt werden. Manuell ausführen:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "ZRAM-Profil konnte nicht entfernt werden; Die Konfiguration wurde wiederhergestellt",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "ZRAM-Profil konnte nicht entfernt werden; Die Konfiguration wurde wiederhergestellt, aber der Swap konnte nicht neu gestartet werden",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Anmeldeinformationen für {registry} konnten nicht entfernt werden; Die Anmeldeinformationen der gespeicherten Datei wurden nicht geändert.",
|
||||
"Could not remove previous DKMS tree at": "Vorheriger DKMS-Baum konnte nicht entfernt werden",
|
||||
"Could not reserve a private network for the stack": "Konnte kein privates Netzwerk für den Stack reservieren",
|
||||
"Could not resolve the Compose user:": "Konnte den Compose-Benutzer nicht lösen:",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Die virtuelle VM-Anzeige konnte nicht auf vga: std gesetzt werden",
|
||||
"Could not set boot order for": "Die Startreihenfolge konnte nicht festgelegt werden",
|
||||
"Could not set the container entrypoint": "Konnte den Container-Einstiegspunkt nicht einstellen",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Anmeldung bei {registry} nicht möglich. Überprüfen Sie den Registrierungszugriff und die Token-Berechtigungen.",
|
||||
"Could not stage pending restore path:": "Ausstehender Wiederherstellungspfad konnte nicht bereitgestellt werden:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "Die Wiederherstellung konnte nicht bereitgestellt werden. Es war nichts Neues geplant.",
|
||||
"Could not stop LXC": "LXC konnte nicht gestoppt werden",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Privates Netzwerk wird erstellt...",
|
||||
"Creating the temporary data container": "Erstellen des temporären Datencontainers",
|
||||
"Creative & Design": "Kreativität und Design",
|
||||
"Credential helper": "Anmeldeinformations-Helfer",
|
||||
"Credential storage and access": "Speicherung und Zugriff von Anmeldeinformationen",
|
||||
"Credentials are correct": "Die Anmeldedaten sind korrekt",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Anmeldedaten gelöscht. jwt_secret und API-Token bleiben erhalten.",
|
||||
"Credentials file created securely.": "Anmeldeinformationsdatei sicher erstellt.",
|
||||
"Credentials file removed.": "Anmeldeinformationsdatei entfernt.",
|
||||
"Credentials file:": "Anmeldeinformationsdatei:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Anmeldeinformationsdatei:\n{path}\n\nIm Besitz von root; Verzeichnismodus 700 und Dateimodus 600.\nGrundlegende Anmeldeinformationen sind Base64-codiert und nicht verschlüsselt.\nAnmeldeinformationshelfer nutzen ihren eigenen Speicher.\n\nVerwenden Sie ein Zugriffstoken mit der Berechtigung zum Abrufen von Bildern.\nKonfigurieren Sie Anmeldeinformationen für jeden Knoten, der Bilder herunterlädt.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Anmeldeinformationsdatei:\n{path}\n\nIm Besitz von root; Verzeichnismodus 700 und Dateimodus 600.\nGrundlegende Anmeldeinformationen sind Base64-codiert und nicht verschlüsselt.\nAnmeldeinformationshelfer nutzen ihren eigenen Speicher.\n\nVerwenden Sie ein Zugriffstoken mit der Berechtigung zum Abrufen von Bildern.\nJeder Knoten des Clusters verwendet die hier gespeicherten Konten.",
|
||||
"Credentials validated successfully": "Anmeldeinformationen erfolgreich validiert",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Hostübergreifende Wiederherstellung: Gast-IDs im Backup überschneiden sich mit Live-IDs auf dem Ziel:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Kernelübergreifende Wiederherstellung – Kernel-gebundene Pfade werden zusammengeführt, nicht kopiert",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Standard-Login",
|
||||
"Default options": "Standardoptionen",
|
||||
"Default options read/write": "Standardoptionen Lesen/Schreiben",
|
||||
"Default settings": "Standardeinstellungen",
|
||||
"Default will be used:": "Standard wird verwendet:",
|
||||
"Default:": "Standard:",
|
||||
"Default: only what the application needs": "Standard: nur das, was die Anwendung braucht",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs ist ein Discord-Bot für die Anforderung von Medien über *arr Backends, geschrieben in Rust.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander ist ein kostenloser Cross-Plattform-Open-Source-Dateimanager mit zwei Panels nebeneinander. Es ist inspiriert von Total Commander und enthält einige neue Ideen.",
|
||||
"Download Spotify music with album art and metadata": "Laden Sie Spotify Musik mit Album Art und Metadaten herunter",
|
||||
"Download an image to template storage": "Laden Sie ein Bild in den Vorlagenspeicher herunter",
|
||||
"Download an oci-compose from an address": "Laden Sie ein oci-compose von einer Adresse herunter",
|
||||
"Download failed for all attempted URLs": "Der Download ist für alle versuchten URLs fehlgeschlagen",
|
||||
"Download its Compose file from an address": "Laden Sie die Compose-Datei von einer Adresse herunter",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Proxmology-Logo wird heruntergeladen...",
|
||||
"Downloading UUP converter...": "UUP-Konverter wird heruntergeladen...",
|
||||
"Downloading amdgpu_top": "Amdgpu_top wird heruntergeladen",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Herunterladen und Überprüfen des Bildes.\nDies kann einige Minuten dauern. Bitte warten...",
|
||||
"Downloading official installer...": "Offizielles Installationsprogramm wird heruntergeladen...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "Das Herunterladen bereits vorhandener verschlüsselter Backups von diesem Host schlägt fehl, es sei denn, Sie haben eine Kopie des aktuellen Schlüssels aufbewahrt.",
|
||||
"Downloading the image:": "Herunterladen des Bildes:",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Geben Sie den ZFS-Poolnamen für die ausgewählte Festplatte ein:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Geben Sie einen Namen für den Mount-Punkt ein (verwendet als /mnt/<Name>):",
|
||||
"Enter a name for the new virtual machine:": "Geben Sie einen Namen für die neue virtuelle Maschine ein:",
|
||||
"Enter a non-empty password or access token on a single line.": "Geben Sie in einer einzelnen Zeile ein nicht leeres Passwort oder Zugriffstoken ein.",
|
||||
"Enter a number, or write or paste a command:": "Geben Sie eine Zahl ein oder schreiben oder fügen Sie einen Befehl ein:",
|
||||
"Enter a systemd calendar event, e.g.:": "Geben Sie ein systemd-Kalenderereignis ein, z. B.:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Geben Sie eine nutzbare IPv4-Adresse mit ihrem Präfix ein, zum Beispiel",
|
||||
"Enter a valid registry username.": "Geben Sie einen gültigen Registrierungsbenutzernamen ein.",
|
||||
"Enter backup file (.zst):": "Geben Sie die Sicherungsdatei (.zst) ein:",
|
||||
"Enter backup path (.tar.zst):": "Geben Sie den Sicherungspfad (.tar.zst) ein:",
|
||||
"Enter backup path (.vma.zst):": "Geben Sie den Sicherungspfad (.vma.zst) ein:",
|
||||
@@ -2287,12 +2310,12 @@
|
||||
"Failed to download Proxmology logo": "Das Proxmology-Logo konnte nicht heruntergeladen werden",
|
||||
"Failed to download VirtIO driver ISO.": "Das Herunterladen der VirtIO-Treiber-ISO ist fehlgeschlagen.",
|
||||
"Failed to download amdgpu_top": "amdgpu_top konnte nicht heruntergeladen werden",
|
||||
"Failed to download loader image.": "Loader-Bild konnte nicht heruntergeladen werden.",
|
||||
"Failed to download loader image.": "Loader-Image konnte nicht heruntergeladen werden.",
|
||||
"Failed to edit /etc/fstab — remove the line manually.": "Die Bearbeitung von /etc/fstab ist fehlgeschlagen. Entfernen Sie die Zeile manuell.",
|
||||
"Failed to enable ZFS autotrim for pool:": "Die ZFS-Autotrim-Funktion für den Pool konnte nicht aktiviert werden:",
|
||||
"Failed to enable automatic time synchronization": "Die automatische Zeitsynchronisierung konnte nicht aktiviert werden",
|
||||
"Failed to extract OVA file:": "Die OVA-Datei konnte nicht extrahiert werden:",
|
||||
"Failed to extract a nonempty loader image.": "Das Extrahieren eines nicht leeren Loader-Bildes ist fehlgeschlagen.",
|
||||
"Failed to extract a nonempty loader image.": "Das Extrahieren eines nicht leeren Loader-Images ist fehlgeschlagen.",
|
||||
"Failed to extract package": "Paket konnte nicht extrahiert werden",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "Der Google Coral GPG-Schlüssel konnte nicht abgerufen werden. Überprüfen",
|
||||
"Failed to format disk as": "Formatierung des Datenträgers als fehlgeschlagen",
|
||||
@@ -2349,7 +2372,7 @@
|
||||
"Failed to retrieve Fastfetch download URL.": "Die Fastfetch-Download-URL konnte nicht abgerufen werden.",
|
||||
"Failed to retrieve loader release metadata.": "Metadaten zur Loader-Version konnten nicht abgerufen werden.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "Das Log2ram-Installationsprogramm konnte nicht ausgeführt werden. Überprüfen Sie /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "Loader-Bild konnte nicht gespeichert werden.",
|
||||
"Failed to save loader image.": "Loader-Image konnte nicht gespeichert werden.",
|
||||
"Failed to set VM description": "Die VM-Beschreibung konnte nicht festgelegt werden",
|
||||
"Failed to set timezone - keeping current settings": "Zeitzone konnte nicht festgelegt werden – aktuelle Einstellungen werden beibehalten",
|
||||
"Failed to start CT": "CT konnte nicht gestartet werden",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Hilfe und Informationen",
|
||||
"Help and Info Commands": "Hilfe- und Infobefehle",
|
||||
"Helper-Scripts logo applied": "Helper-Scripts-Logo angewendet",
|
||||
"Helper:": "Helfer:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Aus Sicherheitsgründen versteckt",
|
||||
"Hidden:": "Versteckt:",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Wenn Ihr DHCP eine statische Reservierung für den alten MAC hat, aktualisieren Sie diese.",
|
||||
"Image": "Bild",
|
||||
"Image Source Directory": "Bildquellenverzeichnis",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Bildzugriff bestätigt.\n\n{reference}\n\nArchitektur: {architecture}\nVersion: {version}\nDownloadgröße: {size}\nDigest: {digest}",
|
||||
"Image cache": "Bild-Cache",
|
||||
"Image compatibility restored:": "Bildkompatibilität wiederhergestellt:",
|
||||
"Image compatibility verified:": "Verifizierte Bildkompatibilität:",
|
||||
"Image directory:": "Bildverzeichnis:",
|
||||
"Image download failed:": "Bild-Download fehlgeschlagen:",
|
||||
"Image downloaded": "Bild heruntergeladen",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Bild heruntergeladen und überprüft.\n\n{reference}\n\nSpeicher: {storage}\nArchivgröße: {size}\nArchiv: {archive}\n\nEs wurde kein Container erstellt.\nProxMenux entfernt nicht verwendete zwischengespeicherte Bilder nach erfolgreichen Updates.",
|
||||
"Image file not found:": "Bilddatei nicht gefunden:",
|
||||
"Image imported:": "Bild importiert:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "Überprüfung der Bildintegrität fehlgeschlagen. Der teilweise Download wurde verworfen; versuchen Sie es erneut.",
|
||||
"Image integrity verified": "Überprüfung der Integrität des Bildes",
|
||||
"Image not allowed for the host monitor profile": "Bild nicht erlaubt für das Host-Monitor-Profil",
|
||||
"Image reference": "Bildreferenz",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Bildreferenz (z. B. ghcr.io/user/application:latest)",
|
||||
"Image selection was cancelled": "Die Image-Auswahl wurde abgebrochen",
|
||||
"Image that is not in the catalog": "Bild, das nicht im Katalog enthalten ist",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Installieren Sie Samba in CT:",
|
||||
"Install ZFS auto-snapshot": "ZFS-Auto-Snapshot installieren",
|
||||
"Install a version from the branch the kernel names.": "Installieren Sie eine Version aus dem Zweig der Kernelnamen.",
|
||||
"Install an image as a native LXC": "Installieren Sie ein Image als natives LXC",
|
||||
"Install an image that is not in the catalog": "Installieren Sie ein Bild, das sich nicht im Katalog befindet",
|
||||
"Install analysis tools": "Analysetools installieren",
|
||||
"Install and configure": "Installieren und konfigurieren",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "Die Installation ist abgeschlossen, aber die Treiber sind nicht geladen. Möglicherweise ist ein Neustart erforderlich.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Installation unvollständig. Diese Container und ihre Daten werden aufbewahrt:",
|
||||
"Installation log:": "Installationsprotokoll:",
|
||||
"Installation settings": "Installationseinstellungen",
|
||||
"Installation summary": "Zusammenfassung der Installation",
|
||||
"Installed": "Installiert",
|
||||
"Installed at:": "Installiert unter:",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Ungültiger Hostpfad:",
|
||||
"Invalid host-monitor firewall plan": "Ungültiger Host-Monitor-Firewallplan",
|
||||
"Invalid image probe descriptor": "Beschreibung der ungültigen Bildsonde",
|
||||
"Invalid image tag.": "Ungültiges Bild-Tag.",
|
||||
"Invalid input": "Ungültige Eingabe",
|
||||
"Invalid internal volume": "Ungültiges internes Volumen",
|
||||
"Invalid list:": "Ungültige Liste:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Anwendung ungültiger Suiten",
|
||||
"Invalid sysctl value:": "Ungültiger sysctl-Wert:",
|
||||
"Invalid template storage": "Speicherung ungültiger Vorlagen",
|
||||
"Invalid template storage name.": "Ungültiger Vorlagenspeichername.",
|
||||
"Invalid tmpfs options:": "Ungültige tmpfs Optionen:",
|
||||
"Invalid tmpfs path:": "Ungültiger tmpfs-Pfad:",
|
||||
"Invalid tmpfs size:": "Ungültige tmpfs Größe:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Log2RAM-Schreibvorgang alle geplant",
|
||||
"Log:": "Protokoll:",
|
||||
"Logged-in users": "Angemeldete Benutzer",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "Zeitüberschreitung bei der Anmeldung bei {registry}. Gespeicherte Anmeldeinformationen wurden nicht geändert.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "Zeitüberschreitung beim Abmelden von {registry}. Die Anmeldeinformationen der gespeicherten Datei wurden nicht geändert.",
|
||||
"Logrotate optimization completed": "Logrotate-Optimierung abgeschlossen",
|
||||
"Logrotate service restarted successfully": "Der Logrotate-Dienst wurde erfolgreich neu gestartet",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop ist ein leichter moderner Musikplayer, der hervorragend auf der GNOME-Desktopumgebung funktioniert.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Benutzerdefinierte Pfade verwalten (Ordner hinzufügen/entfernen)",
|
||||
"Manage installed OCI applications": "Verwalten installierter OCI-Anwendungen",
|
||||
"Manage local backup target": "Lokales Backup-Ziel verwalten",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Private Bildregister verwalten.\nGespeicherte Anmeldeinformationen ermöglichen ProxMenux den Zugriff auf Ihre privaten Bilder.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Registrierungskonten als Root auf dem Proxmox-Knoten verwalten.",
|
||||
"Managed disks must have backup enabled and a valid size": "Managed Disks müssen Backup aktiviert und eine gültige Größe haben",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Verwalten von Nginx Proxy-Hosts mit einer einfachen, leistungsstarken Benutzeroberfläche.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Manueller CLI-Leitfaden (Disk and Storage Manager)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Keine erreichbaren Samba-Server gefunden.",
|
||||
"No accessible exports found.": "Keine zugänglichen Exporte gefunden.",
|
||||
"No accessible shares found.": "Keine zugänglichen Freigaben gefunden.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Kein aktiver Proxmox-Speicher akzeptiert OCI-Vorlagenarchive.",
|
||||
"No active exports or showmount not available": "Keine aktiven Exporte oder Showmount nicht verfügbar",
|
||||
"No active session": "Keine aktive Sitzung",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Kein aktives Abonnement und kein nutzbares PVE-Repository. Im nicht interaktiven Modus können APT-Quellen nicht geändert werden. Konfigurieren Sie sie unter Knoten > Updates > Repositorys.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Nicht aktuell",
|
||||
"No recent Samba servers found.": "Keine aktuellen Samba-Server gefunden.",
|
||||
"No registered OCI containers are available for selection on this host.": "Auf diesem Host stehen keine registrierten OCI-Container zur Auswahl.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Bei {registry} wurde keine Registrierungs-API gefunden. Überprüfen Sie den Hostnamen und den Port.",
|
||||
"No restored OCI application is waiting to be recovered.": "Keine wiederhergestellte OCI-Anwendung wartet auf ihre Registrierung.",
|
||||
"No results": "Keine Ergebnisse",
|
||||
"No routing information found.": "Keine Routing-Informationen gefunden.",
|
||||
@@ -4297,7 +4335,9 @@
|
||||
"Not an OVH server, skipping RTM installation": "Kein OVH-Server, die RTM-Installation wird übersprungen",
|
||||
"Not currently mounted": "Derzeit nicht gemountet",
|
||||
"Not currently mounted — skipping umount.": "Derzeit nicht gemountet – umount wird übersprungen.",
|
||||
"Not declared": "Nicht deklariert",
|
||||
"Not enough free space for the backup": "Nicht genug freier Speicherplatz für das Backup",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Nicht genügend freier Speicherplatz auf {storage}. Geben Sie Speicherplatz frei oder wählen Sie einen anderen Speicher aus.",
|
||||
"Not found": "Nicht gefunden",
|
||||
"Not found in the OCI archive:": "Nicht im OCI-Archiv gefunden:",
|
||||
"Not imported:": "Nicht importiert:",
|
||||
@@ -4388,6 +4428,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Nur Intel/AMD DRM-, Coral- und USB-Knoten können automatisch übernommen werden",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Nur Intel/AMD DRM-, Coral-, NPU- und USB-Knoten können automatisch übernommen werden",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Nur ein Docker Swarm verwendet diese Einstellungen, so dass sie nicht angewendet werden:",
|
||||
"Only a full sha256 image digest is supported.": "Es wird nur ein vollständiger sha256-Image-Digest unterstützt.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Nur eine installierte eigenständige OCI-Instanz kann externe Änderungen übernehmen",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Es können nur gesicherte Proxmox-Volumes übernommen werden",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Konvertieren Sie nur dann in privilegiert, wenn dies für Ihren Anwendungsfall unbedingt erforderlich ist.",
|
||||
@@ -4541,6 +4582,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Passthrough funktioniert möglicherweise auch ohne ROM-Datei.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "Passthrough funktioniert möglicherweise, aber die Start-/Neustartzuverlässigkeit kann nicht garantiert werden.",
|
||||
"Password": "Passwort",
|
||||
"Password / access token (image pull permission)": "Passwort/Zugriffstoken (Bild-Pull-Berechtigung)",
|
||||
"Password Mismatch": "Passwortkonflikt",
|
||||
"Password cannot be empty.": "Das Passwort darf nicht leer sein.",
|
||||
"Password confirmation cannot be empty.": "Die Passwortbestätigung darf nicht leer sein.",
|
||||
@@ -4806,7 +4848,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux verbindet Verzeichnisse, nicht einzelne Dateien, so dass dieses Bild noch nicht installiert werden kann.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux kann vom Host aus Öffnungsberechtigungen für dieses NFS-Verzeichnis anwenden, sodass der Container lesen und schreiben kann:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux kann es mit offenen Berechtigungen erneut bereitstellen, sodass jeder LXC lesen und schreiben kann.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux kann dieses Image nicht automatisch installieren. Importieren Sie stattdessen die Compose-Datei.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux kann serverseitige NFS-Berechtigungen vom Host nicht überschreiben.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux konnte dieses Bild nicht übersetzen. Versuchen Sie, die Compose-Datei aus OCI manager Apps zu importieren.",
|
||||
"ProxMenux customizations removed from bashrc": "ProxMenux-Anpassungen aus bashrc entfernt",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux gibt einem Container nicht das System seines Hosts.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux installiert sie nicht. Die Installation fragt, wie man sich mit ihnen verbindet.",
|
||||
@@ -4927,6 +4971,7 @@
|
||||
"Reading SMART data...": "SMART-Daten werden gelesen...",
|
||||
"Reading SMART self-test log...": "SMART-Selbsttestprotokoll wird gelesen...",
|
||||
"Reading full SMART report...": "Vollständigen SMART-Bericht lesen...",
|
||||
"Reading image metadata. Please wait...": "Bildmetadaten lesen. Bitte warten...",
|
||||
"Real-time Performance Monitoring": "Echtzeit-Leistungsüberwachung",
|
||||
"Real-time bandwidth usage (press q to exit)": "Echtzeit-Bandbreitennutzung (zum Beenden q drücken)",
|
||||
"Real-time collaborative document editor": "Echtzeit-Collaborative Document Editor",
|
||||
@@ -5019,6 +5064,9 @@
|
||||
"Register mount path in Proxmox:": "Mount-Pfad in Proxmox registrieren:",
|
||||
"Registering disk as Proxmox storage...": "Festplatte als Proxmox-Speicher registrieren...",
|
||||
"Registering module with DKMS...": "Modul bei DKMS registrieren...",
|
||||
"Registry accounts": "Registrierungskonten",
|
||||
"Registry hostname": "Registry-Hostname",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Registrierung: {registry}\nKonto: {account}\nAuthentifizierung: {method}\n\nGespeicherte Anmeldeinformationen werden überprüft, wenn auf ein Bild zugegriffen wird.",
|
||||
"Reinstall / update Coral drivers": "Coral-Treiber neu installieren/aktualisieren",
|
||||
"Reinstall Fail2Ban": "Installieren Sie Fail2Ban neu",
|
||||
"Reinstall Lynis": "Lynis neu installieren",
|
||||
@@ -5090,8 +5138,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Entfernen Sie das veraltete systemd-boot-Metapaket",
|
||||
"Remove old repository files:": "Alte Repository-Dateien entfernen:",
|
||||
"Remove passthrough device from VM": "Entfernen Sie das Passthrough-Gerät von der VM",
|
||||
"Remove saved credentials": "Gespeicherte Anmeldeinformationen entfernen",
|
||||
"Remove subscription banner": "Abonnementbanner entfernen",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Anwendung entfernen? Seine Containerfestplatten werden gelöscht und können nur durch ein Backup wiederhergestellt werden.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Die gespeicherten Anmeldeinformationen für {registry} entfernen?\nLaufende Apps funktionieren weiterhin.",
|
||||
"Remove the unprivileged flag from configuration:": "Entfernen Sie das Unprivileged-Flag aus der Konfiguration:",
|
||||
"Remove unused packages and their config": "Entfernen Sie nicht verwendete Pakete und deren Konfiguration",
|
||||
"Remove: delete the application and its containers": "Entfernen: Löschen Sie die Anwendung und ihre Container",
|
||||
@@ -5413,6 +5463,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Speichern und klassifizieren Sie Artikel. Lesen Sie sie später. Frei.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Speichern Sie die Passphrase JETZT an einem sicheren Ort, bevor Sie fortfahren.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Dieses Borg-Ziel speichern, damit Sie die Details nicht erneut eingeben müssen?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Gespeicherte Anmeldeinformationen für {registry} wurden entfernt.\nAndere Skopeo/Docker-Anmeldedatendateien werden separat verwaltet.",
|
||||
"Saved record removed": "Gespeicherter Datensatz entfernt",
|
||||
"Saving changes...": "Änderungen werden gespeichert...",
|
||||
"Saving the new configuration": "Speichern der neuen Konfiguration",
|
||||
@@ -5793,9 +5844,11 @@
|
||||
"Shutdown timeout": "Zeitüberschreitung beim Herunterfahren",
|
||||
"SiYuan access code": "SiYuan-Zugangscode",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear bietet die Verwaltung von TV-Shows und / oder Anime, erkennt neue Episoden, verknüpft Downloader-Apps und mehr.",
|
||||
"Sign in to a registry": "Melden Sie sich bei einer Registrierung an",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Melden Sie sich beim Panel an und erstellen Sie in den Einstellungen einen Samba-Benutzer, bevor Sie ein Verzeichnis über SMB veröffentlichen.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal ist eine Messaging-App mit Privatsphäre im Kern. Es ist kostenlos und einfach zu bedienen, mit starker ende-zu-ende-verschlüsselung, die ihre kommunikation völlig privat hält.",
|
||||
"Signatures removed. Partition table preserved.": "Unterschriften entfernt. Partitionstabelle bleibt erhalten.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Bei {registry} als {username} angemeldet.\n\nAnmeldeinformationen werden für ProxMenux gespeichert.\nWählen Sie das Konto aus, um ein Image zu prüfen, herunterzuladen oder zu installieren.",
|
||||
"Simple and easy to use DDNS": "Einfach und einfach zu bedienen DDNS",
|
||||
"Single GPU Warning": "Warnung vor einer einzelnen GPU",
|
||||
"Single target found — selected automatically:": "Einzelnes Ziel gefunden – automatisch ausgewählt:",
|
||||
@@ -5821,6 +5874,8 @@
|
||||
"Skipping SR-IOV device": "SR-IOV-Gerät wird übersprungen",
|
||||
"Skipping installation.": "Installation überspringen.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Manuelle Patches überspringen – Feranick Fork unterstützt diesen Kernel bereits.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo ist nicht verfügbar. Stellen Sie die ProxMenux OCI-Abhängigkeiten wieder her und versuchen Sie es erneut.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo hat eine ungültige Anmeldeinformationsdatei zurückgegeben. Gespeicherte Anmeldeinformationen wurden nicht geändert.",
|
||||
"Sleek podcast downloader with GPodder sync": "Sleek Podcast Downloader mit GPodder Sync",
|
||||
"Smart restore plan — hardware compatibility check": "Smart Restore Plan – Hardware-Kompatibilitätsprüfung",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping verfolgt Ihre Netzwerklatenz. Für ein vollständiges Beispiel, was diese Anwendung in der Lage ist, besuchen Sie UCDavis.",
|
||||
@@ -6078,6 +6133,7 @@
|
||||
"TCP optimizations configuration completed": "Die Konfiguration der TCP-Optimierungen ist abgeschlossen",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "TCP-Optimierungen wurden zurückgesetzt (Standardeinstellungen werden beim nächsten Neustart wiederhergestellt)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "TCP-Port 5201 ist erreichbar (Firewall auf Server)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "TLS-Überprüfung für {registry} fehlgeschlagen. Installieren Sie die Registrierungs-CA in /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "TPM-Gerät zur VM hinzugefügt",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "Die Auswahl des TPM-Speichers ist fehlgeschlagen oder wurde abgebrochen. VM-Erstellung wurde abgebrochen.",
|
||||
"TROUBLESHOOTING:": "FEHLERBEHEBUNG:",
|
||||
@@ -6271,6 +6327,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "Die Konfiguration muss als root auf Proxmox VE ausgeführt werden",
|
||||
"The configuration of a new member changed after it was created": "Die Konfiguration eines neuen Mitglieds änderte sich, nachdem es erstellt wurde",
|
||||
"The configuration stopped because of an unexpected error": "Die Konfiguration wurde wegen eines unerwarteten Fehlers gestoppt",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "Der konfigurierte Anmeldeinformations-Helper konnte nicht verwendet werden. Überprüfen Sie die Installation und den Anmeldeinformationsspeicher.",
|
||||
"The console of the container could not be configured": "Die Konsole des Containers konnte nicht konfiguriert werden",
|
||||
"The consume/export volumes need at least 1 GB": "Verbrauchs-/Exportvolumen benötigen mindestens 1 GB",
|
||||
"The container could not be removed automatically:": "Der Container konnte nicht automatisch entfernt werden:",
|
||||
@@ -6309,6 +6366,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Die Container brauchen sie nicht mehr; ein Update lädt die neuen Versionen herunter, wenn es welche gibt.",
|
||||
"The containers were created from downloaded OCI images": "Die Container wurden aus heruntergeladenen OCI-Bildern erstellt",
|
||||
"The coordinated backup was modified": "Das koordinierte Backup wurde modifiziert",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "Die Anmeldeinformationsdatei wurde während dieses Vorgangs geändert. Versuchen Sie es erneut; es wurde nicht überschrieben.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "Der aktuelle Treiber wird vor der Installation der neuen Version vollständig deinstalliert. Weitermachen?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "Das aktuelle Bild des gespeicherten Kanals wird überprüft und heruntergeladen. Ressourcen, Pfade und GPU werden beibehalten. Der CT wird während des Austauschs gestoppt und zuerst ein natives Backup erstellt.",
|
||||
"The current record is missing for": "Der aktuelle Rekord fehlt für",
|
||||
@@ -6391,7 +6449,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "Das Host-Monitor-Firewall-Subnetz wurde geändert. Es wurde keine Firewall-Regel hinzugefügt",
|
||||
"The host-monitor web interface uses the host network.": "Die Host-Monitor-Webschnittstelle verwendet das Host-Netzwerk.",
|
||||
"The identity of a member was replaced": "Die Identität eines Mitglieds wurde ersetzt",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "Der Bild-Cache-Pfad ist unsicher. Überprüfen Sie den Vorlagenspeicher, bevor Sie es erneut versuchen.",
|
||||
"The image changes the user expected by the adapter": "Das Bild ändert den Benutzer, den der Adapter erwartet",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "Das Bild konnte nicht heruntergeladen oder überprüft werden. Überprüfen Sie die Registrierung und den Speicherzugriff und versuchen Sie es dann erneut.",
|
||||
"The image could not be read from its registry:": "Das Bild konnte nicht aus seiner Registry gelesen werden:",
|
||||
"The image declares data paths that are still stored in the rootfs": "Das Bild deklariert Datenpfade, die noch in den Rootfs gespeichert sind",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "Das Bild gewährte dem Anwendungsbenutzer keinen Zugriff auf die Geräte; Überprüfen Sie seine native Init. Host-Berechtigungen wurden nicht gelockert.",
|
||||
@@ -6404,6 +6464,8 @@
|
||||
"The image is in its registry, for one architecture.": "Das Bild befindet sich in seiner Registrierung, für eine Architektur.",
|
||||
"The image is in its registry.": "Das Bild befindet sich in seiner Registry.",
|
||||
"The image is in its registry:": "Das Bild befindet sich in seiner Registrierung:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "Die Integritätsüberprüfung des Bildmanifests ist fehlgeschlagen. Versuchen Sie es erneut oder wenden Sie sich an den Bildherausgeber.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "Das Bild oder Tag wurde auf {registry} nicht gefunden oder dieses Konto kann nicht darauf zugreifen. Überprüfen Sie die Referenz.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "Das Bild fordert NVIDIA an, aber der Host hat keinen funktionierenden NVIDIA-Treiber",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "Das Bild fordert die Deaktivierung eines Teils der AppArmor- oder seccomp-Beschränkung auf. Fahren Sie nur fort, wenn Sie dem Image vertrauen und dieses Risiko akzeptieren.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "Das Bild fordert die Deaktivierung eines Teils der AppArmor- oder seccomp-Beschränkung auf. Das Compose bietet eine optionale AppArmor- oder seccomp-Entspannung; es bleibt deaktiviert, es sei denn, der Benutzer wählt es aus. Fahren Sie nur fort, wenn Sie dem Image vertrauen und dieses Risiko akzeptieren.",
|
||||
@@ -6541,7 +6603,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "Die Aufzeichnung oder Diagnose konnte nicht abgeschlossen werden; kein Update wurde ausgeführt.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "Die Rückforderung war nicht abgeschlossen. Überprüfen Sie das Protokoll und wählen Sie erneut \"Wiederherstellen\" für diesen Container im OCI-Verwaltungsmenü.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "Die Wiederherstellung wurde nicht abgeschlossen. Prüfen Sie das Protokoll und wählen Sie für diesen Container im OCI-Verwaltungsmenü erneut \"{choice}\".",
|
||||
"The registry authentication file is invalid; it was not changed.": "Die Registrierungsauthentifizierungsdatei ist ungültig; es wurde nicht geändert.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "Die Registrierungsauthentifizierungsdatei muss Root mit Modus 600 gehören.",
|
||||
"The registry authentication file must have an absolute path.": "Die Registrierungsauthentifizierungsdatei muss einen absoluten Pfad haben.",
|
||||
"The registry authentication path cannot contain symbolic links.": "Der Registrierungsauthentifizierungspfad darf keine symbolischen Links enthalten.",
|
||||
"The registry authentication path has an unsafe parent directory.": "Der Registrierungsauthentifizierungspfad verfügt über ein unsicheres übergeordnetes Verzeichnis.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "Das Registrierungs-Anmeldeinformationsverzeichnis muss Root mit Modus 700 gehören.",
|
||||
"The registry did not return the saved image digest": "Die Registrierung hat den gespeicherten Image-Digest nicht zurückgegeben",
|
||||
"The registry returned incomplete or unsupported image metadata.": "Die Registrierung hat unvollständige oder nicht unterstützte Bildmetadaten zurückgegeben.",
|
||||
"The registry returned invalid or unsupported image metadata.": "Die Registrierung hat ungültige oder nicht unterstützte Bildmetadaten zurückgegeben.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "Die Fernbedienung existiert nicht; erstellen und autorisieren Sie sie zuerst in der WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "Der Remote-Installer muss als root auf Proxmox VE ausgeführt werden",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "Die Fernbedienung muss bereits im Rclone Web UI erstellt und autorisiert werden. Diese operation startet den CT neu und veröffentlicht zwei FUSE-Ansichten auf dem Host.",
|
||||
@@ -6700,6 +6770,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Diese GPU gilt als inkompatibel mit GPU-Passthrough zu einer VM in ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Diese NFS-Freigabe ist vollständig eingeschränkt – selbst der Host-Root kann nicht darauf schreiben.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Für diese VM sind zusätzliche Installationsschritte erforderlich. Weitere Informationen finden Sie im Installationshandbuch unter:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Dieses Konto ist für {registry}. Geben Sie ein Bild aus dieser Registrierung ein.",
|
||||
"This action will:": "Diese Aktion wird:",
|
||||
"This application cannot be recovered yet:": "Diese Anwendung kann noch nicht wiederhergestellt werden:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Diese Anwendung kann noch nicht wiederhergestellt werden; es wurde nichts geändert:",
|
||||
@@ -6731,8 +6802,10 @@
|
||||
"This explicitly marks the container as privileged": "Dadurch wird der Container explizit als privilegiert gekennzeichnet",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Diese Datei entscheidet, was gemountet wird und mit welchen Privilegien. Installieren Sie sie nur, wenn sie aus einer Quelle stammt, der Sie vertrauen.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Dies garantiert, dass Geräteknoten verfügbar sind, bevor die LXC-GPU-Konfiguration angewendet wird.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Diese Hostarchitektur wird vom Bildimporteur OCI nicht unterstützt.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Dieser Host hat kein aktives Abonnement. Zum Repository ohne Abonnement wechseln? Die unzugängliche Enterprise-PVE-Quelle wird deaktiviert. Falls vorhanden, werden Enterprise-Ceph-Quellen deaktiviert, ohne dass ein Ersatz-Ceph-Kanal ausgewählt wird. Konfigurieren Sie Ceph bei Bedarf separat.",
|
||||
"This image cannot be installed as it is described:": "Dieses Bild kann nicht wie beschrieben installiert werden:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Dieses Image verfügt über kein kompatibles Linux-Image für diesen Host ({architecture}).",
|
||||
"This image requires the host module": "Dieses Bild requires das Host-Modul",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Dieser Import lehnt diese Pfade ab, ohne zu prüfen, ob es Dateien oder Verzeichnisse sind.",
|
||||
"This installation will:": "Diese Installation wird:",
|
||||
@@ -6848,6 +6921,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Um die GPU wieder in LXC zu verwenden, führen Sie „GPU zu LXC hinzufügen“ über „GPUs“ und „Coral-TPU-Menü“ aus",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Um die VM problemlos nutzen zu können, muss der Host vor dem Start neu gestartet werden.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Um diese Freigabe von einem LXC aus zu verwenden, mounten Sie sie per Bind-Mount:",
|
||||
"Token": "Token",
|
||||
"Tool exit code:": "Tool-Exit-Code:",
|
||||
"Tool output:": "Werkzeugausgabe:",
|
||||
"Tools": "Werkzeuge",
|
||||
@@ -6992,6 +7066,7 @@
|
||||
"Unsafe private configuration path": "Unsicherer privater Konfigurationspfad",
|
||||
"Unsafe qBittorrent configuration path": "Unsicherer qBittorrent Konfigurationspfad",
|
||||
"Unsafe record": "Unsichere Aufzeichnung",
|
||||
"Unsafe registry credential lock.": "Unsichere Registrierungs-Anmeldeinformationssperre.",
|
||||
"Unsafe registry directory": "Unsicheres Registerverzeichnis",
|
||||
"Unsafe registry lock": "Unsichere Registrierungssperre",
|
||||
"Unsafe rootfs for the capture": "Unsichere Rootfs für den Fang",
|
||||
@@ -7004,6 +7079,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Nicht unterstütztes OCI-LXC AppArmor-Profil:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Nicht unterstütztes OCI-LXC seccomp Profil:",
|
||||
"Unsupported Terminal": "Nicht unterstütztes Terminal",
|
||||
"Unsupported architecture for Figurine:": "Nicht unterstützte Architektur für Figurine:",
|
||||
"Unsupported architecture:": "Nicht unterstützte Architektur:",
|
||||
"Unsupported backup compression": "Nicht unterstützte Backup-Komprimierung",
|
||||
"Unsupported credential pattern:": "Nicht unterstütztes credential-Muster:",
|
||||
@@ -7056,6 +7132,7 @@
|
||||
"Update cancelled by user": "Update vom Benutzer abgebrochen",
|
||||
"Update completed. Data kept.": "Update abgeschlossen. Vorgehaltene Daten.",
|
||||
"Update completed. Press Enter to continue...": "Aktualisierung abgeschlossen. Drücken Sie die Eingabetaste, um fortzufahren...",
|
||||
"Update credentials": "Anmeldeinformationen aktualisieren",
|
||||
"Update every container of the application": "Aktualisieren Sie jeden Container der Anwendung",
|
||||
"Update kernel to compatible version": "Aktualisieren Sie den Kernel auf eine kompatible Version",
|
||||
"Update now?": "Update jetzt?",
|
||||
@@ -7122,8 +7199,10 @@
|
||||
"Use a custom path": "Verwenden Sie einen benutzerdefinierten Pfad",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Verwenden Sie einen privilegierten LXC für NFS-Server-/Client-Workflows.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Verwenden Sie einen privilegierten LXC für Samba-Client/Server-Workflows.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Verwenden Sie einen Registrierungs-Hostnamen, zum Beispiel ghcr.io oder registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Verwenden Sie eine vorhandene private SSH-Schlüsseldatei auf diesem Host",
|
||||
"Use an existing keyfile": "Verwenden Sie eine vorhandene Schlüsseldatei",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Verwenden Sie eine Bildreferenz, zum Beispiel ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "So verwenden, wie es ist – Daten und Dateisystem beibehalten",
|
||||
"Use content types according to your use case.": "Verwenden Sie Inhaltstypen entsprechend Ihrem Anwendungsfall.",
|
||||
"Use default": "Standard verwenden",
|
||||
@@ -7163,6 +7242,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "Benutzerfreundliche WebUI für LLMs (früher Ollama WebUI)",
|
||||
"Username": "Benutzername",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Benutzername (z. B. root@pam oder user@pbs!token):",
|
||||
"Username / token": "Benutzername / Token",
|
||||
"Username and password": "Benutzername und Passwort",
|
||||
"Username and password will be cleared.": "Benutzername und Passwort werden gelöscht.",
|
||||
"Username cannot be empty.": "Der Benutzername darf nicht leer sein.",
|
||||
@@ -7262,6 +7342,7 @@
|
||||
"Verifying Ceph packages availability...": "Verfügbarkeit von Ceph-Paketen überprüfen...",
|
||||
"Verifying all utilities status": "Überprüfen des Status aller Dienstprogramme",
|
||||
"Verifying disk accessibility in CT": "Überprüfung der Festplattenzugänglichkeit im CT",
|
||||
"Verifying registry access. Please wait...": "Überprüfung des Registrierungszugriffs. Bitte warten...",
|
||||
"Verifying the backups...": "Überprüfung der Backups...",
|
||||
"Verifying the image integrity...": "Überprüfung der Bildintegrität...",
|
||||
"Version": "Version",
|
||||
@@ -7561,6 +7642,7 @@
|
||||
"assembling": "Montage",
|
||||
"automatically. Install it manually inside the container.": "automatisch. Installieren Sie es manuell im Container.",
|
||||
"automatically. Reboot LXC to fully release.": "automatisch. Starten Sie LXC neu, um es vollständig freizugeben.",
|
||||
"available": "Verfügbar",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "verfügbar für LXC-Bind-Mounts über „LXC Mount Manager“",
|
||||
"available in this same GPU and TPU menu.": "verfügbar im selben GPU- und TPU-Menü.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "Backup unter /etc/fstab.proxmenux.bak",
|
||||
@@ -7887,8 +7969,8 @@
|
||||
"qBittorrent: invalid login response or missing session cookie": "qBittorrent: ungültige Anmeldeantwort oder fehlendes Sitzungscookie",
|
||||
"raw USB disk — no filesystem (will be FORMATTED)": "Raw-USB-Festplatte – kein Dateisystem (wird FORMATTIERT)",
|
||||
"read-only": "Read-Only",
|
||||
"reboot-quick alias added": "reboot-quick-Alias hinzugefügt",
|
||||
"reboot-quick alias is already configured": "reboot-quick Alias ist bereits konfiguriert",
|
||||
"reboot-quick alias added": "reboot-quick-Alias hinzugefügt",
|
||||
"reboot-quick alias is already configured": "reboot-quick Alias ist bereits konfiguriert",
|
||||
"recognition": "Erkennung",
|
||||
"recognition only": "Nur Erkennung",
|
||||
"recommended": "empfohlen",
|
||||
@@ -7913,6 +7995,7 @@
|
||||
"runs in": "läuft",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "Jetzt sichere Pfade (Konfigurationen, Pakete, /etc, /root, ...)",
|
||||
"same MAC": "gleicher MAC",
|
||||
"saved": "Gespeichert",
|
||||
"seconds (default)": "Sekunden (Standard)",
|
||||
"see log:": "siehe Protokoll:",
|
||||
"selected by default": "Standardmäßig ausgewählt",
|
||||
@@ -8031,8 +8114,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot entfernt (vorhandene Snapshots bleiben im Pool erhalten)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "zpool-Befehl nicht gefunden. Installieren Sie zfsutils-linux und versuchen Sie es erneut.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool nicht gefunden. Installieren Sie zfsutils-linux und versuchen Sie es erneut.",
|
||||
"{count} saved account.": "{count} gespeichertes Konto.",
|
||||
"{count} saved accounts.": "{count} gespeicherte Konten.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} existiert bereits und gehört einem anderen Benutzer des Hosts, daher kann {app} nicht darauf schreiben.\n\nProxMenux kann Zugriffsregeln (ACL) zu diesem Verzeichnis, zu allem darin und zu dem, was später dort erstellt wird, für die Benutzer und Gruppen hinzufügen, unter denen {app} auf dem Host läuft (IDs {ids}). Der Eigentümer der Dateien ändert sich nicht, und was sie heute liest oder schreibt, tut dies weiterhin; der Eigentümer des Verzeichnisses erhält außerdem Zugriff auf die von {app} erstellten Dateien.\n\n{app} Zugriff auf dieses Verzeichnis gewähren?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} existiert bereits und gehört einem anderen Benutzer des Hosts, daher kann {app} nicht darauf schreiben.\n\nProxMenux kann eine Zugriffsregel (ACL) für die Identität hinzufügen, die {app} auf dem Host verwendet (UID {uid}).Nichts, was dort ist, ändert den Besitzer oder die Berechtigungen: Was auch immer diese Dateien heute liest oder schreibt, tut dies weiterhin, und der Besitzer des Verzeichnisses erhält auch Zugriff auf die Dateien, die {app} erstellt.\n\n{app} Zugriff auf dieses Verzeichnis gewähren?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} hat mit einfachem HTTP geantwortet. Verwenden Sie eine Registrierung mit HTTPS; Die TLS-Überprüfung bleibt aktiviert.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} hat nicht innerhalb von {timeout} Sekunden geantwortet. Versuchen Sie es später noch einmal.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "Bei {registry} handelt es sich um ratenbegrenzende Anfragen. Warten Sie eine Weile und versuchen Sie es erneut.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} hat den Zugriff auf dieses Bild verweigert:\n{reference}\n\nWenn das Bild privat ist, melden Sie sich mit einem Konto an, das es abrufen kann.\n\nJetzt anmelden?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} hat einen Serverfehler gemeldet. Versuchen Sie es später noch einmal.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} hat ungültige oder nicht unterstützte Bildmetadaten zurückgegeben.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "– Bei der vollständigen/benutzerdefinierten Wiederherstellung werden an den Kernel gebundene Pfade übersprungen",
|
||||
"— disk may be busy. Skipping fstab removal.": "— Die Festplatte ist möglicherweise ausgelastet. Überspringen der fstab-Entfernung.",
|
||||
"— restore proceeds as same-version (verified safe)": "– Die Wiederherstellung erfolgt wie bei derselben Version (als sicher verifiziert)",
|
||||
|
||||
+96
-5
@@ -190,6 +190,7 @@
|
||||
"Access bridge for Paperless": "Puente de acceso para Paperless",
|
||||
"Access bridge for Tandoor": "Puente de acceso para Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "No se pudo conceder el acceso por completo; puede que la aplicación no pueda escribir en:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "{registry} ha denegado el acceso. Comprueba el nombre de la imagen e inicia sesión desde Cuentas de registro.",
|
||||
"Access granted to the application on:": "Acceso concedido a la aplicación en:",
|
||||
"Access password of the web interface (optional)": "Contraseña de acceso a la interfaz web (opcional)",
|
||||
"Access profile:": "Perfil de acceso:",
|
||||
@@ -308,6 +309,7 @@
|
||||
"Advanced": "Avanzado",
|
||||
"Advanced Diagnostics": "Diagnóstico avanzado",
|
||||
"Advanced Network Diagnostics": "Diagnóstico de red avanzado",
|
||||
"Advanced settings": "Configuración avanzada",
|
||||
"Advanced: every setting of the container": "Avanzado: cada configuración del contenedor",
|
||||
"Affected LXC containers": "Contenedores LXC afectados",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Después de completar la configuración de la GPU, inicie la VM manualmente cuando el host esté listo.",
|
||||
@@ -326,7 +328,7 @@
|
||||
"After this LXC → VM switch, reboot the host so the new binding state is applied cleanly.": "Después de este cambio LXC → VM, reinicie el host para que el nuevo estado de enlace se aplique limpiamente.",
|
||||
"Airsonic Advanced web interface": "Interfaz web de Airsonic Advanced",
|
||||
"Airsonic-advanced is a free, web-based media streamer, providing ubiquitious access to your music. Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple players simultaneously, for instance to one player in your kitchen and another in your living room.": "Airsonic-advanced es un servidor de streaming multimedia gratuito y basado en web que da acceso a tu música desde cualquier lugar. Úsalo para compartir tu música con amigos o para escuchar la tuya en el trabajo. Puede transmitir a varios reproductores a la vez, por ejemplo a uno en la cocina y a otro en el salón.",
|
||||
"Aliases added to .bashrc": "Alias agregados a .bashrc",
|
||||
"Aliases added to .bashrc": "Alias agregados a .bashrc",
|
||||
"Alist Sync web interface": "Interfaz web de Alist Sync",
|
||||
"All": "Todos",
|
||||
"All Available Scripts": "Todos los scripts disponibles",
|
||||
@@ -399,6 +401,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Otra operación OCI está usando el registro de instancias. Espera a que termine y vuelve a abrir este menú; no se modifica ningún contenedor.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Otra operación OCI está usando el registro de instancias. Espera a que termine.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Otra operación OCI está utilizando el registro. Esta operación no se inició.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "Hay otra operación OCI de ProxMenux en curso. Inténtalo de nuevo cuando termine.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Existe otra configuración de ZRAM o no se pudo inspeccionar; se conserva systemd-zram-generator",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Existe otra configuración del generador de ZRAM; no se sobrescribe:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Existe otra configuración de swap con ZRAM; no se sustituye:",
|
||||
@@ -406,6 +409,7 @@
|
||||
"Another instance uses": "Otro caso utiliza",
|
||||
"Another job that writes to the same storage still starts them.": "Otro trabajo que escriba en el mismo almacenamiento los sigue lanzando.",
|
||||
"Another node, typed by hand": "Otro nodo, escrito a mano",
|
||||
"Another registry account operation is running. Try again when it finishes.": "Hay otra operación con las cuentas de registro en curso. Inténtalo de nuevo cuando termine.",
|
||||
"Another stack operation is pending": "Hay otra operación de pila pendiente",
|
||||
"Application": "Aplicación",
|
||||
"Application Specific": "Específico de la aplicación",
|
||||
@@ -500,6 +504,7 @@
|
||||
"Authentication": "Autenticación",
|
||||
"Authentication & Security": "Authentication & Security",
|
||||
"Authentication Error": "Error de autenticación",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "{registry} no ha aceptado la autenticación. Comprueba la cuenta y los permisos del token.",
|
||||
"Authentication failed.": "La autenticación falló.",
|
||||
"Authentication required:": "Se requiere autenticación:",
|
||||
"Authentication:": "Autenticación:",
|
||||
@@ -738,6 +743,7 @@
|
||||
"Cannot resolve the container home directory:": "No se puede resolver el directorio de inicio del contenedor:",
|
||||
"Cannot validate credentials - no shares available for testing.": "No se pueden validar las credenciales: no hay recursos compartidos disponibles para realizar pruebas.",
|
||||
"Cannot verify the reused disk:": "No se puede verificar el disco reutilizado:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "No se puede escribir el archivo de la imagen en {storage}. Comprueba el acceso al almacenamiento y que esté montado.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "No se pueden mantener las capacidades y todas se disminuyen al mismo tiempo",
|
||||
"Category": "Categoría",
|
||||
"Caution: Maximum mode generates more heat.": "Precaución: el modo máximo genera más calor.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Verificar el estado de Samba",
|
||||
"Check VM disk/PCI slots": "Verifique el disco VM/ranuras PCI",
|
||||
"Check VM passthrough settings": "Revise la configuración de passthrough de la VM",
|
||||
"Check access to an image": "Comprobar el acceso a una imagen",
|
||||
"Check connectivity with another host": "Verificar la conectividad con otro host",
|
||||
"Check container mount points": "Verifique los puntos de montaje del contenedor",
|
||||
"Check if container is unprivileged:": "Compruebe si el contenedor no tiene privilegios:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Comprueba que:",
|
||||
"Check the error messages above for details.": "Consulte los mensajes de error anteriores para obtener más detalles.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Comprueba la referencia de la imagen y el acceso al registro. Si el registro no está disponible, inténtalo más tarde. Un registro privado necesita credenciales, que todavía no se admiten.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Comprueba la referencia de la imagen y el acceso al registro. Si el registro no está disponible, inténtalo más tarde. Para una imagen privada, inicia sesión desde Cuentas de registro en el menú OCI.",
|
||||
"Check the service status manually if needed.": "Verifique el estado del servicio manualmente si es necesario.",
|
||||
"Checking MOTD configuration...": "Comprobando la configuración del MOTD...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Comprobar el estado del controlador NVIDIA con nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Comprobando espacio libre en /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Comprobando si el disco del sistema es SSD o M.2...",
|
||||
"Checking if the server belongs to OVH...": "Comprobando si el servidor pertenece a OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Comprobando el acceso a la imagen y sus metadatos. Espera...",
|
||||
"Checking kernel headers and build tools...": "Comprobando los encabezados del kernel y las herramientas de compilación...",
|
||||
"Checking remaining interfaces": "Comprobando las interfaces restantes",
|
||||
"Checking that the container keeps running...": "Comprobando que el contenedor sigue funcionando...",
|
||||
@@ -896,6 +905,7 @@
|
||||
"Choose iperf3 mode:": "Elige el modo iperf3:",
|
||||
"Choose options to configure:": "Elige opciones para configurar:",
|
||||
"Choose specific VMs/CTs": "Elegir VM/CT concretas",
|
||||
"Choose storage for the downloaded image.": "Elige el almacenamiento para la imagen descargada.",
|
||||
"Choose the driver version for Coral M.2:": "Elige la versión del controlador para Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Elige el sistema de archivos para la nueva partición:",
|
||||
"Choose the release channel to use:": "Elige el canal de release que quieres usar:",
|
||||
@@ -1362,17 +1372,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "No se pudo publicar la restauración pendiente. Se mantiene la anterior.",
|
||||
"Could not push the key. Check the password and that": "No se pudo presionar la tecla. Verifique la contraseña y eso",
|
||||
"Could not query the image registry": "No se puede consultar el registro de imágenes",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "No se pudo contactar con {registry}. Comprueba su dirección, el DNS y el acceso a la red.",
|
||||
"Could not read SMART data from": "No se pudieron leer los datos SMART de",
|
||||
"Could not read VM configuration.": "No se pudo leer la configuración de la VM.",
|
||||
"Could not read the CUDA compute capability": "No podía leer la capacidad de cálculo de CUDA",
|
||||
"Could not read the NVIDIA driver version": "No podía leer la versión del controlador NVIDIA",
|
||||
"Could not read the host firewall rules": "No se pudieron leer las reglas del cortafuegos del host",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "No se pudo leer la imagen de {registry}. Comprueba la referencia e inicia sesión desde Cuentas de registro.",
|
||||
"Could not read this job.": "No se pudo leer este trabajo.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "No se pudieron liberar las páginas de ZRAM; el perfil actual sigue activo",
|
||||
"Could not remount automatically. Try manually or check credentials.": "No se pudo volver a montar automáticamente. Pruebe manualmente o verifique las credenciales.",
|
||||
"Could not remove VM automatically. Run manually:": "No se pudo eliminar la VM automáticamente. Ejecutar manualmente:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "No se pudo eliminar el perfil de ZRAM; se restauró la configuración",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "No se pudo eliminar el perfil de ZRAM; se restauró la configuración, pero no se pudo reiniciar el swap",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "No se pudieron eliminar las credenciales de {registry}; las credenciales guardadas no han cambiado.",
|
||||
"Could not remove previous DKMS tree at": "No se pudo eliminar el árbol DKMS anterior en",
|
||||
"Could not reserve a private network for the stack": "No se pudo reservar una red privada para la pila",
|
||||
"Could not resolve the Compose user:": "No podía resolver el usuario de Compose:",
|
||||
@@ -1387,6 +1400,7 @@
|
||||
"Could not set VM virtual display to vga: std": "No se pudo configurar la pantalla virtual de VM en vga: estándar",
|
||||
"Could not set boot order for": "No se pudo establecer el orden de inicio para",
|
||||
"Could not set the container entrypoint": "No podía establecer el punto de entrada del contenedor",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "No se pudo iniciar sesión en {registry}. Comprueba el acceso al registro y los permisos del token.",
|
||||
"Could not stage pending restore path:": "No se pudo preparar la ruta de la restauración pendiente:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "No se pudo preparar la restauración pendiente. No se ha programado nada nuevo.",
|
||||
"Could not stop LXC": "No se pudo detener LXC",
|
||||
@@ -1473,11 +1487,15 @@
|
||||
"Creating the private network...": "Creando la red privada...",
|
||||
"Creating the temporary data container": "Creando el contenedor temporal para los datos",
|
||||
"Creative & Design": "Creative & Design",
|
||||
"Credential helper": "Asistente de credenciales",
|
||||
"Credential storage and access": "Dónde se guardan las credenciales",
|
||||
"Credentials are correct": "Las credenciales son correctas",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Credenciales borradas. Se conservan jwt_secret y los tokens de API.",
|
||||
"Credentials file created securely.": "Archivo de credenciales creado de forma segura.",
|
||||
"Credentials file removed.": "Archivo de credenciales eliminado.",
|
||||
"Credentials file:": "Archivo de credenciales:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Archivo de credenciales:\n{path}\n\nPropiedad de raíz;modo directorio 700 y modo archivo 600.\nLas credenciales básicas están codificadas en base64, no cifradas.\nLos asistentes de credenciales utilizan su propio almacenamiento.\n\nUtilice un token de acceso con permiso para extraer imágenes.\nConfigure las credenciales en cada nodo que descarga imágenes.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Fichero de credenciales:\n{path}\n\nPropiedad de root; carpeta con modo 700 y fichero con modo 600.\nLas credenciales básicas van en base64, no cifradas.\nLos asistentes de credenciales usan su propio almacén.\n\nUsa un token de acceso con permiso para descargar imágenes.\nTodos los nodos del clúster usan las cuentas guardadas aquí.",
|
||||
"Credentials validated successfully": "Credenciales validadas correctamente",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Restauración entre hosts: los ID de VM/CT del backup coinciden con ID activos en el destino:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Restauración entre kernels — rutas vinculadas al kernel fusionadas, no copiadas",
|
||||
@@ -1615,6 +1633,7 @@
|
||||
"Default login": "Acceso predeterminado",
|
||||
"Default options": "Opciones predeterminadas",
|
||||
"Default options read/write": "Opciones predeterminadas lectura/escritura",
|
||||
"Default settings": "Configuración por defecto",
|
||||
"Default will be used:": "Se utilizará el valor predeterminado:",
|
||||
"Default:": "Predeterminado:",
|
||||
"Default: only what the application needs": "Por defecto: solo lo que la aplicación necesita",
|
||||
@@ -1849,6 +1868,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs es un bot de Discord, escrito en Rust, para solicitar contenido a través de backends *arr.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander es un gestor de archivos gratuito, multiplataforma y de código abierto con dos paneles en paralelo. Se inspira en Total Commander y aporta algunas ideas nuevas.",
|
||||
"Download Spotify music with album art and metadata": "Descarga música de Spotify con carátulas y metadatos",
|
||||
"Download an image to template storage": "Descargar una imagen al almacenamiento de plantillas",
|
||||
"Download an oci-compose from an address": "Descargar un oci-compose desde una dirección",
|
||||
"Download failed for all attempted URLs": "La descarga falló en todos los intentos de URL",
|
||||
"Download its Compose file from an address": "Descargar su archivo Compose desde una dirección",
|
||||
@@ -1864,6 +1884,7 @@
|
||||
"Downloading Proxmology logo...": "Descargando el logo de Proxmology...",
|
||||
"Downloading UUP converter...": "Descargando el convertidor UUP...",
|
||||
"Downloading amdgpu_top": "Descargando amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Descargando y verificando la imagen.\nPuede tardar unos minutos. Espera...",
|
||||
"Downloading official installer...": "Descargando el instalador oficial...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "La descarga de backups cifrados ya existentes desde este host fallará salvo que conserve una copia de la clave actual.",
|
||||
"Downloading the image:": "Descargando la imagen:",
|
||||
@@ -1997,9 +2018,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Ingrese el nombre del grupo ZFS para el disco seleccionado:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Ingrese un nombre para el punto de montaje (usado como /mnt/<nombre>):",
|
||||
"Enter a name for the new virtual machine:": "Ingrese un nombre para la nueva máquina virtual:",
|
||||
"Enter a non-empty password or access token on a single line.": "Escribe una contraseña o un token de acceso, en una sola línea.",
|
||||
"Enter a number, or write or paste a command:": "Ingrese un número, o escriba o pegue un comando:",
|
||||
"Enter a systemd calendar event, e.g.:": "Introduzca un evento de calendario de systemd, por ejemplo:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Introduzca una dirección IPv4 usable con su prefijo, por ejemplo",
|
||||
"Enter a valid registry username.": "Escribe un usuario válido para el registro.",
|
||||
"Enter backup file (.zst):": "Ingrese el archivo de backup (.zst):",
|
||||
"Enter backup path (.tar.zst):": "Ingrese la ruta de backup (.tar.zst):",
|
||||
"Enter backup path (.vma.zst):": "Ingrese la ruta de backup (.vma.zst):",
|
||||
@@ -2289,7 +2312,7 @@
|
||||
"Failed to enable ZFS autotrim for pool:": "No se pudo habilitar el recorte automático de ZFS para el grupo:",
|
||||
"Failed to enable automatic time synchronization": "No se pudo habilitar la sincronización automática de la hora",
|
||||
"Failed to extract OVA file:": "No se pudo extraer el archivo OVA:",
|
||||
"Failed to extract a nonempty loader image.": "no se pudo extraer una imagen de cargador que no esté vacía.",
|
||||
"Failed to extract a nonempty loader image.": "No se pudo extraer la imagen del cargador, o está vacía.",
|
||||
"Failed to extract package": "No se pudo extraer el paquete",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "No se pudo recuperar la clave GPG de Google Coral. Controlar",
|
||||
"Failed to format disk as": "No se pudo formatear el disco como",
|
||||
@@ -2344,7 +2367,7 @@
|
||||
"Failed to restart — restart manually to activate mount": "No se pudo reiniciar: reinicie manualmente para activar el montaje",
|
||||
"Failed to restore subscription banner completely": "No se pudo restaurar completamente el banner de suscripción",
|
||||
"Failed to retrieve Fastfetch download URL.": "No se pudo recuperar la URL de descarga de Fastfetch.",
|
||||
"Failed to retrieve loader release metadata.": "no se pudieron recuperar los metadatos de la versión del cargador.",
|
||||
"Failed to retrieve loader release metadata.": "No se pudieron obtener los metadatos de la versión del cargador.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "No se pudo ejecutar el instalador de log2ram. Compruebe /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "No se pudo guardar la imagen del cargador.",
|
||||
"Failed to set VM description": "No se pudo establecer la descripción de la máquina virtual",
|
||||
@@ -2392,7 +2415,7 @@
|
||||
"Fastfetch will start automatically in the console": "Fastfetch se iniciará automáticamente en la consola",
|
||||
"Ferdium is a desktop app that helps you organize how you use your favourite apps by combining them into one application.": "Ferdium es una aplicación de escritorio que te ayuda a organizar el uso de tus aplicaciones favoritas reuniéndolas en una sola.",
|
||||
"Fetching NVIDIA driver versions supported by your GPU...": "Obteniendo versiones del controlador NVIDIA compatibles con su GPU...",
|
||||
"Figurine installation and configuration completed successfully.": "La instalación y configuración deFigurine se completó con éxito.",
|
||||
"Figurine installation and configuration completed successfully.": "La instalación y configuración de Figurine se completó correctamente.",
|
||||
"Figurine is not installed.": "Figurine no está instalado.",
|
||||
"Figurine removed from system": "Figurine desinstalado del sistema",
|
||||
"File bind mounts do not support spaces:": "Los bind mounts de archivo no admiten espacios:",
|
||||
@@ -2673,6 +2696,7 @@
|
||||
"Help and Info": "Ayuda e información",
|
||||
"Help and Info Commands": "Comandos de ayuda e información",
|
||||
"Helper-Scripts logo applied": "Logotipo de Helper-Scripts aplicado",
|
||||
"Helper:": "Asistente:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Escondido por seguridad",
|
||||
"Hidden:": "Oculto:",
|
||||
@@ -2886,16 +2910,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Si su DHCP tiene una reserva estática para la MAC anterior, actualícela.",
|
||||
"Image": "Imagen",
|
||||
"Image Source Directory": "Directorio de origen de imágenes",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Acceso a la imagen confirmado.\n\n{reference}\n\nArquitectura: {architecture}\nVersión: {version}\nTamaño de descarga: {size}\nDigest: {digest}",
|
||||
"Image cache": "Caché de imágenes",
|
||||
"Image compatibility restored:": "Compatibilidad de imagen restaurada:",
|
||||
"Image compatibility verified:": "Compatibilidad de imagen verificada:",
|
||||
"Image directory:": "Directorio de imágenes:",
|
||||
"Image download failed:": "Descarga de imagen falló:",
|
||||
"Image downloaded": "Imagen descargada",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Imagen descargada y verificada.\n\n{reference}\n\nAlmacenamiento: {storage}\nTamaño del archivo: {size}\nArchivo: {archive}\n\nNo se ha creado ningún contenedor.\nProxMenux elimina las imágenes en caché que no se usan tras las actualizaciones correctas.",
|
||||
"Image file not found:": "Archivo de imagen no encontrado:",
|
||||
"Image imported:": "Imagen importada:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "La imagen no ha superado la verificación de integridad. Se ha descartado la descarga parcial; inténtalo de nuevo.",
|
||||
"Image integrity verified": "Integridad de la imagen verificada",
|
||||
"Image not allowed for the host monitor profile": "Imagen no permitida para el perfil del monitor host",
|
||||
"Image reference": "Referencia de la imagen",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Referencia de imagen (por ejemplo ghcr.io/user/application:latest)",
|
||||
"Image selection was cancelled": "Se canceló la selección de la imagen",
|
||||
"Image that is not in the catalog": "Imagen que no está en el catálogo",
|
||||
@@ -3024,6 +3052,7 @@
|
||||
"Install Samba inside CT:": "Instale Samba dentro de CT:",
|
||||
"Install ZFS auto-snapshot": "Instalar ZFS auto-snapshot",
|
||||
"Install a version from the branch the kernel names.": "Instale una versión de la rama que indica el kernel.",
|
||||
"Install an image as a native LXC": "Instalar una imagen como LXC nativo",
|
||||
"Install an image that is not in the catalog": "Instalar una imagen que no está en el catálogo",
|
||||
"Install analysis tools": "Instalar herramientas de análisis",
|
||||
"Install and configure": "Instalar y configurar",
|
||||
@@ -3063,6 +3092,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "La instalación finalizó pero los controladores no están cargados. Es posible que sea necesario reiniciar.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Instalación incompleta. Estos contenedores y sus datos se guardan:",
|
||||
"Installation log:": "Log de instalación:",
|
||||
"Installation settings": "Configuración de la instalación",
|
||||
"Installation summary": "Resumen de instalación",
|
||||
"Installed": "Instalado",
|
||||
"Installed at:": "Instalado en:",
|
||||
@@ -3236,6 +3266,7 @@
|
||||
"Invalid host path:": "Camino del host inválido:",
|
||||
"Invalid host-monitor firewall plan": "El plan de cortafuegos del monitor del host no es válido",
|
||||
"Invalid image probe descriptor": "Descriptor de sonda de imagen inválida",
|
||||
"Invalid image tag.": "La etiqueta de la imagen no es válida.",
|
||||
"Invalid input": "Entrada no válida",
|
||||
"Invalid internal volume": "Volumen interno inválido",
|
||||
"Invalid list:": "Lista inválida:",
|
||||
@@ -3293,6 +3324,7 @@
|
||||
"Invalid suite application": "Aplicación de suite inválida",
|
||||
"Invalid sysctl value:": "Valor sysctl inválido:",
|
||||
"Invalid template storage": "Almacenamiento de plantillas inválidas",
|
||||
"Invalid template storage name.": "El nombre del almacenamiento de plantillas no es válido.",
|
||||
"Invalid tmpfs options:": "Opciones de tmpfs inválidos:",
|
||||
"Invalid tmpfs path:": "Camino de los tmpfs inválidos:",
|
||||
"Invalid tmpfs size:": "Tamaño de tmpfs inválido:",
|
||||
@@ -3531,6 +3563,8 @@
|
||||
"Log2RAM write scheduled every": "Escritura de Log2RAM programada cada",
|
||||
"Log:": "Log:",
|
||||
"Logged-in users": "Usuarios registrados",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "El inicio de sesión en {registry} ha superado el tiempo de espera. Las credenciales guardadas no han cambiado.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "El cierre de sesión en {registry} ha superado el tiempo de espera. Las credenciales guardadas no han cambiado.",
|
||||
"Logrotate optimization completed": "Optimización de logrotate completada",
|
||||
"Logrotate service restarted successfully": "El servicio Logrotate se reinició correctamente",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop es un reproductor de música moderno y ligero, diseñado para funcionar de maravilla en el entorno de escritorio GNOME.",
|
||||
@@ -3593,6 +3627,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Configurar rutas personalizadas (agreguar/eliminar carpetas)",
|
||||
"Manage installed OCI applications": "Gestionar aplicaciones OCI instaladas",
|
||||
"Manage local backup target": "Configurar el destino del backup local",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Gestiona los registros de imágenes privadas.\nCon las credenciales guardadas, ProxMenux puede acceder a tus imágenes privadas.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Gestiona las cuentas de registro como root en el nodo Proxmox.",
|
||||
"Managed disks must have backup enabled and a valid size": "Los discos gestionados deben tener habilitado backup y un tamaño válido",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Gestión de proxy hosts de Nginx con una interfaz sencilla y potente.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Comandos CLI manuales (Administrador de discos y almacenamiento)",
|
||||
@@ -4109,6 +4145,7 @@
|
||||
"No accessible Samba servers found.": "No se encontraron servidores Samba accesibles.",
|
||||
"No accessible exports found.": "No se encontraron exportaciones accesibles.",
|
||||
"No accessible shares found.": "No se encontraron recursos compartidos accesibles.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Ningún almacenamiento activo de Proxmox acepta archivos de plantilla OCI.",
|
||||
"No active exports or showmount not available": "No hay exportaciones activas o showmount no disponible",
|
||||
"No active session": "Ninguna sesión activa",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "No hay suscripción activa ni un repositorio de PVE utilizable. El modo no interactivo no puede cambiar las fuentes de APT; configúralas en Nodo > Actualizaciones > Repositorios.",
|
||||
@@ -4228,6 +4265,7 @@
|
||||
"No recent": "No reciente",
|
||||
"No recent Samba servers found.": "No se encontraron servidores Samba recientes.",
|
||||
"No registered OCI containers are available for selection on this host.": "No hay contenedores OCI registrados disponibles para seleccionar en este host.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "No hay ninguna API de registro en {registry}. Comprueba el nombre y el puerto.",
|
||||
"No restored OCI application is waiting to be recovered.": "No hay ninguna aplicación OCI restaurada pendiente de recuperar.",
|
||||
"No results": "Sin resultados",
|
||||
"No routing information found.": "No se encontró información de enrutamiento.",
|
||||
@@ -4258,7 +4296,7 @@
|
||||
"No sysfs ROM entry — trying ACPI VFCT table...": "No hay entrada de ROM sysfs: probando la tabla ACPI VFCT...",
|
||||
"No target configured.": "No hay destino configurado.",
|
||||
"No test currently running": "No hay ninguna prueba actualmente en ejecución",
|
||||
"No unambiguous loader download found in release metadata.": "No se encontró ninguna descarga de cargador inequívoca en los metadatos de la versión.",
|
||||
"No unambiguous loader download found in release metadata.": "Los metadatos de la versión no indican una única descarga del cargador.",
|
||||
"No uninstaller found for:": "No se encontró ningún desinstalador para:",
|
||||
"No unprivileged containers available in Proxmox.": "No hay contenedores sin privilegios disponibles en Proxmox.",
|
||||
"No updates available — run a scan first or wait for the Monitor to refresh.": "No hay actualizaciones disponibles — ejecute antes un análisis o espere a que el Monitor se actualice.",
|
||||
@@ -4292,6 +4330,8 @@
|
||||
"Not an OVH server, skipping RTM installation": "No es un servidor OVH, se salta la instalación de RTM",
|
||||
"Not currently mounted": "Actualmente no montado",
|
||||
"Not currently mounted — skipping umount.": "Actualmente no montado: omitiendo el desmontaje.",
|
||||
"Not declared": "Sin declarar",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "No hay espacio suficiente en {storage}. Libera espacio o elige otro almacenamiento.",
|
||||
"Not found": "No encontrado",
|
||||
"Not found in the OCI archive:": "No se encuentra en el archivo OCI:",
|
||||
"Not imported:": "No importado:",
|
||||
@@ -4380,6 +4420,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Solo se pueden incorporar automáticamente dispositivos DRM Intel/AMD, Coral y USB",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Solo los nodos DRM de Intel/AMD, Coral, NPU y USB se pueden adoptar automáticamente",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Solo un Docker Swarm utiliza estos ajustes, por lo que no se aplican:",
|
||||
"Only a full sha256 image digest is supported.": "Solo se admite un digest sha256 completo.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Solo una instancia OCI independiente e instalada puede incorporar cambios externos",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Solo se pueden incorporar volúmenes de Proxmox incluidos en los backups",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Convierta a privilegiado solo si es absolutamente necesario para su caso de uso.",
|
||||
@@ -4533,6 +4574,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Es posible que el passthrough siga funcionando sin un archivo ROM.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "El passthrough puede funcionar, pero no se garantiza la fiabilidad del inicio/reinicio.",
|
||||
"Password": "Contraseña",
|
||||
"Password / access token (image pull permission)": "Contraseña o token de acceso (con permiso para descargar imágenes)",
|
||||
"Password Mismatch": "La contraseña no coincide",
|
||||
"Password cannot be empty.": "La contraseña no puede estar vacía.",
|
||||
"Password confirmation cannot be empty.": "La confirmación de contraseña no puede estar vacía.",
|
||||
@@ -4797,7 +4839,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux adjunta directorios, no archivos individuales, por lo que esta imagen no se puede instalar todavía.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux puede aplicar permisos de apertura en este directorio NFS desde el host para que el contenedor pueda leer y escribir:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux puede volver a montarlo con permisos abiertos para que cualquier LXC pueda leer y escribir.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux no puede instalar esta imagen de forma automática. Importa su archivo Compose.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux no puede anular los permisos del lado del servidor NFS del host.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux no ha podido traducir esta imagen. Prueba a importar su archivo Compose desde OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "Personalizaciones de ProxMenux eliminadas de bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux no le da a un contenedor el sistema de su host.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux no los instala. La instalación pide cómo conectarse a ellos.",
|
||||
@@ -4918,6 +4962,7 @@
|
||||
"Reading SMART data...": "Leyendo datos SMART...",
|
||||
"Reading SMART self-test log...": "Leyendo el log de autoprueba SMART...",
|
||||
"Reading full SMART report...": "Leyendo el informe SMART completo...",
|
||||
"Reading image metadata. Please wait...": "Leyendo los metadatos de la imagen. Espera...",
|
||||
"Real-time Performance Monitoring": "Monitorización del rendimiento en tiempo real",
|
||||
"Real-time bandwidth usage (press q to exit)": "Uso de ancho de banda en tiempo real (presione q para salir)",
|
||||
"Real-time collaborative document editor": "Editor colaborativo de documentos en tiempo real",
|
||||
@@ -5003,6 +5048,9 @@
|
||||
"Register mount path in Proxmox:": "Registre la ruta de montaje en Proxmox:",
|
||||
"Registering disk as Proxmox storage...": "Registrando disco como almacenamiento en Proxmox...",
|
||||
"Registering module with DKMS...": "Registrando módulo con DKMS...",
|
||||
"Registry accounts": "Cuentas de registro",
|
||||
"Registry hostname": "Nombre del registro",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Registro: {registry}\nCuenta: {account}\nAutenticación: {method}\n\nLas credenciales guardadas se comprueban al acceder a una imagen.",
|
||||
"Reinstall / update Coral drivers": "Reinstalar/actualizar los controladores Coral",
|
||||
"Reinstall Fail2Ban": "Reinstale Fail2Ban",
|
||||
"Reinstall Lynis": "Reinstale Lynis",
|
||||
@@ -5074,8 +5122,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Eliminar el metapaquete obsoleto systemd-boot",
|
||||
"Remove old repository files:": "Eliminar archivos antiguos del repositorio:",
|
||||
"Remove passthrough device from VM": "Eliminar el dispositivo en passthrough de la VM",
|
||||
"Remove saved credentials": "Eliminar las credenciales guardadas",
|
||||
"Remove subscription banner": "Eliminar banner de suscripción",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "¿Eliminar la aplicación? Los discos de sus contenedores se eliminan y solo un backup puede recuperarlos.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "¿Eliminar las credenciales guardadas de {registry}?\nLas aplicaciones en marcha seguirán funcionando.",
|
||||
"Remove the unprivileged flag from configuration:": "Elimine el flag unprivileged de la configuración:",
|
||||
"Remove unused packages and their config": "Eliminar paquetes no utilizados y su configuración",
|
||||
"Remove: delete the application and its containers": "Eliminar: la aplicación y sus contenedores",
|
||||
@@ -5397,6 +5447,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Guarda y clasifica artículos. Léelos más tarde. Con libertad.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Guarde la frase de contraseña en un lugar seguro AHORA, antes de continuar.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "¿Guardar este destino Borg para no tener que volver a introducir los detalles?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Se han eliminado las credenciales guardadas de {registry}.\nLos demás ficheros de credenciales de Skopeo o Docker se gestionan aparte.",
|
||||
"Saved record removed": "Registro guardado eliminado",
|
||||
"Saving changes...": "Guardando los cambios...",
|
||||
"Saving the new configuration": "Salvando la nueva configuración",
|
||||
@@ -5777,9 +5828,11 @@
|
||||
"Shutdown timeout": "Tiempo de espera de apagado",
|
||||
"SiYuan access code": "Código de acceso de SiYuan",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear gestiona series de TV y anime, detecta nuevos episodios, enlaza con aplicaciones de descarga y más..",
|
||||
"Sign in to a registry": "Iniciar sesión en un registro",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Inicia sesión en el panel y crea un usuario Samba en Ajustes antes de publicar un directorio por SMB.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal es una aplicación de mensajería con la privacidad como base. Es gratuita y fácil de usar, con un sólido cifrado de extremo a extremo que mantiene tus comunicaciones totalmente privadas.",
|
||||
"Signatures removed. Partition table preserved.": "Firmas eliminadas. Se conserva la tabla de particiones.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Sesión iniciada en {registry} como {username}.\n\nLas credenciales quedan guardadas para ProxMenux.\nElige la cuenta para comprobar, descargar o instalar una imagen.",
|
||||
"Simple and easy to use DDNS": "DDNS simple y fácil de usar",
|
||||
"Single GPU Warning": "Advertencia de GPU única",
|
||||
"Single target found — selected automatically:": "Destino único encontrado: seleccionado automáticamente:",
|
||||
@@ -5805,6 +5858,8 @@
|
||||
"Skipping SR-IOV device": "Saltar el dispositivo SR-IOV",
|
||||
"Skipping installation.": "Saltarse la instalación.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Saltarse parches manuales: feranick fork ya es compatible con este kernel.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo no está disponible. Restaura las dependencias OCI de ProxMenux e inténtalo de nuevo.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo ha devuelto un fichero de credenciales no válido; las credenciales guardadas no han cambiado.",
|
||||
"Sleek podcast downloader with GPodder sync": "Descargador de podcasts elegante con sincronización GPodder",
|
||||
"Smart Card": "Tarjeta inteligente",
|
||||
"Smart restore plan — hardware compatibility check": "Plan de restauración inteligente: verificación de compatibilidad de hardware",
|
||||
@@ -6063,6 +6118,7 @@
|
||||
"TCP optimizations configuration completed": "Configuración de optimizaciones TCP completada",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "Optimizaciones de TCP revertidas (los valores predeterminados se restauran en el próximo reinicio)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "El puerto TCP 5201 es accesible (cortafuegos del servidor)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "La verificación TLS de {registry} ha fallado. Instala la CA del registro en /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "Dispositivo TPM agregado a la VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "La selección de almacenamiento de TPM falló o se canceló. Se canceló la creación de la máquina virtual.",
|
||||
"TROUBLESHOOTING:": "SOLUCIÓN DE PROBLEMAS:",
|
||||
@@ -6254,6 +6310,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "La configuración debe funcionar como root en Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "La configuración de un nuevo miembro cambió después de su creación",
|
||||
"The configuration stopped because of an unexpected error": "La configuración se detuvo debido a un error inesperado",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "No se pudo usar el asistente de credenciales configurado. Comprueba su instalación y su almacén de credenciales.",
|
||||
"The console of the container could not be configured": "No se pudo configurar la consola del contenedor",
|
||||
"The consume/export volumes need at least 1 GB": "Los volúmenes de consumo/exportación necesitan al menos 1 GB",
|
||||
"The container could not be removed automatically:": "El contenedor no se puede retirar automáticamente:",
|
||||
@@ -6291,6 +6348,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Los contenedores ya no las necesitan; una actualización descarga las nuevas versiones cuando las hay.",
|
||||
"The containers were created from downloaded OCI images": "Los contenedores fueron creados a partir de imágenes OCI descargadas",
|
||||
"The coordinated backup was modified": "El backup coordinado fue modificada",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "El fichero de credenciales ha cambiado durante la operación. Inténtalo de nuevo; no se ha sobrescrito.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "El controlador actual se desinstalará por completo antes de instalar la nueva versión. ¿Continuar?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "La imagen actual del canal guardado será revisada y descargada. Se mantienen recursos, rutas y GPU. El CT se detiene durante el reemplazo y se crea primero un backup nativo.",
|
||||
"The current record is missing for": "Falta el registro actual para",
|
||||
@@ -6373,7 +6431,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "La subred del bridge ha cambiado; no se ha añadido ninguna regla al cortafuegos",
|
||||
"The host-monitor web interface uses the host network.": "La interfaz web del monitor del host usa la red del host.",
|
||||
"The identity of a member was replaced": "Se sustituyó la identidad de un miembro",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "La ruta de la caché de imágenes no es segura. Comprueba el almacenamiento de plantillas antes de volver a intentarlo.",
|
||||
"The image changes the user expected by the adapter": "La imagen cambia el usuario esperado por el adaptador",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "No se pudo descargar o verificar la imagen. Comprueba el acceso al registro y al almacenamiento, e inténtalo de nuevo.",
|
||||
"The image could not be read from its registry:": "La imagen no se pudo leer desde su registro:",
|
||||
"The image declares data paths that are still stored in the rootfs": "La imagen declara caminos de datos que aún están almacenados en los rootfs",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "La imagen no concedió el acceso del usuario de la aplicación a los dispositivos; comprobar su entrada nativa. Los permisos del host no se relajaron.",
|
||||
@@ -6386,6 +6446,8 @@
|
||||
"The image is in its registry, for one architecture.": "La imagen está en su registro, para una arquitectura.",
|
||||
"The image is in its registry.": "La imagen está en su registro.",
|
||||
"The image is in its registry:": "La imagen está en su registro:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "El manifiesto de la imagen no ha superado la verificación de integridad. Inténtalo de nuevo o contacta con quien publica la imagen.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "La imagen o la etiqueta no está en {registry}, o esta cuenta no puede acceder a ella. Comprueba la referencia.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "La imagen solicita NVIDIA, pero el host no tiene ningún controlador NVIDIA trabajando",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "La imagen pide desactivar parte del confinamiento de AppArmor o seccomp. Continúa solo si confías en la imagen y aceptas este riesgo.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "La imagen pide desactivar parte del confinamiento de AppArmor o seccomp. El Compose ofrece una relajación opcional de AppArmor o seccomp; seguirá desactivada salvo que el usuario la seleccione. Continúa solo si confías en la imagen y aceptas este riesgo.",
|
||||
@@ -6517,7 +6579,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "El registro o el diagnóstico no se pudo completar; no se realizó ninguna actualización.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "La recuperación no terminó. Revise el log y elija \"Recuperar la instalación anterior\" de nuevo para este contenedor en el menú de gestión OCI.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "La recuperación no terminó. Revisa el log y elige \"{choice}\" de nuevo para este contenedor en el menú de gestión OCI.",
|
||||
"The registry authentication file is invalid; it was not changed.": "El fichero de autenticación del registro no es válido; no se ha modificado.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "El fichero de autenticación del registro debe pertenecer a root y tener el modo 600.",
|
||||
"The registry authentication file must have an absolute path.": "El fichero de autenticación del registro debe tener una ruta absoluta.",
|
||||
"The registry authentication path cannot contain symbolic links.": "La ruta del fichero de autenticación no puede contener enlaces simbólicos.",
|
||||
"The registry authentication path has an unsafe parent directory.": "La ruta del fichero de autenticación tiene una carpeta superior insegura.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "La carpeta de credenciales del registro debe pertenecer a root y tener el modo 700.",
|
||||
"The registry did not return the saved image digest": "El registro no devolvió el digest de imagen guardado",
|
||||
"The registry returned incomplete or unsupported image metadata.": "El registro ha devuelto metadatos de imagen incompletos o no admitidos.",
|
||||
"The registry returned invalid or unsupported image metadata.": "El registro ha devuelto metadatos de imagen no válidos o no admitidos.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "El remoto no existe; crear y autorizar primero en el WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "El instalador remoto debe funcionar como root en Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "El remoto ya debe estar creado y autorizado en la interfaz web de Rclone. Esta operación reinicia el CT y publica dos puntos de vista FUSE sobre el host.",
|
||||
@@ -6675,6 +6745,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Esta GPU se considera incompatible con el passthrough de GPU a una VM en ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Este recurso compartido NFS está completamente restringido: ni siquiera la raíz del host puede escribir en él.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Esta máquina virtual requiere pasos de instalación adicionales; consulte la guía de instalación en:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Esta cuenta es de {registry}. Escribe una imagen de ese registro.",
|
||||
"This action will:": "Esta acción:",
|
||||
"This application cannot be recovered yet:": "Esta aplicación todavía no se puede recuperar:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Esta aplicación todavía no se puede recuperar; no se ha cambiado nada:",
|
||||
@@ -6706,8 +6777,10 @@
|
||||
"This explicitly marks the container as privileged": "Esto marca explícitamente el contenedor como privilegiado",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Este archivo decide qué se monta y con qué privilegios. Instálalo solo si viene de una fuente de confianza.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Esto garantiza que los nodos del dispositivo estén disponibles antes de aplicar la configuración de GPU LXC.",
|
||||
"This host architecture is not supported by the OCI image importer.": "El importador de imágenes OCI no admite la arquitectura de este host.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Este host no tiene una suscripción activa, ¿cambiar al repositorio sin suscripción? La fuente Enterprise de PVE, que no es accesible, se desactivará. Las fuentes Enterprise de Ceph, si existen, se desactivarán sin elegir un canal de Ceph que las sustituya; configura Ceph por separado si lo necesitas.",
|
||||
"This image cannot be installed as it is described:": "Esta imagen no se puede instalar como se describe:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Esta imagen no tiene una versión Linux compatible con este host ({architecture}).",
|
||||
"This image requires the host module": "Esta imagen requiere el módulo host",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Esta importación rechaza estas rutas sin comprobar si son archivos o directorios.",
|
||||
"This installation will:": "Esta instalación:",
|
||||
@@ -6823,6 +6896,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Para usar la GPU nuevamente en LXC, ejecute Agregar GPU a LXC desde GPU y Menú Coral-TPU",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Para utilizar la VM sin problemas, se debe reiniciar el host antes de iniciarlo.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Para usar este recurso compartido desde un LXC, móntelo mediante enlace:",
|
||||
"Token": "Token",
|
||||
"Tool exit code:": "Código de salida de la herramienta:",
|
||||
"Tool output:": "Salida de herramienta:",
|
||||
"Tools": "Tools",
|
||||
@@ -6967,6 +7041,7 @@
|
||||
"Unsafe private configuration path": "Vía de configuración privada insegura",
|
||||
"Unsafe qBittorrent configuration path": "Vía de configuración segura qBittorrent",
|
||||
"Unsafe record": "Registro inseguro",
|
||||
"Unsafe registry credential lock.": "El bloqueo de las credenciales del registro no es seguro.",
|
||||
"Unsafe registry directory": "Directorio del registro no seguro",
|
||||
"Unsafe registry lock": "Bloqueo del registro no seguro",
|
||||
"Unsafe rootfs for the capture": "rootfs inseguros para la captura",
|
||||
@@ -6979,6 +7054,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Perfil OCI-LXC sin soporte:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Perfil sin soporte OCI-LXC seccomp:",
|
||||
"Unsupported Terminal": "Terminal no compatible",
|
||||
"Unsupported architecture for Figurine:": "Arquitectura no compatible con Figurine:",
|
||||
"Unsupported architecture:": "Arquitectura sin soporte:",
|
||||
"Unsupported backup compression": "Compresión de backup sin soporte",
|
||||
"Unsupported credential pattern:": "Patrón credential sin soporte:",
|
||||
@@ -7029,6 +7105,7 @@
|
||||
"Update cancelled by user": "Actualización cancelada por el usuario",
|
||||
"Update completed. Data kept.": "Actualización completada. Datos conservados.",
|
||||
"Update completed. Press Enter to continue...": "Actualización completada. Presione Entrar para continuar...",
|
||||
"Update credentials": "Actualizar las credenciales",
|
||||
"Update every container of the application": "Actualizar cada contenedor de la aplicación",
|
||||
"Update kernel to compatible version": "Actualizar el kernel a una versión compatible",
|
||||
"Update now?": "¿Actualizar ahora?",
|
||||
@@ -7095,8 +7172,10 @@
|
||||
"Use a custom path": "Usar una ruta personalizada",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Utilice un LXC privilegiado para flujos de trabajo de servidor/cliente NFS.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Utilice un LXC privilegiado para flujos de trabajo de cliente/servidor Samba.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Escribe el nombre de un registro, por ejemplo ghcr.io o registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Use un archivo de clave privada SSH existente en este host",
|
||||
"Use an existing keyfile": "Usar un archivo de claves existente",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Escribe una referencia de imagen, por ejemplo ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Úselo tal cual: mantenga los datos y el sistema de archivos",
|
||||
"Use content types according to your use case.": "Utilice tipos de contenido según su caso de uso.",
|
||||
"Use default": "Usar predeterminado",
|
||||
@@ -7136,6 +7215,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "WebUI fácil de usar para LLM (antes Ollama WebUI)",
|
||||
"Username": "Nombre de usuario",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Nombre de usuario (por ejemplo, root@pam o usuario@pbs!token):",
|
||||
"Username / token": "Usuario y token",
|
||||
"Username and password": "Nombre de usuario y contraseña",
|
||||
"Username and password will be cleared.": "Se borrarán el nombre de usuario y la contraseña.",
|
||||
"Username cannot be empty.": "El nombre de usuario no puede estar vacío.",
|
||||
@@ -7236,6 +7316,7 @@
|
||||
"Verifying Ceph packages availability...": "Verificando la disponibilidad de los paquetes de Ceph...",
|
||||
"Verifying all utilities status": "Comprobando el estado de todas las utilidades",
|
||||
"Verifying disk accessibility in CT": "Verificación de la accesibilidad del disco en CT",
|
||||
"Verifying registry access. Please wait...": "Comprobando el acceso al registro. Espera...",
|
||||
"Verifying the backups...": "Verificando los backups...",
|
||||
"Verifying the image integrity...": "Verificando la integridad de la imagen...",
|
||||
"Version": "Versión",
|
||||
@@ -7535,6 +7616,7 @@
|
||||
"assembling": "ensamblando",
|
||||
"automatically. Install it manually inside the container.": "automáticamente. Instálelo manualmente dentro del contenedor.",
|
||||
"automatically. Reboot LXC to fully release.": "automáticamente. Reinicie LXC para liberarlo por completo.",
|
||||
"available": "disponibles",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "disponible para montajes de enlace LXC a través de 'LXC Mount Manager'",
|
||||
"available in this same GPU and TPU menu.": "disponible en este mismo menú de GPU y TPU.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "backup en /etc/fstab.proxmenux.bak",
|
||||
@@ -7886,6 +7968,7 @@
|
||||
"runs in": "se ejecuta en",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "rutas seguras ahora (configuraciones, paquetes, /etc, /root, ...)",
|
||||
"same MAC": "misma MAC",
|
||||
"saved": "guardada",
|
||||
"seconds (default)": "segundos (predeterminado)",
|
||||
"see log:": "ver log:",
|
||||
"selected by default": "seleccionado por defecto",
|
||||
@@ -8004,7 +8087,15 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot eliminado (las instantáneas existentes se conservan en el grupo)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "Comando zpool no encontrado. Instale zfsutils-linux y vuelva a intentarlo.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool no encontrado. Instale zfsutils-linux y vuelva a intentarlo.",
|
||||
"{count} saved account.": "{count} cuenta guardada.",
|
||||
"{count} saved accounts.": "{count} cuentas guardadas.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} ya existe y pertenece a otro usuario del host, así que {app} no puede escribir en él.\n\nProxMenux puede añadir reglas de acceso (ACL) a este directorio, a todo lo que contiene y a lo que se cree en él después, para los usuarios y grupos con los que {app} se ejecuta en el host (ID {ids}). El propietario de los archivos no cambia y lo que hoy los lee o escribe lo sigue haciendo; el propietario del directorio también tiene acceso a los archivos que cree {app}.\n\n¿Dar acceso a {app} a este directorio?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} ha respondido con HTTP sin cifrar. Usa un registro con HTTPS; la verificación TLS sigue activa.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} no ha respondido en {timeout} segundos. Inténtalo más tarde.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "{registry} está limitando las peticiones. Espera un rato e inténtalo de nuevo.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} ha denegado el acceso a esta imagen:\n{reference}\n\nSi la imagen es privada, inicia sesión con una cuenta que pueda descargarla.\n\n¿Iniciar sesión ahora?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} ha informado de un error del servidor. Inténtalo más tarde.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} ha devuelto metadatos de imagen no válidos o no admitidos.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "— La restauración completa/personalizada omitirá las rutas vinculadas al kernel",
|
||||
"— disk may be busy. Skipping fstab removal.": "— el disco puede estar ocupado. Saltarse la eliminación de fstab.",
|
||||
"— restore proceeds as same-version (verified safe)": "- la restauración procede como la misma versión (segura verificada)",
|
||||
|
||||
+98
-7
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Pont d'accès pour Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "L'accès n'a pas pu être accordé complètement ; l'application risque de ne pas pouvoir écrire dans :",
|
||||
"Access could not be granted; the application cannot write to:": "L'accès n'a pas pu être accordé ; l'application ne peut pas écrire dans :",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Accès refusé par {registry}. Vérifiez le nom de l'image et connectez-vous à partir des comptes de registre.",
|
||||
"Access granted to the application on:": "Accès accordé à l’application sur :",
|
||||
"Access password of the web interface (optional)": "Mot de passe d'accès à l'interface web (facultatif)",
|
||||
"Access profile:": "Profil d'accès :",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Avancé",
|
||||
"Advanced Diagnostics": "Diagnostic avancé",
|
||||
"Advanced Network Diagnostics": "Diagnostics réseau avancés",
|
||||
"Advanced settings": "Paramètres avancés",
|
||||
"Advanced: every setting of the container": "Avancé : chaque réglage du conteneur",
|
||||
"Affected LXC containers": "Conteneurs LXC concernés",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Après avoir terminé la configuration du GPU, démarrez la VM manuellement lorsque l'hôte est prêt.",
|
||||
@@ -328,7 +330,7 @@
|
||||
"After this LXC → VM switch, reboot the host so the new binding state is applied cleanly.": "Après ce commutateur LXC → VM, redémarrez l'hôte afin que le nouvel état de liaison soit appliqué proprement.",
|
||||
"Airsonic Advanced web interface": "Interface web Airsonic Advanced",
|
||||
"Airsonic-advanced is a free, web-based media streamer, providing ubiquitious access to your music. Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple players simultaneously, for instance to one player in your kitchen and another in your living room.": "Airsonic-Advanced est un flux multimédia gratuit, basé sur le web, offrant un accès ubiquitious à votre musique. Utilisez-le pour partager votre musique avec des amis, ou pour écouter votre propre musique au travail. Vous pouvez diffuser simultanément vers plusieurs joueurs, par exemple vers un joueur dans votre cuisine et un autre dans votre salon.",
|
||||
"Aliases added to .bashrc": "Alias ajoutés à .bashrc",
|
||||
"Aliases added to .bashrc": "Alias ajoutés à .bashrc",
|
||||
"Alist Sync web interface": "Alist Interface web Sync",
|
||||
"All": "Tous",
|
||||
"All Available Scripts": "Tous les scripts disponibles",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Un autre OCI operation utilise le registre des instances. Attendez qu'il finisse et ouvrez à nouveau ce menu; aucun conteneur n'est modifié.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Une autre opération OCI utilise le registre d'instance. Attendez que ça se termine.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Un autre OCI operation utilise le registre. Ce opera n'a pas commencé.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "Une autre opération ProxMenux OCI est en cours d'exécution. Réessayez une fois terminé.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Une autre configuration ZRAM existe ou n'a pas pu être inspectée ; systemd-zram-generator a été conservé",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Une autre configuration de générateur ZRAM existe ; refusant de l'écraser:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Une autre configuration d'échange ZRAM existe ; refusant de le remplacer :",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Une autre instance utilise",
|
||||
"Another job that writes to the same storage still starts them.": "Une autre tâche qui écrit dans le même stockage continue de les lancer.",
|
||||
"Another node, typed by hand": "Un autre nœud, tapé à la main",
|
||||
"Another registry account operation is running. Try again when it finishes.": "Une autre opération de compte de registre est en cours. Réessayez une fois terminé.",
|
||||
"Another stack operation is pending": "Une autre pile operation est en attente",
|
||||
"Application": "Demande",
|
||||
"Application registered on this host:": "Application enregistrée sur cet hôte :",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Authentification",
|
||||
"Authentication & Security": "Authentification et sécurité",
|
||||
"Authentication Error": "Erreur d'authentification",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Échec de l'authentification pour {registry}. Vérifiez les autorisations du compte et du jeton.",
|
||||
"Authentication failed.": "L'authentification a échoué.",
|
||||
"Authentication required:": "Authentification requise :",
|
||||
"Authentication:": "Authentification:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Impossible de résoudre le répertoire de base du conteneur :",
|
||||
"Cannot validate credentials - no shares available for testing.": "Impossible de valider les informations d'identification - aucun partage disponible pour les tests.",
|
||||
"Cannot verify the reused disk:": "Impossible de vérifier le disque réutilisé :",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Impossible d'écrire l'archive d'images sur {storage}. Vérifiez l'accès au stockage et l'état du montage.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Les capacités ne peuvent être conservées et toutes abandonnées en même temps",
|
||||
"Category": "Catégorie",
|
||||
"Caution: Maximum mode generates more heat.": "Attention : le mode maximum génère plus de chaleur.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Vérifier le statut de Samba",
|
||||
"Check VM disk/PCI slots": "Vérifiez les emplacements disque/PCI de la VM",
|
||||
"Check VM passthrough settings": "Vérifier les paramètres de relais de la VM",
|
||||
"Check access to an image": "Vérifier l'accès à une image",
|
||||
"Check connectivity with another host": "Vérifiez la connectivité avec un autre hôte",
|
||||
"Check container mount points": "Vérifier les points de montage du conteneur",
|
||||
"Check if container is unprivileged:": "Vérifiez si le conteneur n'est pas privilégié :",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Vérifiez que :",
|
||||
"Check the error messages above for details.": "Consultez les messages d'erreur ci-dessus pour plus de détails.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Vérifiez la référence de l'image et l'accès au registre. Si le registre n'est pas disponible, réessayez plus tard. Un registre privé nécessite des identifiants, qui ne sont pas encore pris en charge.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Vérifiez la référence de l’image et l’accès au registre. Si le registre n'est pas disponible, réessayez plus tard. Pour une image privée, connectez-vous à partir des comptes de registre dans le menu OCI.",
|
||||
"Check the service status manually if needed.": "Vérifiez l'état du service manuellement si nécessaire.",
|
||||
"Checking MOTD configuration...": "Vérification de la configuration MOTD...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Vérification de l'état du pilote NVIDIA avec nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Vérification de l'espace libre dans /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Vérifier si le disque système est SSD ou M.2...",
|
||||
"Checking if the server belongs to OVH...": "Vérifier si le serveur appartient à OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Vérification de l'accès aux images et des métadonnées. S'il vous plaît, attendez...",
|
||||
"Checking kernel headers and build tools...": "Vérification des en-têtes du noyau et des outils de construction...",
|
||||
"Checking remaining interfaces": "Vérification des interfaces restantes",
|
||||
"Checking that the container keeps running...": "Je vérifie que le conteneur continue de fonctionner...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Choisissez le mode iperf3 :",
|
||||
"Choose options to configure:": "Choisissez les options à configurer :",
|
||||
"Choose specific VMs/CTs": "Choisir des VM/CT spécifiques",
|
||||
"Choose storage for the downloaded image.": "Choisissez le stockage pour l’image téléchargée.",
|
||||
"Choose the driver version for Coral M.2:": "Choisissez la version du pilote pour Coral M.2 :",
|
||||
"Choose the filesystem for the new partition:": "Choisissez le système de fichiers pour la nouvelle partition :",
|
||||
"Choose the release channel to use:": "Choisissez le canal de publication à utiliser :",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "Impossible de publier la restauration en attente. La restauration précédente en attente a été conservée.",
|
||||
"Could not push the key. Check the password and that": "Impossible d'appuyer sur la clé. Vérifiez le mot de passe et cela",
|
||||
"Could not query the image registry": "Impossible d'interroger le registre d'images",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "Impossible d'atteindre {registry}. Vérifiez son adresse, son DNS et son accès au réseau.",
|
||||
"Could not read SMART data from": "Impossible de lire les données SMART de",
|
||||
"Could not read VM configuration.": "Impossible de lire la configuration de la VM.",
|
||||
"Could not read the CUDA compute capability": "Impossible de lire la capacité de calcul CUDA",
|
||||
"Could not read the NVIDIA driver version": "Impossible de lire la version du pilote NVIDIA",
|
||||
"Could not read the host firewall rules": "Impossible de lire les règles du pare-feu de l'hôte",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Impossible de lire l'image à partir de {registry}. Vérifiez la référence et connectez-vous à partir des comptes de registre.",
|
||||
"Could not read this job.": "Impossible de lire ce travail.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "Impossible de publier les pages ZRAM ; le profil existant reste actif",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Impossible de remonter automatiquement. Essayez manuellement ou vérifiez les informations d'identification.",
|
||||
"Could not remove VM automatically. Run manually:": "Impossible de supprimer automatiquement la VM. Exécuter manuellement :",
|
||||
"Could not remove ZRAM profile; configuration was restored": "Impossible de supprimer le profil ZRAM ; la configuration a été restaurée",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "Impossible de supprimer le profil ZRAM ; la configuration a été restaurée mais le swap n'a pas pu être redémarré",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Impossible de supprimer les informations d'identification pour {registry} ; les informations d'identification du fichier enregistré n'ont pas été modifiées.",
|
||||
"Could not remove previous DKMS tree at": "Impossible de supprimer l'arborescence DKMS précédente à",
|
||||
"Could not reserve a private network for the stack": "Impossible de réserver un réseau privé pour la pile",
|
||||
"Could not resolve the Compose user:": "Impossible de résoudre l'utilisateur Composer :",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Impossible de définir l'affichage virtuel de la VM sur VGA : std",
|
||||
"Could not set boot order for": "Impossible de définir l'ordre de démarrage pour",
|
||||
"Could not set the container entrypoint": "Impossible de définir le point d'entrée du conteneur",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Impossible de se connecter à {registry}. Vérifiez l'accès au registre et les autorisations des jetons.",
|
||||
"Could not stage pending restore path:": "Impossible de préparer le chemin de restauration en attente :",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "Impossible d’effectuer la restauration en attente. Rien de nouveau n'était prévu.",
|
||||
"Could not stop LXC": "Impossible d'arrêter LXC",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Création du réseau privé...",
|
||||
"Creating the temporary data container": "Création du conteneur temporaire de données",
|
||||
"Creative & Design": "Création et design",
|
||||
"Credential helper": "Assistant d'identification",
|
||||
"Credential storage and access": "Stockage et accès des informations d’identification",
|
||||
"Credentials are correct": "Les informations d'identification sont correctes",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Informations d'identification effacées. Jwt_secret et jetons API préservés.",
|
||||
"Credentials file created securely.": "Fichier d’informations d’identification créé en toute sécurité.",
|
||||
"Credentials file removed.": "Fichier d'informations d'identification supprimé.",
|
||||
"Credentials file:": "Fichier d'informations d'identification :",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Fichier d'informations d'identification :\n{path}\n\nPropriété de root ; mode répertoire 700 et mode fichier 600.\nLes informations d’identification de base sont codées en base64 et non cryptées.\nLes assistants d’identification utilisent leur propre stockage.\n\nUtilisez un jeton d'accès avec l'autorisation d'extraire des images.\nConfigurez les informations d'identification sur chaque nœud qui télécharge des images.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Fichier d'informations d'identification :\n{path}\n\nPropriété de root ; mode répertoire 700 et mode fichier 600.\nLes informations d’identification de base sont codées en base64 et non cryptées.\nLes assistants d’identification utilisent leur propre stockage.\n\nUtilisez un jeton d'accès avec l'autorisation d'extraire des images.\nChaque nœud du cluster utilise les comptes enregistrés ici.",
|
||||
"Credentials validated successfully": "Identifiants validés avec succès",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Restauration entre hôtes : les ID d'invité dans la sauvegarde chevauchent les ID actifs sur la cible :",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Restauration inter-noyau – chemins liés au noyau fusionnés, non copiés",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Connexion par défaut",
|
||||
"Default options": "Options par défaut",
|
||||
"Default options read/write": "Options par défaut lecture/écriture",
|
||||
"Default settings": "Paramètres par défaut",
|
||||
"Default will be used:": "la valeur par défaut sera utilisée :",
|
||||
"Default:": "Par défaut :",
|
||||
"Default: only what the application needs": "Par défaut : seulement ce dont l'application a besoin",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs est un robot Discord pour demander des médias à travers *arr backends, écrit dans Rust.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander est un gestionnaire de fichiers gratuit cross open source avec deux panneaux côte à côte. Il est inspiré par Total Commander et présente de nouvelles idées.",
|
||||
"Download Spotify music with album art and metadata": "Télécharger Spotify musique avec album art et métadonnées",
|
||||
"Download an image to template storage": "Télécharger une image dans le stockage de modèles",
|
||||
"Download an oci-compose from an address": "Télécharger un oci-compose à partir d'une adresse",
|
||||
"Download failed for all attempted URLs": "Le téléchargement a échoué pour toutes les tentatives d'URL",
|
||||
"Download its Compose file from an address": "Télécharger son fichier Composer depuis une adresse",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Téléchargement du logo Proxmology...",
|
||||
"Downloading UUP converter...": "Téléchargement du convertisseur UUP...",
|
||||
"Downloading amdgpu_top": "Téléchargement de amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Téléchargement et vérification de l'image.\nCela peut prendre quelques minutes. S'il vous plaît, attendez...",
|
||||
"Downloading official installer...": "Téléchargement du programme d'installation officiel...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "Le téléchargement de sauvegardes chiffrées préexistantes à partir de cet hôte échouera à moins que vous ne conserviez une copie de la clé actuelle.",
|
||||
"Downloading the image:": "Téléchargement de l'image :",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Entrez le nom du pool ZFS pour le disque sélectionné :",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Entrez un nom pour le point de montage (utilisé comme /mnt/<name>) :",
|
||||
"Enter a name for the new virtual machine:": "Entrez un nom pour la nouvelle machine virtuelle :",
|
||||
"Enter a non-empty password or access token on a single line.": "Saisissez un mot de passe non vide ou un jeton d'accès sur une seule ligne.",
|
||||
"Enter a number, or write or paste a command:": "Entrez un nombre, ou écrivez ou collez une commande :",
|
||||
"Enter a systemd calendar event, e.g.:": "Saisissez un événement du calendrier systemd, par exemple :",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Saisissez une adresse IPv4 utilisable avec son préfixe, par exemple",
|
||||
"Enter a valid registry username.": "Saisissez un nom d'utilisateur de registre valide.",
|
||||
"Enter backup file (.zst):": "Entrez le fichier de sauvegarde (.zst) :",
|
||||
"Enter backup path (.tar.zst):": "Entrez le chemin de sauvegarde (.tar.zst) :",
|
||||
"Enter backup path (.vma.zst):": "Entrez le chemin de sauvegarde (.vma.zst) :",
|
||||
@@ -2292,7 +2315,7 @@
|
||||
"Failed to enable ZFS autotrim for pool:": "Échec de l'activation du découpage automatique ZFS pour le pool :",
|
||||
"Failed to enable automatic time synchronization": "Échec de l'activation de la synchronisation automatique de l'heure",
|
||||
"Failed to extract OVA file:": "Échec de l'extraction du fichier OVA :",
|
||||
"Failed to extract a nonempty loader image.": "échec de l'extraction d'une image de chargeur non vide.",
|
||||
"Failed to extract a nonempty loader image.": "Échec de l'extraction d'une image de chargeur non vide.",
|
||||
"Failed to extract package": "Échec de l'extraction du package",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "Échec de la récupération de la clé GPG Google Coral. Vérifier",
|
||||
"Failed to format disk as": "Échec du formatage du disque en tant que",
|
||||
@@ -2347,9 +2370,9 @@
|
||||
"Failed to restart — restart manually to activate mount": "Échec du redémarrage : redémarrez manuellement pour activer le montage",
|
||||
"Failed to restore subscription banner completely": "Échec de la restauration complète de la bannière d'abonnement",
|
||||
"Failed to retrieve Fastfetch download URL.": "Échec de la récupération de l'URL de téléchargement Fastfetch.",
|
||||
"Failed to retrieve loader release metadata.": "échec de la récupération des métadonnées de la version du chargeur.",
|
||||
"Failed to retrieve loader release metadata.": "Échec de la récupération des métadonnées de la version du chargeur.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "Échec de l'exécution du programme d'installation de log2ram. Vérifiez /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "échec de l'enregistrement de l'image du chargeur.",
|
||||
"Failed to save loader image.": "Échec de l'enregistrement de l'image du chargeur.",
|
||||
"Failed to set VM description": "Échec de la définition de la description de la VM",
|
||||
"Failed to set timezone - keeping current settings": "Échec de la définition du fuseau horaire - conservation des paramètres actuels",
|
||||
"Failed to start CT": "Échec du démarrage de CT",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Aide et informations",
|
||||
"Help and Info Commands": "Commandes d'aide et d'informations",
|
||||
"Helper-Scripts logo applied": "Logo Helper-Scripts appliqué",
|
||||
"Helper:": "Aide :",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Caché pour plus de sécurité",
|
||||
"Hidden:": "Caché:",
|
||||
@@ -2778,7 +2802,7 @@
|
||||
"How do you want to add it?": "Comment veux-tu l’ajouter ?",
|
||||
"How do you want to authenticate this backup target?": "Comment souhaitez-vous authentifier cette cible de sauvegarde ?",
|
||||
"How do you want to select the": "Comment voulez-vous sélectionner le",
|
||||
"How do you want to select the HOST folder to mount?": "Comment souhaitez-vous sélectionner le dossier HOST à monter ?",
|
||||
"How do you want to select the HOST folder to mount?": "Comment souhaitez-vous sélectionner le dossier HOST à monter ?",
|
||||
"How do you want to select the NFS server?": "Comment voulez-vous sélectionner le serveur NFS ?",
|
||||
"How do you want to select the Samba server?": "Comment voulez-vous sélectionner le serveur Samba ?",
|
||||
"How do you want to select the folder to export?": "Comment voulez-vous sélectionner le dossier à exporter ?",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Si votre DHCP a une réservation statique pour l'ancien MAC, mettez-la à jour.",
|
||||
"Image": "Image",
|
||||
"Image Source Directory": "Répertoire des sources d'images",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Accès à l’image confirmé.\n\n{reference}\n\nArchitecture : {architecture}\nVersion : {version}\nTaille du téléchargement : {size}\nRésumé : {digest}",
|
||||
"Image cache": "cache d'image",
|
||||
"Image compatibility restored:": "Compatibilité de l'image restaurée :",
|
||||
"Image compatibility verified:": "Compatibilité de l'image vérifiée :",
|
||||
"Image directory:": "Répertoire d'images :",
|
||||
"Image download failed:": "Le téléchargement de l'image a échoué :",
|
||||
"Image downloaded": "Image téléchargée",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Image téléchargée et vérifiée.\n\n{reference}\n\nStockage : {storage}\nTaille des archives : {size}\nArchives : {archive}\n\nAucun conteneur n'a été créé.\nProxMenux supprime les images mises en cache inutilisées après des mises à jour réussies.",
|
||||
"Image file not found:": "Fichier image introuvable :",
|
||||
"Image imported:": "Image importée :",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "La vérification de l'intégrité de l'image a échoué. Le téléchargement partiel a été rejeté ; essayer à nouveau.",
|
||||
"Image integrity verified": "Intégrité de l'image vérifiée",
|
||||
"Image not allowed for the host monitor profile": "Image non autorisée pour le profil du moniteur hôte",
|
||||
"Image reference": "Référence de l'image",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Référence de l'image (par exemple ghcr.io/user/application:latest)",
|
||||
"Image selection was cancelled": "La sélection de l'image a été annulée",
|
||||
"Image that is not in the catalog": "Image ne figurant pas dans le catalogue",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Installez Samba dans CT :",
|
||||
"Install ZFS auto-snapshot": "Installer l'instantané automatique ZFS",
|
||||
"Install a version from the branch the kernel names.": "Installez une version à partir de la branche des noms de noyau.",
|
||||
"Install an image as a native LXC": "Installer une image en tant que LXC natif",
|
||||
"Install an image that is not in the catalog": "Installez une image qui n'est pas dans le catalogue",
|
||||
"Install analysis tools": "Installer des outils d'analyse",
|
||||
"Install and configure": "Installer et configurer",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "Installation terminée mais les pilotes ne sont pas chargés. Un redémarrage peut être nécessaire.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Installation incomplète. Ces conteneurs et leurs données sont conservés:",
|
||||
"Installation log:": "Journal d'installation :",
|
||||
"Installation settings": "Paramètres d'installation",
|
||||
"Installation summary": "Résumé de l'installation",
|
||||
"Installed": "Installé",
|
||||
"Installed at:": "Installé à :",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Chemin de l'hôte non valide & #160;:",
|
||||
"Invalid host-monitor firewall plan": "Plan de pare-feu de moniteur d'hôte invalide",
|
||||
"Invalid image probe descriptor": "Descripteur de la sonde d'image non valide",
|
||||
"Invalid image tag.": "Balise d'image non valide.",
|
||||
"Invalid input": "Entrée invalide",
|
||||
"Invalid internal volume": "Volume interne non valable",
|
||||
"Invalid list:": "Liste non valide:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Demande de suite non valide",
|
||||
"Invalid sysctl value:": "Valeur sysctl non valable:",
|
||||
"Invalid template storage": "Stockage de gabarit non valide",
|
||||
"Invalid template storage name.": "Nom de stockage de modèle non valide.",
|
||||
"Invalid tmpfs options:": "Options non valides:",
|
||||
"Invalid tmpfs path:": "Path tmpfs non valide :",
|
||||
"Invalid tmpfs size:": "Taille de tmpfs non valable:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Écriture Log2RAM programmée tous les",
|
||||
"Log:": "Enregistrer:",
|
||||
"Logged-in users": "Utilisateurs connectés",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "La connexion à {registry} a expiré. Les informations d'identification enregistrées n'ont pas été modifiées.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "La déconnexion de {registry} a expiré. Les informations d'identification du fichier enregistré n'ont pas été modifiées.",
|
||||
"Logrotate optimization completed": "Optimisation de la rotation terminée",
|
||||
"Logrotate service restarted successfully": "Le service Logrotate a redémarré avec succès",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop est un lecteur de musique moderne léger conçu pour fonctionner parfaitement sur l'environnement de bureau GNOME.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Gérer les chemins personnalisés (ajouter/supprimer vos dossiers)",
|
||||
"Manage installed OCI applications": "Gérer les applications OCI installées",
|
||||
"Manage local backup target": "Gérer la cible de sauvegarde locale",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Gérer les registres d’images privés.\nLes informations d'identification enregistrées permettent à ProxMenux d'accéder à vos images privées.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Gérez les comptes de registre en tant que root sur le nœud Proxmox.",
|
||||
"Managed disks must have backup enabled and a valid size": "Les disques gérés doivent avoir une sauvegarde activée et une taille valide",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Gestion des hôtes proxy Nginx avec une interface simple et puissante.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Guide CLI manuel (Gestionnaire de disques et de stockage)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Aucun serveur Samba accessible trouvé.",
|
||||
"No accessible exports found.": "Aucune exportation accessible trouvée.",
|
||||
"No accessible shares found.": "Aucun partage accessible trouvé.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Aucun stockage Proxmox actif n'accepte les archives de modèles OCI.",
|
||||
"No active exports or showmount not available": "Aucune exportation active ou showmount non disponible",
|
||||
"No active session": "Aucune session active",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Aucun abonnement actif et aucun référentiel PVE utilisable. Le mode non interactif ne peut pas modifier les sources APT ; configurez-les dans Nœud > Mises à jour > Dépôts.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Pas de récent",
|
||||
"No recent Samba servers found.": "Aucun serveur Samba récent trouvé.",
|
||||
"No registered OCI containers are available for selection on this host.": "Aucun conteneur OCI enregistré n'est disponible pour la sélection sur cet hôte.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Aucune API de registre n'a été trouvée sur {registry}. Vérifiez le nom d'hôte et le port.",
|
||||
"No restored OCI application is waiting to be recovered.": "Aucune application OCI restaurée n'est en attente de récupération.",
|
||||
"No results": "Aucun résultat",
|
||||
"No routing information found.": "Aucune information de routage trouvée.",
|
||||
@@ -4296,8 +4334,10 @@
|
||||
"Not all shared directories were verified": "Tous les répertoires partagés n'ont pas été vérifiés",
|
||||
"Not an OVH server, skipping RTM installation": "Pas un serveur OVH, sautant l'installation RTM",
|
||||
"Not currently mounted": "Non monté actuellement",
|
||||
"Not currently mounted — skipping umount.": "Non monté actuellement – ignorer umount.",
|
||||
"Not currently mounted — skipping umount.": "Non monté actuellement – ignorer umount.",
|
||||
"Not declared": "Non déclaré",
|
||||
"Not enough free space for the backup": "Pas assez d'espace libre pour la sauvegarde",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Pas assez d’espace libre sur {storage}. Libérez de l'espace ou sélectionnez un autre stockage.",
|
||||
"Not found": "Pas trouvé",
|
||||
"Not found in the OCI archive:": "Non trouvé dans l'archive OCI :",
|
||||
"Not imported:": "Non importé :",
|
||||
@@ -4388,6 +4428,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Seuls les nœuds Intel/AMD DRM, Coral et USB peuvent être adoptés automatiquement",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Seuls les nœuds Intel/AMD DRM, Coral, NPU et USB peuvent être adoptés automatiquement",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Seul un Swarm Docker utilise ces paramètres, donc ils ne sont pas appliqués:",
|
||||
"Only a full sha256 image digest is supported.": "Seul un résumé d'image sha256 complet est pris en charge.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Seule une instance OCI autonome installée peut adopter des modifications externes.",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Seuls les volumes Proxmox sauvegardés peuvent être adoptés",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Ne convertissez en privilèges que si cela est absolument nécessaire pour votre cas d'utilisation.",
|
||||
@@ -4541,6 +4582,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Passthrough peut toujours fonctionner sans fichier ROM.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "Le relais peut fonctionner, mais la fiabilité du démarrage/redémarrage n'est pas garantie.",
|
||||
"Password": "Mot de passe",
|
||||
"Password / access token (image pull permission)": "Mot de passe/jeton d'accès (autorisation d'extraction d'image)",
|
||||
"Password Mismatch": "Incompatibilité de mot de passe",
|
||||
"Password cannot be empty.": "Le mot de passe ne peut pas être vide.",
|
||||
"Password confirmation cannot be empty.": "La confirmation du mot de passe ne peut pas être vide.",
|
||||
@@ -4576,7 +4618,7 @@
|
||||
"Passwords do not match. Please try again.": "Les mots de passe ne correspondent pas. Veuillez réessayer.",
|
||||
"Paste an oci-compose in the terminal": "Coller un oci-compose dans le terminal",
|
||||
"Paste it here and press Ctrl+D on an empty line.": "Collez-le ici et appuyez sur Ctrl+D sur une ligne vide.",
|
||||
"Paste it here and press Ctrl+D.": "collez-le ici et appuyez sur Ctrl+D.",
|
||||
"Paste it here and press Ctrl+D.": "Collez-le ici et appuyez sur Ctrl+D.",
|
||||
"Paste its Compose file in the terminal": "Coller son fichier Composer dans le terminal",
|
||||
"Paste its docker run command in the terminal": "Coller sa commande d'exécution docker dans le terminal",
|
||||
"Paste the UUP Dump URL here": "Collez l'URL de vidage UUP ici",
|
||||
@@ -4806,7 +4848,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux attache des répertoires, pas des fichiers uniques, donc cette image ne peut pas encore être installée.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux peut appliquer des autorisations d'ouverture sur ce répertoire NFS depuis l'hôte afin que le conteneur puisse lire et écrire :",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux peut le remonter avec des autorisations ouvertes afin que n'importe quel LXC puisse lire et écrire.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux ne peut pas installer cette image automatiquement. Importez plutôt son fichier Compose.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux ne peut pas remplacer les autorisations côté serveur NFS de l'hôte.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux n'a pas pu traduire cette image. Essayez d'importer son fichier Compose depuis OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "Personnalisations de ProxMenux supprimées de bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux ne donne pas à un conteneur le système de son hôte.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux ne les installe pas. L'installation demande comment s'y connecter.",
|
||||
@@ -4927,6 +4971,7 @@
|
||||
"Reading SMART data...": "Lecture des données SMART...",
|
||||
"Reading SMART self-test log...": "Lecture du journal d'autotest SMART...",
|
||||
"Reading full SMART report...": "Lecture du rapport SMART complet...",
|
||||
"Reading image metadata. Please wait...": "Lecture des métadonnées de l'image. S'il vous plaît, attendez...",
|
||||
"Real-time Performance Monitoring": "Surveillance du rendement en temps réel",
|
||||
"Real-time bandwidth usage (press q to exit)": "Utilisation de la bande passante en temps réel (appuyez sur q pour quitter)",
|
||||
"Real-time collaborative document editor": "Éditeur de document collaboratif en temps réel",
|
||||
@@ -5019,6 +5064,9 @@
|
||||
"Register mount path in Proxmox:": "Enregistrez le chemin de montage dans Proxmox :",
|
||||
"Registering disk as Proxmox storage...": "Enregistrement du disque en tant que stockage Proxmox...",
|
||||
"Registering module with DKMS...": "Module d'enregistrement avec DKMS...",
|
||||
"Registry accounts": "Comptes de registre",
|
||||
"Registry hostname": "Nom d'hôte du registre",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Registre : {registry}\nCompte : {account}\nAuthentification : {method}\n\nLes informations d'identification enregistrées sont vérifiées lors de l'accès à une image.",
|
||||
"Reinstall / update Coral drivers": "Réinstaller/mettre à jour les pilotes Coral",
|
||||
"Reinstall Fail2Ban": "Réinstaller Fail2Ban",
|
||||
"Reinstall Lynis": "Réinstaller Lynis",
|
||||
@@ -5090,8 +5138,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Supprimer le méta-paquet systemd-boot obsolète",
|
||||
"Remove old repository files:": "Supprimez les anciens fichiers du référentiel :",
|
||||
"Remove passthrough device from VM": "Supprimer le périphérique relais de la VM",
|
||||
"Remove saved credentials": "Supprimer les informations d'identification enregistrées",
|
||||
"Remove subscription banner": "Supprimer la bannière d'abonnement",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Supprimer l'application ?Ses disques conteneurs sont supprimés et seule une sauvegarde peut les restaurer.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Supprimer les informations d'identification enregistrées pour {registry} ?\nLes applications en cours d’exécution continueront de fonctionner.",
|
||||
"Remove the unprivileged flag from configuration:": "Supprimez l'indicateur sans privilèges de la configuration :",
|
||||
"Remove unused packages and their config": "Supprimer les packages inutilisés et leur configuration",
|
||||
"Remove: delete the application and its containers": "Supprimer: supprimer l'application et ses conteneurs",
|
||||
@@ -5413,6 +5463,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Enregistrer et classer les articles. Lisez-les plus tard. Gratuitement.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Enregistrez la phrase secrète dans un endroit sûr MAINTENANT, avant de continuer.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Enregistrer cette cible Borg pour ne pas avoir à saisir à nouveau les détails ?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Les informations d'identification enregistrées pour {registry} ont été supprimées.\nLes autres fichiers d'informations d'identification Skopeo/Docker sont gérés séparément.",
|
||||
"Saved record removed": "Enregistrement supprimé",
|
||||
"Saving changes...": "Enregistrer les modifications...",
|
||||
"Saving the new configuration": "Enregistrement de la nouvelle configuration",
|
||||
@@ -5793,9 +5844,11 @@
|
||||
"Shutdown timeout": "Délai d'arrêt",
|
||||
"SiYuan access code": "Code d'accès SiYuan",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear assure la gestion d'émissions TV et/ou Anime, détecte de nouveaux épisodes, links downloader apps, etc.",
|
||||
"Sign in to a registry": "Connectez-vous à un registre",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Connectez-vous au panneau et créez un utilisateur Samba dans Paramètres avant de publier un répertoire via SMB.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal est une application de messagerie avec la confidentialité à son cœur. Il est gratuit et facile à utiliser, avec un cryptage de bout en bout fort qui maintient votre communication complètement privée.",
|
||||
"Signatures removed. Partition table preserved.": "Signatures supprimées. Table de partition conservée.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Connecté à {registry} en tant que {username}.\n\nLes informations d'identification sont enregistrées pour ProxMenux.\nSélectionnez le compte pour vérifier, télécharger ou installer une image.",
|
||||
"Simple and easy to use DDNS": "Simple et facile à utiliser DDNS",
|
||||
"Single GPU Warning": "Avertissement sur un seul GPU",
|
||||
"Single target found — selected automatically:": "Cible unique trouvée — sélectionnée automatiquement :",
|
||||
@@ -5821,6 +5874,8 @@
|
||||
"Skipping SR-IOV device": "Ignorer le périphérique SR-IOV",
|
||||
"Skipping installation.": "Sauter l'installation.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Ignorer les correctifs manuels — feranick fork prend déjà en charge ce noyau.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo n’est pas disponible. Restaurez les dépendances ProxMenux OCI et réessayez.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo a renvoyé un fichier d'informations d'identification invalide ; les informations d'identification enregistrées n'ont pas été modifiées.",
|
||||
"Sleek podcast downloader with GPodder sync": "Téléchargeur de podcast Sleek avec synchronisation GPodder",
|
||||
"Smart restore plan — hardware compatibility check": "Plan de restauration intelligent – vérification de la compatibilité matérielle",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping suit votre latence réseau. Pour un exemple complet de ce que cette application est capable de visiter UCDavis.",
|
||||
@@ -6078,6 +6133,7 @@
|
||||
"TCP optimizations configuration completed": "Configuration des optimisations TCP terminée",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "Optimisations TCP annulées (valeurs par défaut restaurées au prochain redémarrage)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "Le port TCP 5201 est accessible (pare-feu sur le serveur)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "La vérification TLS a échoué pour {registry}. Installez l'autorité de certification de registre dans /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "Périphérique TPM ajouté à la VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "La sélection du stockage TPM a échoué ou a été annulée. Création de VM abandonnée.",
|
||||
"TROUBLESHOOTING:": "DÉPANNAGE :",
|
||||
@@ -6270,6 +6326,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "La configuration doit fonctionner comme racine sur Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "La configuration d'un nouveau membre a changé après sa création",
|
||||
"The configuration stopped because of an unexpected error": "La configuration s'est arrêtée en raison d'une erreur inattendue",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "L'assistant d'identification configuré n'a pas pu être utilisé. Vérifiez son installation et son magasin d’informations d’identification.",
|
||||
"The console of the container could not be configured": "La console du conteneur n'a pas pu être configurée",
|
||||
"The consume/export volumes need at least 1 GB": "Les volumes de consommation/exportation nécessitent au moins 1 Go",
|
||||
"The container could not be removed automatically:": "Le conteneur n'a pas pu être enlevé automatiquement:",
|
||||
@@ -6308,6 +6365,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Les conteneurs n'en ont plus besoin ; une mise à jour télécharge les nouvelles versions quand il y en a.",
|
||||
"The containers were created from downloaded OCI images": "Les conteneurs ont été créés à partir d'images OCI téléchargées",
|
||||
"The coordinated backup was modified": "La sauvegarde coordonnée a été modifiée",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "Le fichier d'informations d'identification a été modifié au cours de cette opération. Essayer à nouveau; il n'a pas été écrasé.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "Le pilote actuel sera complètement désinstallé avant d'installer la nouvelle version. Continuer?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "L'image actuelle du canal sauvegardé sera vérifiée et téléchargée. Les ressources, les chemins et le GPU sont conservés. Le CT est arrêté pendant le remplacement et une sauvegarde native est créée en premier.",
|
||||
"The current record is missing for": "L'enregistrement actuel manque pour",
|
||||
@@ -6390,7 +6448,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "Le sous-réseau du pare-feu du moniteur hôte a été modifié ;aucune règle de pare-feu n'a été ajoutée",
|
||||
"The host-monitor web interface uses the host network.": "L'interface Web hôte-moniteur utilise le réseau hôte.",
|
||||
"The identity of a member was replaced": "L'identité d'un membre a été remplacée",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "Le chemin du cache d’images n’est pas sécurisé. Vérifiez le stockage du modèle avant de réessayer.",
|
||||
"The image changes the user expected by the adapter": "L'image change l'utilisateur attendu par l'adaptateur",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "L'image n'a pas pu être téléchargée ou vérifiée. Vérifiez l'accès au registre et au stockage, puis réessayez.",
|
||||
"The image could not be read from its registry:": "L'image n'a pas pu être lue depuis son registre :",
|
||||
"The image declares data paths that are still stored in the rootfs": "L'image déclare les chemins de données qui sont encore stockés dans les rootfs",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "L'image n'a pas permis à l'utilisateur de l'application d'accéder aux appareils; vérifiez son init natif. Les permissions de l'hôte n'étaient pas détendues.",
|
||||
@@ -6403,6 +6463,8 @@
|
||||
"The image is in its registry, for one architecture.": "L'image est dans son registre, pour une architecture.",
|
||||
"The image is in its registry.": "L'image est dans son registre.",
|
||||
"The image is in its registry:": "L'image est dans son registre:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "La vérification de l'intégrité du manifeste de l'image a échoué. Réessayez ou contactez l'éditeur d'images.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "L'image ou la balise est introuvable sur {registry}, ou ce compte ne peut pas y accéder. Vérifiez la référence.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "L'image demande NVIDIA, mais l'hôte n'a pas de pilote NVIDIA fonctionnant",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "L'image demande l'invalidation d'une partie de l'AppArmor ou du confinement de seccomp. Continuez seulement si vous faites confiance à l'image et acceptez ce risque.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "L'image demande l'invalidation d'une partie de l'AppArmor ou du confinement de seccomp. Le Compose offre une relaxation en option AppArmor ou seccomp ; il restera désactivé à moins que l'utilisateur le sélectionne. Continuez seulement si vous faites confiance à l'image et acceptez ce risque.",
|
||||
@@ -6540,7 +6602,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "Le dossier ou le diagnostic n'a pu être complété; aucune mise à jour n'a été effectuée.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "La récupération n'est pas terminée. Passez en revue le journal et choisissez « Recover » pour ce conteneur dans le menu de gestion OCI.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "La restauration ne s'est pas terminée. Consultez le journal et choisissez de nouveau « {choice} » pour ce conteneur dans le menu de gestion OCI.",
|
||||
"The registry authentication file is invalid; it was not changed.": "Le fichier d'authentification du registre n'est pas valide ; cela n'a pas été changé.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "Le fichier d'authentification du registre doit appartenir à root avec le mode 600.",
|
||||
"The registry authentication file must have an absolute path.": "Le fichier d’authentification du registre doit avoir un chemin absolu.",
|
||||
"The registry authentication path cannot contain symbolic links.": "Le chemin d’authentification du registre ne peut pas contenir de liens symboliques.",
|
||||
"The registry authentication path has an unsafe parent directory.": "Le chemin d'authentification du registre possède un répertoire parent non sécurisé.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "Le répertoire des informations d'identification du registre doit appartenir à root avec le mode 700.",
|
||||
"The registry did not return the saved image digest": "Le registre n'a pas renvoyé le digest d'image enregistré",
|
||||
"The registry returned incomplete or unsupported image metadata.": "Le registre a renvoyé des métadonnées d'image incomplètes ou non prises en charge.",
|
||||
"The registry returned invalid or unsupported image metadata.": "Le registre a renvoyé des métadonnées d'image invalides ou non prises en charge.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "La télécommande n'existe pas; créez et autorisez-la d'abord dans le WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "L'installateur distant doit fonctionner comme root sur Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "La télécommande doit déjà être créée et autorisée dans l'interface web Rclone. Ce operation redémarre le CT et publie deux vues FUSE sur l'hôte.",
|
||||
@@ -6699,6 +6769,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Ce GPU est considéré comme incompatible avec le relais GPU vers une VM dans ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Ce partage NFS est entièrement restreint : même la racine de l'hôte ne peut pas y écrire.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Cette VM nécessite des étapes d'installation supplémentaires. Consultez le guide d'installation à l'adresse :\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Ce compte concerne {registry}. Entrez une image de ce registre.",
|
||||
"This action will:": "Cette action va :",
|
||||
"This application cannot be recovered yet:": "Cette application ne peut pas encore être récupérée :",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Cette application ne peut pas encore être récupérée ; rien n'a été changé :",
|
||||
@@ -6730,8 +6801,10 @@
|
||||
"This explicitly marks the container as privileged": "Cela marque explicitement le conteneur comme privilégié",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Ce fichier décide de ce qui est monté et avec quels privilèges. Installez-le uniquement s'il provient d'une source de confiance.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Cela garantit que les nœuds de périphérique sont disponibles avant d'appliquer la configuration GPU LXC.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Cette architecture hôte n'est pas prise en charge par l'importateur d'images OCI.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Cet hôte n'a pas d'abonnement actif, passer au référentiel sans abonnement ? La source PVE Enterprise, inaccessible, sera désactivée. Les sources Ceph Enterprise, si elles sont présentes, seront désactivées sans choisir de canal Ceph de remplacement ; configurez Ceph séparément si nécessaire.",
|
||||
"This image cannot be installed as it is described:": "Cette image ne peut pas être installée comme elle est décrite :",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Cette image n'a pas d'image Linux compatible pour cet hôte ({architecture}).",
|
||||
"This image requires the host module": "Cette image requirese le module hôte",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Cette importation rejette ces chemins sans vérifier s'il s'agit de fichiers ou de répertoires.",
|
||||
"This installation will:": "Cette installation va :",
|
||||
@@ -6847,6 +6920,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Pour utiliser à nouveau le GPU dans LXC, exécutez Ajouter un GPU à LXC à partir des GPU et du menu Coral-TPU",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Pour utiliser la VM sans problème, l'hôte doit être redémarré avant de le démarrer.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Pour utiliser ce partage à partir d'un LXC, montez-le via :",
|
||||
"Token": "Jeton",
|
||||
"Tool exit code:": "Code de sortie de l'outil :",
|
||||
"Tool output:": "Sortie de l'outil :",
|
||||
"Tools": "Outils",
|
||||
@@ -6991,6 +7065,7 @@
|
||||
"Unsafe private configuration path": "Voie de configuration privée non sûre",
|
||||
"Unsafe qBittorrent configuration path": "Path de configuration qBittorrent non sûr",
|
||||
"Unsafe record": "Enregistrement non sûr",
|
||||
"Unsafe registry credential lock.": "Verrouillage dangereux des informations d’identification du registre.",
|
||||
"Unsafe registry directory": "Répertoire de registre non sûr",
|
||||
"Unsafe registry lock": "Verrouillage du registre non sûr",
|
||||
"Unsafe rootfs for the capture": "Des rootfs non sûrs pour la capture",
|
||||
@@ -7003,6 +7078,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Profil OCI-LXC AppArmor non soutenu :",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Profil de seccomp OCI-LXC non pris en charge:",
|
||||
"Unsupported Terminal": "Terminal non pris en charge",
|
||||
"Unsupported architecture for Figurine:": "Architecture non prise en charge pour Figurine :",
|
||||
"Unsupported architecture:": "Architecture non supportée :",
|
||||
"Unsupported backup compression": "compression de sauvegarde non prise en charge",
|
||||
"Unsupported credential pattern:": "Modèle credential non pris en charge:",
|
||||
@@ -7055,6 +7131,7 @@
|
||||
"Update cancelled by user": "Mise à jour annulée par l'utilisateur",
|
||||
"Update completed. Data kept.": "Mise à jour terminée. Données conservées.",
|
||||
"Update completed. Press Enter to continue...": "Mise à jour terminée. Appuyez sur Entrée pour continuer...",
|
||||
"Update credentials": "Mettre à jour les informations d'identification",
|
||||
"Update every container of the application": "Mettre à jour chaque conteneur de l'application",
|
||||
"Update kernel to compatible version": "Mettre à jour le noyau vers une version compatible",
|
||||
"Update now?": "Mise à jour ?",
|
||||
@@ -7121,8 +7198,10 @@
|
||||
"Use a custom path": "utiliser un chemin personnalisé",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Utilisez un LXC privilégié pour les workflows serveur/client NFS.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Utilisez un LXC privilégié pour les workflows client/serveur Samba.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Utilisez un nom d'hôte de registre, par exemple ghcr.io ou registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Utiliser un fichier de clé privée SSH existant sur cet hôte",
|
||||
"Use an existing keyfile": "utiliser un fichier de clés existant",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Utilisez une référence d'image, par exemple ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Utiliser tel quel – conserver les données et le système de fichiers",
|
||||
"Use content types according to your use case.": "Utilisez les types de contenu en fonction de votre cas d'utilisation.",
|
||||
"Use default": "utiliser la valeur par défaut",
|
||||
@@ -7162,6 +7241,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "WebUI convivial pour les LLM (anciennement Ollama WebUI)",
|
||||
"Username": "Nom d'utilisateur",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Nom d'utilisateur (par exemple root@pam ou user@pbs!token) :",
|
||||
"Username / token": "Nom d'utilisateur / jeton",
|
||||
"Username and password": "Nom d'utilisateur et mot de passe",
|
||||
"Username and password will be cleared.": "Le nom d'utilisateur et le mot de passe seront effacés.",
|
||||
"Username cannot be empty.": "Le nom d'utilisateur ne peut pas être vide.",
|
||||
@@ -7261,6 +7341,7 @@
|
||||
"Verifying Ceph packages availability...": "Vérification de la disponibilité des packages Ceph...",
|
||||
"Verifying all utilities status": "Vérification de l'état de tous les utilitaires",
|
||||
"Verifying disk accessibility in CT": "Vérification de l'accessibilité du disque dans CT",
|
||||
"Verifying registry access. Please wait...": "Vérification de l'accès au registre. S'il vous plaît, attendez...",
|
||||
"Verifying the backups...": "Vérifier les sauvegardes...",
|
||||
"Verifying the image integrity...": "Vérifier l'intégrité de l'image...",
|
||||
"Version": "Version",
|
||||
@@ -7560,6 +7641,7 @@
|
||||
"assembling": "assemblage",
|
||||
"automatically. Install it manually inside the container.": "automatiquement. Installez-le manuellement à l'intérieur du conteneur.",
|
||||
"automatically. Reboot LXC to fully release.": "automatiquement. Redémarrez LXC pour le libérer complètement.",
|
||||
"available": "Disponible",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "disponible pour les montages liés LXC via 'LXC Mount Manager'",
|
||||
"available in this same GPU and TPU menu.": "disponible dans ce même menu GPU et TPU.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "sauvegarde sur /etc/fstab.proxmenux.bak",
|
||||
@@ -7912,6 +7994,7 @@
|
||||
"runs in": "cours d'eau",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "chemins sécurisés maintenant (configurations, packages, /etc, /root, ...)",
|
||||
"same MAC": "même MAC",
|
||||
"saved": "Enregistré",
|
||||
"seconds (default)": "secondes (par défaut)",
|
||||
"see log:": "voir le journal :",
|
||||
"selected by default": "sélectionné par défaut",
|
||||
@@ -8030,8 +8113,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot supprimé (instantanés existants conservés sur le pool)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "Commande zpool introuvable. Installez zfsutils-linux et réessayez.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool introuvable. Installez zfsutils-linux et réessayez.",
|
||||
"{count} saved account.": "Compte enregistré {count}.",
|
||||
"{count} saved accounts.": "Comptes enregistrés {count}.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} existe déjà et appartient à un autre utilisateur de l'hôte, donc {app} ne peut pas y écrire.\n\nProxMenux peut ajouter des règles d'accès (ACL) à ce répertoire, à tout ce qu'il contient et à ce qui y sera créé ensuite, pour les utilisateurs et les groupes sous lesquels {app} s'exécute sur l'hôte (ID {ids}). Le propriétaire des fichiers ne change pas et ce qui les lit ou les écrit aujourd'hui continue de le faire ; le propriétaire du répertoire a également accès aux fichiers créés par {app}.\n\nAccorder à {app} l'accès à ce répertoire ?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} existe déjà et appartient à un autre utilisateur de l'hôte, donc {app} ne peut pas y écrire.\n\nProxMenux peut ajouter une règle d'accès (ACL) pour l'identité que {app} utilise sur l'hôte (UID {uid}).Rien de ce qui s'y trouve ne change le propriétaire ou les autorisations : tout ce qui lit ou écrit ces fichiers aujourd'hui continue de le faire, et le propriétaire du répertoire a également accès aux fichiers créés par {app}.\n\nAccorder à {app} l'accès à ce répertoire ?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} a répondu avec HTTP simple. Utilisez un registre avec HTTPS ; La vérification TLS reste activée.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} n'a pas répondu dans les secondes {timeout}. Réessayez plus tard.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "{registry} correspond aux requêtes de limitation de débit. Attendez un peu et réessayez.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} a refusé l'accès à cette image :\n{reference}\n\nSi l'image est privée, connectez-vous avec un compte capable de l'extraire.\n\nConnectez-vous maintenant ?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} a signalé une erreur de serveur. Réessayez plus tard.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} a renvoyé des métadonnées d'image non valides ou non prises en charge.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "— La restauration complète/personnalisée ignorera les chemins liés au noyau",
|
||||
"— disk may be busy. Skipping fstab removal.": "— le disque est peut-être occupé. Ignorer la suppression de fstab.",
|
||||
"— restore proceeds as same-version (verified safe)": "— restaurer le produit avec la même version (coffre-fort vérifié)",
|
||||
|
||||
+98
-7
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Bridge di accesso per Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "Non è stato possibile concedere completamente l'accesso; l'applicazione potrebbe non riuscire a scrivere a:",
|
||||
"Access could not be granted; the application cannot write to:": "Impossibile concedere l'accesso; l'applicazione non può scrivere a:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Accesso negato da {registry}. Controlla il nome dell'immagine e accedi dagli account del Registro.",
|
||||
"Access granted to the application on:": "Accesso concesso all'applicazione a:",
|
||||
"Access password of the web interface (optional)": "Password di accesso all'interfaccia web (facoltativa)",
|
||||
"Access profile:": "Profilo di accesso:",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Avanzato",
|
||||
"Advanced Diagnostics": "Diagnostica avanzata",
|
||||
"Advanced Network Diagnostics": "Diagnostica di rete avanzata",
|
||||
"Advanced settings": "Impostazioni avanzate",
|
||||
"Advanced: every setting of the container": "Avanzata: tutte le impostazioni del container",
|
||||
"Affected LXC containers": "Container LXC interessati",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Dopo aver completato la configurazione della GPU, avvia manualmente la VM quando l'host è pronto.",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Un'altra operazione OCI sta utilizzando il registro delle istanze. Attendere che termini e riaprire questo menu; nessun container è stato modificato.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Un’altra operazione OCI sta utilizzando il registro delle istanze. Attendi che termini.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Un’altra operazione OCI sta utilizzando il registro. Questa operazione non è stata avviata.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "È in esecuzione un'altra operazione ProxMenux OCI. Riprovare al termine.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Esiste un'altra configurazione ZRAM o non è possibile controllarla; systemd-zram-generator è stato mantenuto",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Esiste un'altra configurazione del generatore ZRAM; rifiutandosi di sovrascriverlo:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Esiste un'altra configurazione di scambio ZRAM; rifiutandosi di sostituirlo:",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Un'altra istanza usa",
|
||||
"Another job that writes to the same storage still starts them.": "Un altro job che scrive sullo stesso storage continua ad avviarli.",
|
||||
"Another node, typed by hand": "Altro nodo di dispositivo (manuale)",
|
||||
"Another registry account operation is running. Try again when it finishes.": "È in esecuzione un'altra operazione sull'account del registro. Riprovare al termine.",
|
||||
"Another stack operation is pending": "È in sospeso un'altra operazione sullo stack",
|
||||
"Application": "Applicazione",
|
||||
"Application registered on this host:": "Applicazione registrata su questo host:",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Autenticazione",
|
||||
"Authentication & Security": "Autenticazione e sicurezza",
|
||||
"Authentication Error": "Errore di autenticazione",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Messaggio tecnico per Proxmox e IT. Traduzione: autenticazione non riuscita per {registry}. Controlla le autorizzazioni dell'account e del token.",
|
||||
"Authentication failed.": "Autenticazione non riuscita.",
|
||||
"Authentication required:": "Autenticazione richiesta:",
|
||||
"Authentication:": "Autenticazione:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Impossibile determinare la directory home del container:",
|
||||
"Cannot validate credentials - no shares available for testing.": "Impossibile convalidare le credenziali: nessuna condivisione disponibile per il test.",
|
||||
"Cannot verify the reused disk:": "Impossibile verificare il disco riutilizzato:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Impossibile scrivere l'archivio immagini su {storage}. Controlla l'accesso allo spazio di archiviazione e lo stato di montaggio.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Non è possibile conservare alcune capability e rimuoverle tutte contemporaneamente",
|
||||
"Category": "Categoria",
|
||||
"Caution: Maximum mode generates more heat.": "Attenzione: la modalità massima genera più calore.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Controlla stato Samba",
|
||||
"Check VM disk/PCI slots": "Controlla gli slot disco/PCI della VM",
|
||||
"Check VM passthrough settings": "Controlla impostazioni passthrough VM",
|
||||
"Check access to an image": "Controlla l'accesso a un'immagine",
|
||||
"Check connectivity with another host": "Controlla la connettività con un altro host",
|
||||
"Check container mount points": "Controlla i punti di montaggio del container",
|
||||
"Check if container is unprivileged:": "Controlla se il container non è privilegiato:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Controlla che:",
|
||||
"Check the error messages above for details.": "Controlla i messaggi di errore qui sopra per i dettagli.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Controllare il riferimento dell'immagine e l'accesso al registro. Se il registro non è disponibile, riprovare più tardi. Un registro privato richiede credenziali, che non sono ancora supportate.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Controlla il riferimento all'immagine e l'accesso al registro. Se il registro non è disponibile, riprova più tardi. Per un'immagine privata, accedi dagli account del Registro nel menu OCI.",
|
||||
"Check the service status manually if needed.": "Controlla manualmente lo stato del servizio, se necessario.",
|
||||
"Checking MOTD configuration...": "Controllo della configurazione MOTD...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Controllo dello stato del driver NVIDIA con nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Controllo dello spazio libero in /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Verifica se il disco di sistema è SSD o M.2...",
|
||||
"Checking if the server belongs to OVH...": "Verifica se il server appartiene a OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Controllo dell'accesso alle immagini e dei metadati. Attendere prego...",
|
||||
"Checking kernel headers and build tools...": "Controllo delle intestazioni kernel e degli strumenti di compilazione...",
|
||||
"Checking remaining interfaces": "Controllo delle interfacce rimanenti",
|
||||
"Checking that the container keeps running...": "Controllo che il container rimanga in esecuzione...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Scegli la modalità iperf3:",
|
||||
"Choose options to configure:": "Scegli le opzioni da configurare:",
|
||||
"Choose specific VMs/CTs": "Scegli VM/CT specifici",
|
||||
"Choose storage for the downloaded image.": "Scegli lo spazio di archiviazione per l'immagine scaricata.",
|
||||
"Choose the driver version for Coral M.2:": "Scegli la versione del driver per Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Scegli il filesystem per la nuova partizione:",
|
||||
"Choose the release channel to use:": "Scegli il canale di rilascio da usare:",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "Impossibile pubblicare il ripristino in sospeso. Il precedente ripristino in sospeso è stato mantenuto.",
|
||||
"Could not push the key. Check the password and that": "Impossibile trasferire la chiave. Controlla la password e verifica che",
|
||||
"Could not query the image registry": "Impossibile interrogare il registro delle immagini",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "Impossibile raggiungere {registry}. Controlla il suo indirizzo, DNS e accesso alla rete.",
|
||||
"Could not read SMART data from": "Impossibile leggere i dati SMART da",
|
||||
"Could not read VM configuration.": "Impossibile leggere la configurazione della VM.",
|
||||
"Could not read the CUDA compute capability": "Impossibile leggere la compute capability CUDA",
|
||||
"Could not read the NVIDIA driver version": "Impossibile leggere la versione del driver NVIDIA",
|
||||
"Could not read the host firewall rules": "Impossibile leggere le regole del firewall dell’host",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Impossibile leggere l'immagine da {registry}. Controlla il riferimento e accedi dagli account del Registro.",
|
||||
"Could not read this job.": "Impossibile leggere questo job.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "Impossibile rilasciare le pagine ZRAM; il profilo esistente rimane attivo",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Impossibile rimontare automaticamente. Prova manualmente o controlla le credenziali.",
|
||||
"Could not remove VM automatically. Run manually:": "Impossibile rimuovere la VM automaticamente. Esegui manualmente:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "Impossibile rimuovere il profilo ZRAM; la configurazione è stata ripristinata",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "Impossibile rimuovere il profilo ZRAM; la configurazione è stata ripristinata ma non è stato possibile riavviare lo scambio",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Messaggio tecnico per Proxmox e IT. Traduzione: impossibile rimuovere le credenziali per {registry}; le credenziali del file salvato non sono state modificate.",
|
||||
"Could not remove previous DKMS tree at": "Impossibile rimuovere l'albero DKMS precedente in",
|
||||
"Could not reserve a private network for the stack": "Impossibile riservare una rete privata per lo stack",
|
||||
"Could not resolve the Compose user:": "Impossibile risolvere l’utente Compose:",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Impossibile impostare il display virtuale della VM su vga: std",
|
||||
"Could not set boot order for": "Impossibile impostare l'ordine di avvio per",
|
||||
"Could not set the container entrypoint": "Impossibile impostare l'entrypoint del container",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Impossibile accedere a {registry}. Controlla l'accesso al registro e le autorizzazioni del token.",
|
||||
"Could not stage pending restore path:": "Impossibile preparare il percorso di ripristino in sospeso:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "Impossibile preparare il ripristino in sospeso. Non è stato pianificato nulla di nuovo.",
|
||||
"Could not stop LXC": "Impossibile fermare LXC",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Creazione rete privata...",
|
||||
"Creating the temporary data container": "Creazione del container temporaneo per i dati",
|
||||
"Creative & Design": "Creatività e design",
|
||||
"Credential helper": "Assistente credenziali",
|
||||
"Credential storage and access": "Archiviazione e accesso alle credenziali",
|
||||
"Credentials are correct": "Le credenziali sono corrette",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Credenziali cancellate. jwt_secret e token API conservati.",
|
||||
"Credentials file created securely.": "File delle credenziali creato in sicurezza.",
|
||||
"Credentials file removed.": "File delle credenziali rimosso.",
|
||||
"Credentials file:": "File delle credenziali:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "File delle credenziali:\n{path}\n\nDi proprietà di root; modalità directory 700 e modalità file 600.\nLe credenziali di base sono codificate base64, non crittografate.\nGli helper credenziali utilizzano il proprio spazio di archiviazione.\n\nUtilizza un token di accesso con l'autorizzazione per estrarre le immagini.\nConfigura le credenziali su ciascun nodo che scarica le immagini.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "File delle credenziali:\n{path}\n\nDi proprietà di root; modalità directory 700 e modalità file 600.\nLe credenziali di base sono codificate base64, non crittografate.\nGli helper credenziali utilizzano il proprio spazio di archiviazione.\n\nUtilizza un token di accesso con l'autorizzazione per estrarre le immagini.\nOgni nodo del cluster utilizza gli account salvati qui.",
|
||||
"Credentials validated successfully": "Credenziali convalidate correttamente",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Ripristino tra host: gli ID guest nel backup si sovrappongono agli ID presenti sulla destinazione:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Ripristino tra kernel diversi: percorsi legati al kernel uniti, non copiati",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Accesso predefinito",
|
||||
"Default options": "Opzioni predefinite",
|
||||
"Default options read/write": "Opzioni predefinite di lettura/scrittura",
|
||||
"Default settings": "Impostazioni predefinite",
|
||||
"Default will be used:": "Sarà usato il valore predefinito:",
|
||||
"Default:": "Predefinito:",
|
||||
"Default: only what the application needs": "Predefinita: solo ciò che serve all’applicazione",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs è un bot Discord scritto in Rust per richiedere contenuti multimediali tramite i backend *arr.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander è un file manager gratuito, open source e multipiattaforma con due pannelli affiancati. Si ispira a Total Commander e introduce alcune nuove idee.",
|
||||
"Download Spotify music with album art and metadata": "Scarica musica da Spotify con copertine album e metadati",
|
||||
"Download an image to template storage": "Scarica un'immagine nella memoria del modello",
|
||||
"Download an oci-compose from an address": "Scarica un oci-compose da un indirizzo",
|
||||
"Download failed for all attempted URLs": "Download non riuscito per tutti gli URL tentati",
|
||||
"Download its Compose file from an address": "Scarica il file Compose da un indirizzo",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Download del logo Proxmology...",
|
||||
"Downloading UUP converter...": "Download del convertitore UUP...",
|
||||
"Downloading amdgpu_top": "Download di amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Download e verifica dell'immagine.\nL'operazione può richiedere alcuni minuti. Attendere prego...",
|
||||
"Downloading official installer...": "Download del programma di installazione ufficiale...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "Il download di backup crittografati preesistenti da questo host fallirà a meno che tu non abbia conservato una copia della chiave corrente.",
|
||||
"Downloading the image:": "Download dell'immagine:",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Inserisci il nome del pool ZFS per il disco selezionato:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Inserisci un nome per il punto di montaggio (usato come /mnt/<name>):",
|
||||
"Enter a name for the new virtual machine:": "Inserisci un nome per la nuova VM:",
|
||||
"Enter a non-empty password or access token on a single line.": "Inserisci una password non vuota o un token di accesso su una singola riga.",
|
||||
"Enter a number, or write or paste a command:": "Inserisci un numero o scrivi o incolla un comando:",
|
||||
"Enter a systemd calendar event, e.g.:": "Inserisci un evento di calendario systemd, ad esempio:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Inserisci un indirizzo IPv4 utilizzabile con il suo prefisso, per esempio",
|
||||
"Enter a valid registry username.": "Inserisci un nome utente di registro valido.",
|
||||
"Enter backup file (.zst):": "Inserisci file backup (.zst):",
|
||||
"Enter backup path (.tar.zst):": "Inserisci percorso backup (.tar.zst):",
|
||||
"Enter backup path (.vma.zst):": "Inserisci percorso backup (.vma.zst):",
|
||||
@@ -2287,12 +2310,12 @@
|
||||
"Failed to download Proxmology logo": "Impossibile scaricare il logo Proxmology",
|
||||
"Failed to download VirtIO driver ISO.": "Impossibile scaricare l'ISO del driver VirtIO.",
|
||||
"Failed to download amdgpu_top": "Impossibile scaricare amdgpu_top",
|
||||
"Failed to download loader image.": "impossibile scaricare l'immagine del caricatore.",
|
||||
"Failed to download loader image.": "Impossibile scaricare l'immagine del loader.",
|
||||
"Failed to edit /etc/fstab — remove the line manually.": "Impossibile modificare /etc/fstab: rimuovi la riga manualmente.",
|
||||
"Failed to enable ZFS autotrim for pool:": "Impossibile abilitare ZFS autotrim per il pool:",
|
||||
"Failed to enable automatic time synchronization": "Impossibile abilitare la sincronizzazione automatica dell'ora",
|
||||
"Failed to extract OVA file:": "Impossibile estrarre il file OVA:",
|
||||
"Failed to extract a nonempty loader image.": "impossibile estrarre un'immagine del caricatore non vuota.",
|
||||
"Failed to extract a nonempty loader image.": "Impossibile estrarre un'immagine del loader non vuota.",
|
||||
"Failed to extract package": "Impossibile estrarre il pacchetto",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "Impossibile recuperare la chiave GPG di Google Coral. Controlla",
|
||||
"Failed to format disk as": "Impossibile formattare il disco come",
|
||||
@@ -2329,7 +2352,7 @@
|
||||
"Failed to mount container filesystem.": "Impossibile montare il filesystem del container.",
|
||||
"Failed to mount disk": "Impossibile montare il disco",
|
||||
"Failed to obtain public IP address - keeping current timezone settings": "Impossibile ottenere l'indirizzo IP pubblico: impostazioni attuali del fuso orario mantenute",
|
||||
"Failed to prepare loader download directory.": "impossibile preparare la directory di download del caricatore.",
|
||||
"Failed to prepare loader download directory.": "Impossibile preparare la directory di download del loader.",
|
||||
"Failed to reconcile conflicting ZFS ARC settings.": "Impossibile correggere le impostazioni ZFS ARC in conflitto.",
|
||||
"Failed to refresh boot configuration": "Impossibile aggiornare la configurazione di avvio",
|
||||
"Failed to refresh proxmox-boot-tool": "Impossibile aggiornare proxmox-boot-tool",
|
||||
@@ -2347,9 +2370,9 @@
|
||||
"Failed to restart — restart manually to activate mount": "Impossibile riavviare: riavvia manualmente per attivare il montaggio",
|
||||
"Failed to restore subscription banner completely": "Impossibile ripristinare completamente il banner di abbonamento",
|
||||
"Failed to retrieve Fastfetch download URL.": "Impossibile recuperare l'URL di download di Fastfetch.",
|
||||
"Failed to retrieve loader release metadata.": "impossibile recuperare i metadati della versione del caricatore.",
|
||||
"Failed to retrieve loader release metadata.": "Impossibile recuperare i metadati della versione del loader.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "Impossibile eseguire l’installer log2ram. Controlla /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "impossibile salvare l'immagine del caricatore.",
|
||||
"Failed to save loader image.": "Impossibile salvare l'immagine del loader.",
|
||||
"Failed to set VM description": "Impossibile impostare la descrizione della VM",
|
||||
"Failed to set timezone - keeping current settings": "Impossibile impostare il fuso orario: impostazioni attuali mantenute",
|
||||
"Failed to start CT": "Impossibile avviare il CT",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Aiuto e informazioni",
|
||||
"Help and Info Commands": "Comandi di aiuto e informazioni",
|
||||
"Helper-Scripts logo applied": "Logo Helper-Scripts applicato",
|
||||
"Helper:": "Aiutante:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Dispositivi nascosti per sicurezza",
|
||||
"Hidden:": "Archivi .tar non ProxMenux nascosti:",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Se il tuo DHCP ha una prenotazione statica per il vecchio MAC, aggiornala.",
|
||||
"Image": "Immagine",
|
||||
"Image Source Directory": "Directory origine immagini",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Accesso alle immagini confermato.\n\n{reference}\n\nArchitettura: {architecture}\nVersione: {version}\nDimensioni del download: {size}\nDigestione: {digest}",
|
||||
"Image cache": "Cache immagini",
|
||||
"Image compatibility restored:": "Compatibilità dell'immagine ripristinata:",
|
||||
"Image compatibility verified:": "Compatibilità dell'immagine verificata:",
|
||||
"Image directory:": "Directory immagini:",
|
||||
"Image download failed:": "Download dell'immagine non riuscito:",
|
||||
"Image downloaded": "Immagine scaricata",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Immagine scaricata e verificata.\n\n{reference}\n\nConservazione: {storage}\nDimensione archivio: {size}\nArchivio: {archive}\n\nNon è stato creato alcun contenitore.\nProxMenux rimuove le immagini memorizzate nella cache inutilizzate dopo gli aggiornamenti riusciti.",
|
||||
"Image file not found:": "File immagine non trovato:",
|
||||
"Image imported:": "Immagine importata:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "Verifica dell'integrità dell'immagine non riuscita. Il download parziale è stato scartato; riprova.",
|
||||
"Image integrity verified": "Integrità dell’immagine verificata",
|
||||
"Image not allowed for the host monitor profile": "Immagine non consentita per il profilo di monitoraggio dell'host",
|
||||
"Image reference": "Riferimento all'immagine",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Riferimento immagine (ad esempio ghcr.io/user/application:latest)",
|
||||
"Image selection was cancelled": "Selezione immagine annullata",
|
||||
"Image that is not in the catalog": "Immagine non presente nel catalogo",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Installa Samba nel CT:",
|
||||
"Install ZFS auto-snapshot": "Installa ZFS auto-snapshot",
|
||||
"Install a version from the branch the kernel names.": "Installa una versione del ramo indicato dal kernel.",
|
||||
"Install an image as a native LXC": "Installa un'immagine come LXC nativa",
|
||||
"Install an image that is not in the catalog": "Installa un’immagine non presente nel catalogo",
|
||||
"Install analysis tools": "Installa strumenti di analisi",
|
||||
"Install and configure": "Installa e configura",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "Installazione terminata, ma i driver non sono caricati. Potrebbe servire un riavvio.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Installazione incompleta. Questi container e i relativi dati vengono conservati:",
|
||||
"Installation log:": "Registro installazione:",
|
||||
"Installation settings": "Impostazioni di installazione",
|
||||
"Installation summary": "Riepilogo installazione",
|
||||
"Installed": "Installato",
|
||||
"Installed at:": "Installazione:",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Percorso host non valido:",
|
||||
"Invalid host-monitor firewall plan": "Piano firewall monitoraggio host non valido",
|
||||
"Invalid image probe descriptor": "Descrittore verifica immagine non valido",
|
||||
"Invalid image tag.": "Tag immagine non valido.",
|
||||
"Invalid input": "Immissione non valida",
|
||||
"Invalid internal volume": "Volume interno non valido",
|
||||
"Invalid list:": "Elenco non valido:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Applicazione suite non valida",
|
||||
"Invalid sysctl value:": "Valore sysctl non valido:",
|
||||
"Invalid template storage": "Storage dei template non valido",
|
||||
"Invalid template storage name.": "Nome di archiviazione del modello non valido.",
|
||||
"Invalid tmpfs options:": "Opzioni tmpfs non valide:",
|
||||
"Invalid tmpfs path:": "Percorso tmpfs non valido:",
|
||||
"Invalid tmpfs size:": "Dimensione tmpfs non valida:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Scrittura Log2RAM programmata ogni",
|
||||
"Log:": "Registro:",
|
||||
"Logged-in users": "Utenti connessi",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "Accesso a {registry} scaduto. Le credenziali salvate non sono state modificate.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "Disconnessione da {registry} scaduta. Le credenziali del file salvato non sono state modificate.",
|
||||
"Logrotate optimization completed": "Ottimizzazione Logrotate completata",
|
||||
"Logrotate service restarted successfully": "Servizio Logrotate riavviato correttamente",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop è un lettore musicale moderno e leggero, progettato per integrarsi al meglio con l'ambiente desktop GNOME.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Gestisci percorsi personalizzati (aggiungi/rimuovi le tue cartelle)",
|
||||
"Manage installed OCI applications": "Gestisci le applicazioni OCI installate",
|
||||
"Manage local backup target": "Gestisci la destinazione di backup locale",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Gestisci i registri di immagini private.\nLe credenziali salvate consentono a ProxMenux di accedere alle tue immagini private.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Gestisci gli account del registro come root sul nodo Proxmox.",
|
||||
"Managed disks must have backup enabled and a valid size": "I dischi gestiti devono avere il backup abilitato e una dimensione valida",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Gestione degli host proxy Nginx tramite un'interfaccia semplice e potente.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Guida CLI manuale (Gestione dischi e storage)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Nessun server Samba accessibile trovato.",
|
||||
"No accessible exports found.": "Nessuna esportazione accessibile trovata.",
|
||||
"No accessible shares found.": "Nessuna condivisione accessibile trovata.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Nessuno spazio di archiviazione Proxmox attivo accetta archivi modello OCI.",
|
||||
"No active exports or showmount not available": "Nessuna esportazione attiva o showmount non disponibile",
|
||||
"No active session": "Nessuna sessione attiva",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Nessun abbonamento attivo e nessun repository PVE utilizzabile. La modalità non interattiva non può modificare le origini APT; configurarle in Nodo > Aggiornamenti > Repository.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Nessun server recente di tipo",
|
||||
"No recent Samba servers found.": "Nessun server Samba recente trovato.",
|
||||
"No registered OCI containers are available for selection on this host.": "Nessun container OCI registrato disponibile per la selezione su questo host.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Nessuna API di registro trovata in {registry}. Controlla il nome host e la porta.",
|
||||
"No restored OCI application is waiting to be recovered.": "Nessuna applicazione OCI ripristinata è in attesa di recupero.",
|
||||
"No results": "Nessun risultato",
|
||||
"No routing information found.": "Nessuna informazione di routing trovata.",
|
||||
@@ -4263,7 +4301,7 @@
|
||||
"No sysfs ROM entry — trying ACPI VFCT table...": "Nessuna voce ROM in sysfs: provo la tabella ACPI VFCT...",
|
||||
"No target configured.": "Nessuna destinazione configurata.",
|
||||
"No test currently running": "Nessun test attualmente in corso",
|
||||
"No unambiguous loader download found in release metadata.": "nessun download di caricatore inequivocabile trovato nei metadati della versione.",
|
||||
"No unambiguous loader download found in release metadata.": "Nessun download univoco del loader trovato nei metadati della versione.",
|
||||
"No uninstaller found for:": "Nessun programma di disinstallazione trovato per:",
|
||||
"No unprivileged containers available in Proxmox.": "Nessun container non privilegiato disponibile in Proxmox.",
|
||||
"No updates available — run a scan first or wait for the Monitor to refresh.": "Nessun aggiornamento disponibile: esegui prima una scansione o attendi l'aggiornamento del monitor.",
|
||||
@@ -4297,7 +4335,9 @@
|
||||
"Not an OVH server, skipping RTM installation": "Non è un server OVH, installazione RTM saltata",
|
||||
"Not currently mounted": "Attualmente non montato",
|
||||
"Not currently mounted — skipping umount.": "Attualmente non montato: umount saltato.",
|
||||
"Not declared": "Non dichiarato",
|
||||
"Not enough free space for the backup": "Spazio libero insufficiente per il backup",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Spazio libero insufficiente su {storage}. Libera spazio o seleziona un altro spazio di archiviazione.",
|
||||
"Not found": "Non trovato",
|
||||
"Not found in the OCI archive:": "Non trovato nell'archivio OCI:",
|
||||
"Not imported:": "Non importato:",
|
||||
@@ -4388,6 +4428,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Solo i nodi DRM Intel/AMD, Coral e USB possono essere acquisiti automaticamente",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Solo i nodi Intel/AMD DRM, Coral, NPU e USB possono essere adottati automaticamente",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Queste impostazioni si usano solo in Docker Swarm, quindi non vengono applicate:",
|
||||
"Only a full sha256 image digest is supported.": "Messaggio tecnico per Proxmox e IT. Traduzione: è supportato solo un digest di immagini sha256 completo.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Solo un’istanza OCI autonoma installata può acquisire modifiche esterne",
|
||||
"Only backed-up Proxmox volumes can be adopted": "L'adozione dei volumi Proxmox richiede l'opzione backup=1",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Converti in privilegiato solo se assolutamente necessario per il tuo caso d'uso.",
|
||||
@@ -4541,6 +4582,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Il passthrough potrebbe funzionare anche senza un file ROM.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "Il passthrough potrebbe funzionare, ma l'affidabilità di avvio/riavvio non è garantita.",
|
||||
"Password": "Password",
|
||||
"Password / access token (image pull permission)": "Password/token di accesso (autorizzazione al pull dell'immagine)",
|
||||
"Password Mismatch": "Password non corrispondenti",
|
||||
"Password cannot be empty.": "La password non può essere vuota.",
|
||||
"Password confirmation cannot be empty.": "La conferma della password non può essere vuota.",
|
||||
@@ -4576,7 +4618,7 @@
|
||||
"Passwords do not match. Please try again.": "Le password non corrispondono. Riprova.",
|
||||
"Paste an oci-compose in the terminal": "Incolla un oci-compose nel terminale",
|
||||
"Paste it here and press Ctrl+D on an empty line.": "Incollalo qui e premi Ctrl+D su una riga vuota.",
|
||||
"Paste it here and press Ctrl+D.": "incollalo qui e premi Ctrl+D.",
|
||||
"Paste it here and press Ctrl+D.": "Incollalo qui e premi Ctrl+D.",
|
||||
"Paste its Compose file in the terminal": "Incolla il file Compose nel terminale",
|
||||
"Paste its docker run command in the terminal": "Incolla il comando docker run nel terminale",
|
||||
"Paste the UUP Dump URL here": "Incolla qui l'URL di UUP Dump",
|
||||
@@ -4806,7 +4848,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux allega directory, non file singoli, quindi questa immagine non può essere ancora installata.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux può applicare permessi aperti su questa directory NFS dall'host in modo che il container possa leggere e scrivere:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux può rimontarlo con permessi aperti in modo che qualsiasi LXC possa leggere e scrivere.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux non può installare questa immagine automaticamente. Importa invece il relativo file di composizione.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux non può sovrascrivere le autorizzazioni lato server NFS dall'host.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux non è riuscito a tradurre questa immagine. Prova a importare il file Compose da OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "Personalizzazioni ProxMenux rimosse da bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux non dà al container accesso al sistema dell’host.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux non li installa. Durante l'installazione ti verranno chiesti i dati di connessione.",
|
||||
@@ -4927,6 +4971,7 @@
|
||||
"Reading SMART data...": "Lettura dei dati SMART...",
|
||||
"Reading SMART self-test log...": "Lettura del registro dell'autotest SMART...",
|
||||
"Reading full SMART report...": "Lettura del rapporto SMART completo...",
|
||||
"Reading image metadata. Please wait...": "Lettura dei metadati dell'immagine. Attendere prego...",
|
||||
"Real-time Performance Monitoring": "Monitoraggio prestazioni in tempo reale",
|
||||
"Real-time bandwidth usage (press q to exit)": "Utilizzo banda in tempo reale (premi q per uscire)",
|
||||
"Real-time collaborative document editor": "Editor collaborativo di documenti in tempo reale",
|
||||
@@ -5019,6 +5064,9 @@
|
||||
"Register mount path in Proxmox:": "Registra il percorso di montaggio in Proxmox:",
|
||||
"Registering disk as Proxmox storage...": "Registrazione disco come storage Proxmox...",
|
||||
"Registering module with DKMS...": "Registrazione del modulo con DKMS...",
|
||||
"Registry accounts": "Conti del Registro di sistema",
|
||||
"Registry hostname": "Nome host del registro",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Registro: {registry}\nConto: {account}\nAutenticazione: {method}\n\nLe credenziali salvate vengono verificate quando si accede a un'immagine.",
|
||||
"Reinstall / update Coral drivers": "Reinstalla/aggiorna i driver Coral",
|
||||
"Reinstall Fail2Ban": "Reinstalla Fail2Ban",
|
||||
"Reinstall Lynis": "Reinstalla Lynis",
|
||||
@@ -5090,8 +5138,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Rimuovi il metapacchetto systemd-boot obsoleto",
|
||||
"Remove old repository files:": "Rimuovi i vecchi file del repository:",
|
||||
"Remove passthrough device from VM": "Rimuovi dispositivo passthrough dalla VM",
|
||||
"Remove saved credentials": "Rimuovi le credenziali salvate",
|
||||
"Remove subscription banner": "Rimuovi il banner di abbonamento",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Rimuovere l’applicazione? I dischi dei suoi container vengono eliminati e solo un backup può ripristinarli.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Rimuovere le credenziali salvate per {registry}?\nLe app in esecuzione continueranno a funzionare.",
|
||||
"Remove the unprivileged flag from configuration:": "Rimuovi il flag unprivileged dalla configurazione:",
|
||||
"Remove unused packages and their config": "Rimuovi i pacchetti non utilizzati e la loro configurazione",
|
||||
"Remove: delete the application and its containers": "Rimuovi: elimina l'applicazione e i suoi container",
|
||||
@@ -5413,6 +5463,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Salva e classifica gli articoli. Leggili più tardi. Liberamente.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Salva la passphrase in un posto sicuro ORA, prima di continuare.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Salvare questa destinazione Borg per non dover reinserire i dettagli?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Le credenziali salvate per {registry} sono state rimosse.\nGli altri file di credenziali Skopeo/Docker vengono gestiti separatamente.",
|
||||
"Saved record removed": "Registrazione salvata rimossa",
|
||||
"Saving changes...": "Salvataggio delle modifiche...",
|
||||
"Saving the new configuration": "Salvataggio della nuova configurazione",
|
||||
@@ -5793,9 +5844,11 @@
|
||||
"Shutdown timeout": "Timeout di spegnimento",
|
||||
"SiYuan access code": "Codice di accesso SiYuan",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear gestisce serie TV e/o anime, rileva nuovi episodi, si collega alle applicazioni di download e altro ancora.",
|
||||
"Sign in to a registry": "Accedi a un registro",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Accedi al pannello e crea un utente Samba in Impostazioni prima di pubblicare una directory su SMB.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal è un'app di messaggistica che mette la privacy al centro. È gratuita e facile da usare, con una robusta crittografia end-to-end che protegge la riservatezza delle comunicazioni.",
|
||||
"Signatures removed. Partition table preserved.": "Firme rimosse. Tabella delle partizioni conservata.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Accesso a {registry} come {username}.\n\nLe credenziali vengono salvate per ProxMenux.\nSeleziona l'account per controllare, scaricare o installare un'immagine.",
|
||||
"Simple and easy to use DDNS": "DDNS semplice e facile da usare",
|
||||
"Single GPU Warning": "Avviso GPU singola",
|
||||
"Single target found — selected automatically:": "Unica destinazione trovata - selezionata automaticamente:",
|
||||
@@ -5821,6 +5874,8 @@
|
||||
"Skipping SR-IOV device": "Dispositivo SR-IOV saltato",
|
||||
"Skipping installation.": "Installazione saltata.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Patch manuali saltate: il fork feranick supporta già questo kernel.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Scopeo non è disponibile. Ripristinare le dipendenze ProxMenux OCI e riprovare.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo ha restituito un file di credenziali non valido; le credenziali salvate non sono state modificate.",
|
||||
"Sleek podcast downloader with GPodder sync": "Downloader podcast intuitivo con sincronizzazione GPodder",
|
||||
"Smart restore plan — hardware compatibility check": "Piano di ripristino intelligente: verifica compatibilità hardware",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping monitora la latenza della rete. Per un esempio completo delle sue funzionalità, visita UCDavis.",
|
||||
@@ -6078,6 +6133,7 @@
|
||||
"TCP optimizations configuration completed": "Configurazione ottimizzazioni TCP completata",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "Ottimizzazioni TCP rimosse (valori predefiniti ripristinati al prossimo riavvio)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "La porta TCP 5201 è raggiungibile (firewall sul server)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "Verifica TLS non riuscita per {registry}. Installare la CA del registro in /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "Dispositivo TPM aggiunto alla VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "Selezione storage TPM non riuscita o annullata. Creazione VM interrotta.",
|
||||
"TROUBLESHOOTING:": "RISOLUZIONE DEI PROBLEMI:",
|
||||
@@ -6271,6 +6327,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "La configurazione deve essere eseguita come root su Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "La configurazione di un nuovo componente è cambiata dopo la creazione",
|
||||
"The configuration stopped because of an unexpected error": "La configurazione si è interrotta per un errore imprevisto",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "Non è stato possibile utilizzare l'assistente credenziali configurato. Controlla la sua installazione e l'archivio credenziali.",
|
||||
"The console of the container could not be configured": "Impossibile configurare la console del container",
|
||||
"The consume/export volumes need at least 1 GB": "I volumi consume/export richiedono almeno 1 GB",
|
||||
"The container could not be removed automatically:": "Impossibile rimuovere automaticamente il container:",
|
||||
@@ -6309,6 +6366,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "I container non ne hanno più bisogno; un aggiornamento scarica le nuove versioni, se disponibili.",
|
||||
"The containers were created from downloaded OCI images": "I container sono stati creati da immagini OCI scaricate",
|
||||
"The coordinated backup was modified": "Il backup coordinato è stato modificato",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "Il file delle credenziali è stato modificato durante questa operazione. Riprova;non è stato sovrascritto.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "Il driver corrente verrà completamente disinstallato prima di installare la nuova versione. Continuare?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "L'immagine corrente del canale salvato verrà controllata e scaricata. Risorse, percorsi e GPU sono tenuti. La CT viene fermata durante la sostituzione e viene creato un backup nativo prima.",
|
||||
"The current record is missing for": "Manca il record attuale per",
|
||||
@@ -6391,7 +6449,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "La sottorete del firewall per il monitoraggio dell’host è cambiata; non è stata aggiunta alcuna regola",
|
||||
"The host-monitor web interface uses the host network.": "L’interfaccia web del monitor usa la rete dell’host.",
|
||||
"The identity of a member was replaced": "L'identità di un membro è stata sostituita",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "Il percorso della cache delle immagini non è sicuro. Controlla la memorizzazione del modello prima di riprovare.",
|
||||
"The image changes the user expected by the adapter": "L'immagine modifica l'utente previsto dall'adattatore",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "Non è stato possibile scaricare o verificare l'immagine. Controlla l'accesso al registro e allo spazio di archiviazione, quindi riprova.",
|
||||
"The image could not be read from its registry:": "Impossibile leggere l’immagine dal relativo registry:",
|
||||
"The image declares data paths that are still stored in the rootfs": "L’immagine dichiara percorsi dei dati che sono ancora archiviati nel rootfs",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "L’immagine non ha consentito all’utente dell’applicazione di accedere ai dispositivi; verificare l’inizializzazione nativa. I permessi sull’host non sono stati allentati.",
|
||||
@@ -6404,6 +6464,8 @@
|
||||
"The image is in its registry, for one architecture.": "L’immagine è presente nel relativo registry per una sola architettura.",
|
||||
"The image is in its registry.": "L’immagine è presente nel relativo registry.",
|
||||
"The image is in its registry:": "L’immagine è presente nel relativo registry:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "Il manifest dell'immagine non ha superato la verifica dell'integrità. Riprova o contatta l'editore dell'immagine.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "L'immagine o il tag non è stato trovato su {registry} oppure questo account non può accedervi. Controllare il riferimento.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "L'immagine richiede NVIDIA, ma l'host non ha un driver NVIDIA funzionante",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "L’immagine richiede di disabilitare parte dell’isolamento AppArmor o seccomp. Continuare solo se si ritiene affidabile l’immagine e si accetta il rischio.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "L’immagine richiede di disabilitare parte dell’isolamento AppArmor o seccomp. Compose consente di allentare queste restrizioni; l’opzione resta disattivata salvo selezione dell’utente. Continuare solo se si ritiene affidabile l’immagine e si accetta il rischio.",
|
||||
@@ -6541,7 +6603,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "Non è stato possibile completare la registrazione o la diagnosi; non è stato eseguito alcun aggiornamento.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "Il recupero non è completo. Rivedere il registro e scegliere \"Recuperare\" di nuovo per questo contenitore nel menu di gestione OCI.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "Il ripristino non è stato completato. Controllare il log e scegliere di nuovo \"{choice}\" per questo container nel menu di gestione OCI.",
|
||||
"The registry authentication file is invalid; it was not changed.": "Il file di autenticazione del registro non è valido;non è stato cambiato.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "Il file di autenticazione del registro deve essere di proprietà di root con modalità 600.",
|
||||
"The registry authentication file must have an absolute path.": "Il file di autenticazione del registro deve avere un percorso assoluto.",
|
||||
"The registry authentication path cannot contain symbolic links.": "Il percorso di autenticazione del registro non può contenere collegamenti simbolici.",
|
||||
"The registry authentication path has an unsafe parent directory.": "Il percorso di autenticazione del registro ha una directory principale non sicura.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "La directory delle credenziali del registro deve essere di proprietà di root con modalità 700.",
|
||||
"The registry did not return the saved image digest": "Il registry non ha restituito il digest salvato dell’immagine",
|
||||
"The registry returned incomplete or unsupported image metadata.": "Il registro ha restituito metadati dell'immagine incompleti o non supportati.",
|
||||
"The registry returned invalid or unsupported image metadata.": "Il registro ha restituito metadati dell'immagine non validi o non supportati.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "Il remote non esiste; crearlo e autorizzarlo prima nella WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "L'installer remoto deve essere eseguito come root su Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "Il remote deve essere già creato e autorizzato nell’interfaccia web Rclone. Questa operazione riavvia il CT e pubblica due viste FUSE sull’host.",
|
||||
@@ -6700,6 +6770,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Questa GPU è considerata incompatibile con il passthrough GPU a una VM in ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Questa condivisione NFS è completamente limitata: nemmeno l'utente root dell'host può scrivervi.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Questa VM richiede ulteriori passaggi di installazione; vedere la guida:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Questo account è per {registry}. Inserisci un'immagine da quel registro.",
|
||||
"This action will:": "Questa azione:",
|
||||
"This application cannot be recovered yet:": "Questa applicazione non può ancora essere recuperata:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Questa applicazione non può ancora essere recuperata; non è cambiato nulla:",
|
||||
@@ -6731,8 +6802,10 @@
|
||||
"This explicitly marks the container as privileged": "Ciò contrassegna esplicitamente il container come privilegiato",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Questo file decide cosa viene montato e con quali privilegi. Installarlo solo se proviene da una fonte attendibile.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Garantisce la disponibilità dei nodi dispositivo prima di applicare la configurazione GPU LXC.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Questa architettura host non è supportata dall'importatore di immagini OCI.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Questo host non ha un abbonamento attivo, passare al repository senza abbonamento? L'origine PVE Enterprise, non accessibile, verrà disabilitata. Le origini Ceph Enterprise, se presenti, verranno disabilitate senza scegliere un canale Ceph sostitutivo; configurare Ceph separatamente se necessario.",
|
||||
"This image cannot be installed as it is described:": "L’immagine non può essere installata secondo la descrizione fornita:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Questa immagine non ha un'immagine Linux compatibile per questo host ({architecture}).",
|
||||
"This image requires the host module": "Questa immagine richiede il modulo dell’host",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Questa importazione rifiuta questi percorsi senza verificare se sono file o directory.",
|
||||
"This installation will:": "Questa installazione:",
|
||||
@@ -6848,6 +6921,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Per riutilizzare la GPU in LXC, eseguire Aggiungi GPU a LXC dal Menu GPU e Coral-TPU",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Per utilizzare la VM senza problemi, è necessario riavviare l'host prima di avviarla.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Per usare questa condivisione da un LXC, eseguire il bind-mount tramite:",
|
||||
"Token": "Gettone",
|
||||
"Tool exit code:": "Codice di uscita strumento:",
|
||||
"Tool output:": "Output strumento:",
|
||||
"Tools": "Strumenti",
|
||||
@@ -6992,6 +7066,7 @@
|
||||
"Unsafe private configuration path": "Percorso configurazione privata non sicuro",
|
||||
"Unsafe qBittorrent configuration path": "Percorso configurazione qBittorrent non sicuro",
|
||||
"Unsafe record": "Record non sicuro",
|
||||
"Unsafe registry credential lock.": "Blocco delle credenziali del registro non sicuro.",
|
||||
"Unsafe registry directory": "Directory registro non sicura",
|
||||
"Unsafe registry lock": "Lock registro non sicuro",
|
||||
"Unsafe rootfs for the capture": "Rootfs non sicura per l'acquisizione",
|
||||
@@ -7004,6 +7079,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Profilo OCI-LXC AppArmor non supportato:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Profilo seccomp OCI-LXC non supportato:",
|
||||
"Unsupported Terminal": "Terminale non supportato",
|
||||
"Unsupported architecture for Figurine:": "Architettura non supportata da Figurine:",
|
||||
"Unsupported architecture:": "Architettura non supportata:",
|
||||
"Unsupported backup compression": "Compressione backup non supportata",
|
||||
"Unsupported credential pattern:": "Schema credenziali non supportato:",
|
||||
@@ -7056,6 +7132,7 @@
|
||||
"Update cancelled by user": "Aggiornamento annullato dall'utente",
|
||||
"Update completed. Data kept.": "Aggiornamento completato. Dati conservati.",
|
||||
"Update completed. Press Enter to continue...": "Aggiornamento completato. Premere Invio per continuare...",
|
||||
"Update credentials": "Aggiorna le credenziali",
|
||||
"Update every container of the application": "Aggiorna tutti i container dell’applicazione",
|
||||
"Update kernel to compatible version": "Aggiorna il kernel alla versione compatibile",
|
||||
"Update now?": "Aggiornare ora?",
|
||||
@@ -7122,8 +7199,10 @@
|
||||
"Use a custom path": "Usa percorso personalizzato",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Usare un LXC privilegiato per le operazioni server/client NFS.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Usare un LXC privilegiato per le operazioni client/server Samba.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Utilizza un nome host del registro, ad esempio ghcr.io o registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Usa un file di chiave privata SSH esistente su questo host",
|
||||
"Use an existing keyfile": "Usa file di chiavi esistente",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Utilizza un riferimento a un'immagine, ad esempio ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Usa così com’è — conserva dati e file system",
|
||||
"Use content types according to your use case.": "Usare i tipi di contenuto adatti al caso d’uso.",
|
||||
"Use default": "Usa impostazione predefinita",
|
||||
@@ -7163,6 +7242,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "Interfaccia web intuitiva per LLM (in precedenza Ollama WebUI)",
|
||||
"Username": "Nome utente",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Nome utente (ad esempio root@pam o user@pbs!token):",
|
||||
"Username / token": "Nome utente/token",
|
||||
"Username and password": "Nome utente e password",
|
||||
"Username and password will be cleared.": "Nome utente e password verranno cancellati.",
|
||||
"Username cannot be empty.": "Il nome utente non può essere vuoto.",
|
||||
@@ -7262,6 +7342,7 @@
|
||||
"Verifying Ceph packages availability...": "Verifica disponibilità pacchetti Ceph...",
|
||||
"Verifying all utilities status": "Verifica stato di tutte le utilità",
|
||||
"Verifying disk accessibility in CT": "Verifica accessibilità disco nel CT",
|
||||
"Verifying registry access. Please wait...": "Verifica dell'accesso al registro. Attendere prego...",
|
||||
"Verifying the backups...": "Verifica backup...",
|
||||
"Verifying the image integrity...": "Verifica integrità immagine...",
|
||||
"Version": "Versione",
|
||||
@@ -7561,6 +7642,7 @@
|
||||
"assembling": "assemblaggio",
|
||||
"automatically. Install it manually inside the container.": "automaticamente. Installalo manualmente all'interno del container.",
|
||||
"automatically. Reboot LXC to fully release.": "automaticamente. Riavviare LXC per il rilascio completo.",
|
||||
"available": "Disponibile",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "disponibile per bind mount LXC tramite Gestore montaggi LXC",
|
||||
"available in this same GPU and TPU menu.": "disponibile nello stesso menu GPU e TPU.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "backup su /etc/fstab.proxmenux.bak",
|
||||
@@ -7913,6 +7995,7 @@
|
||||
"runs in": "usa",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "percorsi sicuri ora (configurazioni, pacchetti, /etc, /root, ...)",
|
||||
"same MAC": "stesso MAC",
|
||||
"saved": "Salvato",
|
||||
"seconds (default)": "secondi (predefinito)",
|
||||
"see log:": "vedi registro:",
|
||||
"selected by default": "selezionata per impostazione predefinita",
|
||||
@@ -8031,8 +8114,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot rimosso (snapshot esistenti conservati nel pool)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "Comando zpool non trovato. Installare zfsutils-linux e riprovare.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool non trovato. Installare zfsutils-linux e riprovare.",
|
||||
"{count} saved account.": "Account salvato {count}.",
|
||||
"{count} saved accounts.": "Account salvati {count}.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} esiste già e appartiene a un altro utente dell'host, quindi {app} non può scrivervi.\n\nProxMenux può aggiungere regole di accesso (ACL) a questa directory, a tutto ciò che contiene e a ciò che vi verrà creato in seguito, per gli utenti e i gruppi con cui {app} viene eseguito sull'host (ID {ids}). Il proprietario dei file non cambia e chi oggi li legge o li scrive continua a farlo; anche il proprietario della directory ottiene l'accesso ai file creati da {app}.\n\nConcedere a {app} l'accesso a questa directory?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} esiste già e appartiene a un altro utente dell'host, quindi {app} non può scrivervi.\n\nProxMenux può aggiungere una regola di accesso (ACL) per l'identità utilizzata da {app} sull'host (UID {uid}).Niente di ciò che c'è cambia proprietario o autorizzazioni: qualunque cosa legga o scriva quei file oggi continua a farlo, e anche il proprietario della directory ottiene l'accesso ai file creati da {app}.\n\nConcedere a {app} l'accesso a questa directory?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} ha risposto con un semplice HTTP. Utilizzare un registro con HTTPS; La verifica TLS rimane abilitata.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} non ha risposto entro {timeout} secondi. Riprova più tardi.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "{registry} è una richiesta di limitazione della velocità. Aspetta un po' e riprova.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} ha rifiutato l'accesso a questa immagine:\n{reference}\n\nSe l'immagine è privata, accedi con un account che possa recuperarla.\n\nAccedi adesso?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} ha segnalato un errore del server. Riprova più tardi.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} ha restituito metadati dell'immagine non validi o non supportati.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "— il ripristino completo/personalizzato salterà i percorsi legati al kernel",
|
||||
"— disk may be busy. Skipping fstab removal.": "— il disco potrebbe essere occupato. Rimozione della voce da fstab saltata.",
|
||||
"— restore proceeds as same-version (verified safe)": "— il ripristino procede come per la stessa versione (sicurezza verificata)",
|
||||
|
||||
+93
-2
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Ponte de acesso para Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "O acesso não pôde ser concedido completamente; o aplicativo pode não conseguir gravar em:",
|
||||
"Access could not be granted; the application cannot write to:": "O acesso não pôde ser concedido; o aplicativo não pode gravar em:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Acesso negado por {registry}. Verifique o nome da imagem e faça login nas contas do Registro.",
|
||||
"Access granted to the application on:": "Acesso concedido ao aplicativo em:",
|
||||
"Access password of the web interface (optional)": "Senha de acesso da interface web (opcional)",
|
||||
"Access profile:": "Perfil de acesso:",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Avançado",
|
||||
"Advanced Diagnostics": "Diagnóstico Avançado",
|
||||
"Advanced Network Diagnostics": "Diagnóstico avançado de rede",
|
||||
"Advanced settings": "Configurações avançadas",
|
||||
"Advanced: every setting of the container": "Avançado: cada configuração do recipiente",
|
||||
"Affected LXC containers": "Contêineres LXC afetados",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Depois de concluir a configuração da GPU, inicie a VM manualmente quando o host estiver pronto.",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Outra OCI operation está usando o registro de instância. Espere que termine e abra este menu novamente; nenhum recipiente é modificado.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Outra operação OCI está usando o registro da instância. Espere terminar.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Outra OCI operation está usando o registro. Esta operation não foi iniciada.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "Outra operação ProxMenux OCI está em execução. Tente novamente quando terminar.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Existe outra configuração ZRAM ou não pôde ser inspecionada; systemd-zram-generator foi mantido",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Existe outra configuração de gerador ZRAM; recusando-se a substituí-lo:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Existe outra configuração de troca de ZRAM; recusando-se a substituí-lo:",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Outra instância usa",
|
||||
"Another job that writes to the same storage still starts them.": "Outro trabalho que grava no mesmo armazenamento continua a iniciá-los.",
|
||||
"Another node, typed by hand": "Outro nó, digitado manualmente",
|
||||
"Another registry account operation is running. Try again when it finishes.": "Outra operação de conta de registro está em execução. Tente novamente quando terminar.",
|
||||
"Another stack operation is pending": "Outra pilha operation está pendente",
|
||||
"Application": "Aplicação",
|
||||
"Application registered on this host:": "Aplicativo registrado neste host:",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Autenticação",
|
||||
"Authentication & Security": "Autenticação e segurança",
|
||||
"Authentication Error": "Erro de autenticação",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Falha na autenticação para {registry}. Verifique as permissões da conta e do token.",
|
||||
"Authentication failed.": "Falha na autenticação.",
|
||||
"Authentication required:": "Autenticação necessária:",
|
||||
"Authentication:": "Autenticação:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Não é possível resolver o diretório inicial do contêiner:",
|
||||
"Cannot validate credentials - no shares available for testing.": "Não é possível validar credenciais – não há compartilhamentos disponíveis para teste.",
|
||||
"Cannot verify the reused disk:": "Não foi possível verificar o disco reutilizado:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Não é possível gravar o arquivo de imagem em {storage}. Verifique o acesso ao armazenamento e o status de montagem.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Capacidades não podem ser mantidas e todas retiradas ao mesmo tempo",
|
||||
"Category": "Categoria",
|
||||
"Caution: Maximum mode generates more heat.": "Cuidado: O modo máximo gera mais calor.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Verifique o status do Samba",
|
||||
"Check VM disk/PCI slots": "Verifique os slots de disco/PCI da VM",
|
||||
"Check VM passthrough settings": "Verifique as configurações de passagem da VM",
|
||||
"Check access to an image": "Verifique o acesso a uma imagem",
|
||||
"Check connectivity with another host": "Verifique a conectividade com outro host",
|
||||
"Check container mount points": "Verifique os pontos de montagem do contêiner",
|
||||
"Check if container is unprivileged:": "Verifique se o contêiner não tem privilégios:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Verifique isso:",
|
||||
"Check the error messages above for details.": "Verifique as mensagens de erro acima para obter detalhes.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Verifique a referência da imagem e o acesso ao registro. Se o registro não estiver disponível, tente novamente mais tarde. Um registro privado precisa de credenciais, que ainda não são suportadas.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Verifique a referência da imagem e o acesso ao registro. Se o registro não estiver disponível, tente novamente mais tarde. Para uma imagem privada, faça login nas contas do Registro no menu OCI.",
|
||||
"Check the service status manually if needed.": "Verifique o status do serviço manualmente, se necessário.",
|
||||
"Checking MOTD configuration...": "Verificando a configuração do MOTD...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Verificando o status do driver NVIDIA com nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Verificando espaço livre em /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Verificando se o disco do sistema é SSD ou M.2...",
|
||||
"Checking if the server belongs to OVH...": "Verificando se o servidor pertence à OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Verificando o acesso à imagem e metadados. Por favor, aguarde...",
|
||||
"Checking kernel headers and build tools...": "Verificando cabeçalhos do kernel e ferramentas de construção...",
|
||||
"Checking remaining interfaces": "Verificando interfaces restantes",
|
||||
"Checking that the container keeps running...": "A verificar se o contentor continua a funcionar...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Escolha o modo iperf3:",
|
||||
"Choose options to configure:": "Escolha opções para configurar:",
|
||||
"Choose specific VMs/CTs": "Escolha VMs/CTs específicos",
|
||||
"Choose storage for the downloaded image.": "Escolha o armazenamento para a imagem baixada.",
|
||||
"Choose the driver version for Coral M.2:": "Escolha a versão do driver para Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Escolha o sistema de arquivos para a nova partição:",
|
||||
"Choose the release channel to use:": "Escolha o canal de lançamento a ser usado:",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "não foi possível publicar a restauração pendente. A restauração pendente anterior foi mantida.",
|
||||
"Could not push the key. Check the password and that": "Não foi possível pressionar a chave. Verifique a senha e isso",
|
||||
"Could not query the image registry": "Não foi possível consultar o registro de imagem",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "Não foi possível acessar {registry}. Verifique seu endereço, DNS e acesso à rede.",
|
||||
"Could not read SMART data from": "Não foi possível ler os dados SMART de",
|
||||
"Could not read VM configuration.": "Não foi possível ler a configuração da VM.",
|
||||
"Could not read the CUDA compute capability": "Não foi possível ler a capacidade de computação do CUDA",
|
||||
"Could not read the NVIDIA driver version": "Não foi possível ler a versão do driver NVIDIA",
|
||||
"Could not read the host firewall rules": "Não foi possível ler as regras do firewall do host",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Não foi possível ler a imagem do {registry}. Verifique a referência e faça login nas contas do Registro.",
|
||||
"Could not read this job.": "Não foi possível ler este trabalho.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "Não foi possível liberar páginas ZRAM; o perfil existente permanece ativo",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Não foi possível remontar automaticamente. Tente manualmente ou verifique as credenciais.",
|
||||
"Could not remove VM automatically. Run manually:": "Não foi possível remover a VM automaticamente. Execute manualmente:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "Não foi possível remover o perfil ZRAM; a configuração foi restaurada",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "Não foi possível remover o perfil ZRAM; a configuração foi restaurada, mas o swap não pôde ser reiniciado",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Não foi possível remover as credenciais do {registry}; as credenciais do arquivo salvo não foram alteradas.",
|
||||
"Could not remove previous DKMS tree at": "Não foi possível remover a árvore DKMS anterior em",
|
||||
"Could not reserve a private network for the stack": "Não foi possível reservar uma rede privada para a pilha",
|
||||
"Could not resolve the Compose user:": "Não foi possível resolver o usuário Compose:",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Não foi possível definir a exibição virtual da VM como vga: std",
|
||||
"Could not set boot order for": "Não foi possível definir a ordem de inicialização para",
|
||||
"Could not set the container entrypoint": "Não foi possível definir o ponto de entrada do recipiente",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Não foi possível fazer login no {registry}. Verifique o acesso ao registro e as permissões de token.",
|
||||
"Could not stage pending restore path:": "Não foi possível preparar o caminho de restauração pendente:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "não foi possível preparar a restauração pendente. Nada de novo foi programado.",
|
||||
"Could not stop LXC": "Não foi possível parar o LXC",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Criando a rede privada...",
|
||||
"Creating the temporary data container": "Criando o recipiente de dados temporário",
|
||||
"Creative & Design": "Criatividade e design",
|
||||
"Credential helper": "Auxiliar de credencial",
|
||||
"Credential storage and access": "Armazenamento e acesso de credenciais",
|
||||
"Credentials are correct": "As credenciais estão corretas",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Credenciais apagadas. jwt_secret e tokens de API preservados.",
|
||||
"Credentials file created securely.": "Arquivo de credenciais criado com segurança.",
|
||||
"Credentials file removed.": "Arquivo de credenciais removido.",
|
||||
"Credentials file:": "Arquivo de credenciais:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Arquivo de credenciais:\n{path}\n\nPropriedade do root; modo de diretório 700 e modo de arquivo 600.\nAs credenciais básicas são codificadas em base64, não criptografadas.\nOs auxiliares de credenciais usam seu próprio armazenamento.\n\nUse um token de acesso com permissão para extrair imagens.\nConfigure credenciais em cada nó que baixa imagens.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Arquivo de credenciais:\n{path}\n\nPropriedade do root; modo de diretório 700 e modo de arquivo 600.\nAs credenciais básicas são codificadas em base64, não criptografadas.\nOs auxiliares de credenciais usam seu próprio armazenamento.\n\nUse um token de acesso com permissão para extrair imagens.\nCada nó do cluster usa as contas salvas aqui.",
|
||||
"Credentials validated successfully": "Credenciais validadas com sucesso",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Restauração entre hosts: os IDs de convidados no backup se sobrepõem aos Live IDs no destino:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Restauração entre kernels – caminhos vinculados ao kernel mesclados, não copiados",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Utilizador por omissão",
|
||||
"Default options": "Opções padrão",
|
||||
"Default options read/write": "Opções padrão leitura/gravação",
|
||||
"Default settings": "Configurações padrão",
|
||||
"Default will be used:": "O padrão será usado:",
|
||||
"Default:": "Padrão:",
|
||||
"Default: only what the application needs": "Padrão: somente o que a aplicação precisa",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs é um bot Discord para solicitar mídia através de backends *arr, escrito em Rust.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander é um gerenciador de arquivos de código aberto livre plataforma cruzada com dois painéis lado a lado. Ele é inspirado pelo Comandante Total e apresenta algumas novas ideias.",
|
||||
"Download Spotify music with album art and metadata": "Baixar música Spotify com arte de álbum e metadados",
|
||||
"Download an image to template storage": "Baixe uma imagem para armazenamento de modelos",
|
||||
"Download an oci-compose from an address": "Baixe um oci-compose de um endereço",
|
||||
"Download failed for all attempted URLs": "Falha no download de todas as tentativas de URL",
|
||||
"Download its Compose file from an address": "Baixe seu arquivo Compose de um endereço",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Baixando o logotipo da Proxmologia...",
|
||||
"Downloading UUP converter...": "Baixando o conversor UUP...",
|
||||
"Downloading amdgpu_top": "Baixando amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Baixando e verificando a imagem.\nIsso pode levar alguns minutos. Por favor, aguarde...",
|
||||
"Downloading official installer...": "Baixando o instalador oficial...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "O download de backups criptografados pré-existentes deste host falhará, a menos que você mantenha uma cópia da chave atual.",
|
||||
"Downloading the image:": "Baixando a imagem:",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Insira o nome do pool ZFS para o disco selecionado:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Insira um nome para o ponto de montagem (usado como /mnt/<nome>):",
|
||||
"Enter a name for the new virtual machine:": "Insira um nome para a nova máquina virtual:",
|
||||
"Enter a non-empty password or access token on a single line.": "Insira uma senha ou token de acesso não vazio em uma única linha.",
|
||||
"Enter a number, or write or paste a command:": "Digite um número ou escreva ou cole um comando:",
|
||||
"Enter a systemd calendar event, e.g.:": "Insira um evento de calendário do systemd, por exemplo:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Digite um endereço IPv4 utilizável com seu prefixo, por exemplo",
|
||||
"Enter a valid registry username.": "Insira um nome de usuário de registro válido.",
|
||||
"Enter backup file (.zst):": "Insira o arquivo de backup (.zst):",
|
||||
"Enter backup path (.tar.zst):": "Insira o caminho de backup (.tar.zst):",
|
||||
"Enter backup path (.vma.zst):": "Insira o caminho de backup (.vma.zst):",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Ajuda e informações",
|
||||
"Help and Info Commands": "Comandos de ajuda e informações",
|
||||
"Helper-Scripts logo applied": "Logotipo Helper-Scripts aplicado",
|
||||
"Helper:": "Ajudante:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Escondido por segurança",
|
||||
"Hidden:": "Escondido:",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Se o seu DHCP tiver uma reserva estática para o MAC antigo, atualize-o.",
|
||||
"Image": "Imagem",
|
||||
"Image Source Directory": "Diretório de origem da imagem",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Acesso à imagem confirmado.\n\n{reference}\n\nArquitetura: {architecture}\nVersão: {version}\nTamanho do download: {size}\nResumo: {digest}",
|
||||
"Image cache": "Cache de imagens",
|
||||
"Image compatibility restored:": "Compatibilidade da imagem restaurada:",
|
||||
"Image compatibility verified:": "Compatibilidade da imagem verificada:",
|
||||
"Image directory:": "Diretório de imagens:",
|
||||
"Image download failed:": "A transferência da imagem falhou:",
|
||||
"Image downloaded": "Imagem transferida",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Imagem baixada e verificada.\n\n{reference}\n\nArmazenamento: {storage}\nTamanho do arquivo: {size}\nArquivo: {archive}\n\nNenhum contêiner foi criado.\nProxMenux remove imagens em cache não utilizadas após atualizações bem-sucedidas.",
|
||||
"Image file not found:": "Arquivo de imagem não encontrado:",
|
||||
"Image imported:": "Imagem importada:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "Falha na verificação da integridade da imagem. O download parcial foi descartado; tente novamente.",
|
||||
"Image integrity verified": "Integridade da imagem verificada",
|
||||
"Image not allowed for the host monitor profile": "Imagem não permitida para o perfil do monitor da máquina",
|
||||
"Image reference": "Referência de imagem",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Referência da imagem (por exemplo ghcr.io/usuário/aplicação:latest)",
|
||||
"Image selection was cancelled": "A seleção da imagem foi cancelada",
|
||||
"Image that is not in the catalog": "Imagem que não está no catálogo",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Instale o Samba dentro do CT:",
|
||||
"Install ZFS auto-snapshot": "Instale o instantâneo automático do ZFS",
|
||||
"Install a version from the branch the kernel names.": "Instale uma versão da ramificação dos nomes do kernel.",
|
||||
"Install an image as a native LXC": "Instale uma imagem como LXC nativo",
|
||||
"Install an image that is not in the catalog": "Instalar uma imagem que não está no catálogo",
|
||||
"Install analysis tools": "Instale ferramentas de análise",
|
||||
"Install and configure": "Instalar e configurar",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "A instalação foi concluída, mas os drivers não foram carregados. Uma reinicialização pode ser necessária.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Instalação incompleta. Estes contentores e os seus dados são conservados:",
|
||||
"Installation log:": "Registro de instalação:",
|
||||
"Installation settings": "Configurações de instalação",
|
||||
"Installation summary": "Resumo da instalação",
|
||||
"Installed": "Instalado",
|
||||
"Installed at:": "Instalado em:",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Caminho da máquina inválido:",
|
||||
"Invalid host-monitor firewall plan": "Plano de firewall de monitor de host inválido",
|
||||
"Invalid image probe descriptor": "descritor de sonda de imagem inválido",
|
||||
"Invalid image tag.": "Tag de imagem inválida.",
|
||||
"Invalid input": "Entrada inválida",
|
||||
"Invalid internal volume": "Volume interno inválido",
|
||||
"Invalid list:": "Lista inválida:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Aplicativo de suite inválido",
|
||||
"Invalid sysctl value:": "Valor do sysctl inválido:",
|
||||
"Invalid template storage": "Armazenamento de modelos inválido",
|
||||
"Invalid template storage name.": "Nome de armazenamento de modelo inválido.",
|
||||
"Invalid tmpfs options:": "Opções de tmpfs inválidas:",
|
||||
"Invalid tmpfs path:": "Caminho do tmpfs inválido:",
|
||||
"Invalid tmpfs size:": "Tamanho do tmpfs inválido:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Gravação Log2RAM agendada a cada",
|
||||
"Log:": "Registro:",
|
||||
"Logged-in users": "Usuários logados",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "O login no {registry} expirou. As credenciais salvas não foram alteradas.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "O logout do {registry} expirou. As credenciais do arquivo salvo não foram alteradas.",
|
||||
"Logrotate optimization completed": "Otimização do Logrotate concluída",
|
||||
"Logrotate service restarted successfully": "Serviço Logrotate reiniciado com sucesso",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop é um player de música moderna leve projetado para trabalhar de forma excelente no ambiente de trabalho GNOME.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Gerencie caminhos personalizados (adicione/remova suas pastas)",
|
||||
"Manage installed OCI applications": "Gerenciar aplicativos OCI instalados",
|
||||
"Manage local backup target": "Gerenciar destino de backup local",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Gerencie registros de imagens privadas.\nAs credenciais salvas permitem que ProxMenux acesse suas imagens privadas.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Gerencie contas de registro como root no nó Proxmox.",
|
||||
"Managed disks must have backup enabled and a valid size": "Os discos gerenciados devem ter backup ativado e um tamanho válido",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Gerenciando hosts proxy Nginx com uma interface simples e poderosa.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Guia CLI manual (Gerenciador de disco e armazenamento)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Nenhum servidor Samba acessível encontrado.",
|
||||
"No accessible exports found.": "Nenhuma exportação acessível encontrada.",
|
||||
"No accessible shares found.": "Nenhum compartilhamento acessível encontrado.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Nenhum armazenamento Proxmox ativo aceita arquivos de modelo OCI.",
|
||||
"No active exports or showmount not available": "Nenhuma exportação ativa ou showmount não disponível",
|
||||
"No active session": "Nenhuma sessão ativa",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Nenhuma assinatura ativa e nenhum repositório PVE utilizável. O modo não interativo não pode alterar fontes APT; configure-as em Nó > Atualizações > Repositórios.",
|
||||
@@ -4178,7 +4215,7 @@
|
||||
"No format-safe disks are available.": "Nenhum disco de formato seguro está disponível.",
|
||||
"No free ProxMenux private /24 network is available": "Nenhuma rede privada ProxMenux livre 24 está disponível",
|
||||
"No gasket DKMS registrations remain.": "Não restam registos DKMS de gasket.",
|
||||
"No group creation required — uses world-writable sticky bit permissions.": "Não é necessária a criação de grupos — usa permissões de sticky bit graváveis mundialmente.",
|
||||
"No group creation required — uses world-writable sticky bit permissions.": "Não é necessária a criação de grupos — usa permissões de sticky bit graváveis mundialmente.",
|
||||
"No guest selected.": "Nenhum convidado selecionado.",
|
||||
"No host VFIO reconfiguration expected": "Nenhuma reconfiguração VFIO do host é esperada",
|
||||
"No host VFIO/native binding changes were required.": "Nenhuma alteração de ligação VFIO/nativa do host foi necessária.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Nenhum recente",
|
||||
"No recent Samba servers found.": "Nenhum servidor Samba recente encontrado.",
|
||||
"No registered OCI containers are available for selection on this host.": "Nenhum contêiner OCI registrado está disponível para seleção neste host.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Nenhuma API de registro foi encontrada em {registry}. Verifique o nome do host e a porta.",
|
||||
"No restored OCI application is waiting to be recovered.": "Nenhum aplicativo OCI restaurado está aguardando para ser recuperado.",
|
||||
"No results": "Nenhum resultado",
|
||||
"No routing information found.": "Nenhuma informação de roteamento encontrada.",
|
||||
@@ -4297,7 +4335,9 @@
|
||||
"Not an OVH server, skipping RTM installation": "Não é um servidor OVH, ignorando a instalação do RTM",
|
||||
"Not currently mounted": "Atualmente não montado",
|
||||
"Not currently mounted — skipping umount.": "Atualmente não montado – ignorando umount.",
|
||||
"Not declared": "Não declarado",
|
||||
"Not enough free space for the backup": "Não há espaço livre suficiente para o backup",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Não há espaço livre suficiente no {storage}. Libere espaço ou selecione outro armazenamento.",
|
||||
"Not found": "Não encontrado",
|
||||
"Not found in the OCI archive:": "Não encontrado no arquivo OCI:",
|
||||
"Not imported:": "Não importado:",
|
||||
@@ -4388,10 +4428,11 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Somente nós Intel/AMD DRM, Coral e USB podem ser adotados automaticamente",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Somente nós Intel/AMD DRM, Coral, NPU e USB podem ser adotados automaticamente",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Apenas um Swarm Docker usa estas configurações, então elas não são aplicadas:",
|
||||
"Only a full sha256 image digest is supported.": "Apenas um resumo completo da imagem sha256 é suportado.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Somente uma instância OCI autônoma instalada pode adotar alterações externas",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Somente volumes Proxmox com backup podem ser adotados",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Converta para privilegiado apenas se for absolutamente necessário para o seu caso de uso.",
|
||||
"Only fully free disks are shown (not system-used and not referenced by VM/LXC).": "Somente discos totalmente livres são mostrados (não usados pelo sistema e não referenciados pelo VM/LXC).",
|
||||
"Only fully free disks are shown (not system-used and not referenced by VM/LXC).": "Somente discos totalmente livres são mostrados (não usados pelo sistema e não referenciados pelo VM/LXC).",
|
||||
"Only if using enterprise subscription": "Somente se estiver usando assinatura corporativa",
|
||||
"Only if using no-subscription repository": "Somente se estiver usando repositório sem assinatura",
|
||||
"Only needed if you mounted the filesystem in step 6b": "Necessário apenas se você montou o sistema de arquivos na etapa 6b",
|
||||
@@ -4541,6 +4582,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Passthrough ainda pode funcionar sem um arquivo ROM.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "A passagem pode funcionar, mas a confiabilidade de inicialização/reinício não é garantida.",
|
||||
"Password": "Senha",
|
||||
"Password / access token (image pull permission)": "Senha/token de acesso (permissão de extração de imagem)",
|
||||
"Password Mismatch": "Incompatibilidade de senha",
|
||||
"Password cannot be empty.": "A senha não pode ficar vazia.",
|
||||
"Password confirmation cannot be empty.": "A confirmação da senha não pode ficar vazia.",
|
||||
@@ -4806,7 +4848,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux atribui diretórios, não arquivos únicos, então esta imagem ainda não pode ser instalada.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux pode aplicar permissões abertas neste diretório NFS do host para que o contêiner possa ler e escrever:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux pode remontá-lo com permissões abertas para que qualquer LXC possa ler e escrever.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux não pode instalar esta imagem automaticamente. Em vez disso, importe seu arquivo Compose.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux não pode substituir as permissões do servidor NFS do host.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux não conseguiu traduzir esta imagem. Tente importar seu arquivo Compose de OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "Personalizações do ProxMenux removidas do bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux não dá a um recipiente o sistema de seu host.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux não os instala. A instalação pergunta como se conectar a eles.",
|
||||
@@ -4927,6 +4971,7 @@
|
||||
"Reading SMART data...": "Lendo dados SMART...",
|
||||
"Reading SMART self-test log...": "Lendo o registro de autoteste SMART...",
|
||||
"Reading full SMART report...": "Lendo o relatório SMART completo...",
|
||||
"Reading image metadata. Please wait...": "Lendo metadados de imagem. Por favor, aguarde...",
|
||||
"Real-time Performance Monitoring": "Monitoramento de desempenho em tempo real",
|
||||
"Real-time bandwidth usage (press q to exit)": "Uso de largura de banda em tempo real (pressione q para sair)",
|
||||
"Real-time collaborative document editor": "Editor de documentos colaborativos em tempo real",
|
||||
@@ -5019,6 +5064,9 @@
|
||||
"Register mount path in Proxmox:": "Registre o caminho de montagem no Proxmox:",
|
||||
"Registering disk as Proxmox storage...": "Registrando disco como armazenamento Proxmox...",
|
||||
"Registering module with DKMS...": "Registrando módulo com DKMS...",
|
||||
"Registry accounts": "Contas de registro",
|
||||
"Registry hostname": "Nome de host do registro",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Registro: {registry}\nConta: {account}\nAutenticação: {method}\n\nAs credenciais salvas são verificadas quando uma imagem é acessada.",
|
||||
"Reinstall / update Coral drivers": "Reinstale / atualize os drivers Coral",
|
||||
"Reinstall Fail2Ban": "Reinstale o Fail2Ban",
|
||||
"Reinstall Lynis": "Reinstale o Lynis",
|
||||
@@ -5090,8 +5138,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Remover meta-pacote obsoleto systemd-boot",
|
||||
"Remove old repository files:": "Remova arquivos antigos do repositório:",
|
||||
"Remove passthrough device from VM": "Remover dispositivo de passagem da VM",
|
||||
"Remove saved credentials": "Remover credenciais salvas",
|
||||
"Remove subscription banner": "Remover banner de assinatura",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Remover o aplicativo? Seus discos contêineres são excluídos e somente um backup pode recuperá-los.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Remover as credenciais salvas para {registry}?\nOs aplicativos em execução continuarão funcionando.",
|
||||
"Remove the unprivileged flag from configuration:": "Remova o sinalizador sem privilégios da configuração:",
|
||||
"Remove unused packages and their config": "Remova pacotes não utilizados e suas configurações",
|
||||
"Remove: delete the application and its containers": "Remover: apagar o aplicativo e seus recipientes",
|
||||
@@ -5413,6 +5463,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Salvar e classificar artigos. Lê-os depois. Livremente.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Salve a senha em algum lugar seguro AGORA, antes de continuar.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Salvar este alvo Borg para não precisar inserir os detalhes novamente?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "As credenciais salvas para {registry} foram removidas.\nOutros arquivos de credenciais Skopeo/Docker são gerenciados separadamente.",
|
||||
"Saved record removed": "Gravação salva removida",
|
||||
"Saving changes...": "Salvando alterações...",
|
||||
"Saving the new configuration": "Salvando a nova configuração",
|
||||
@@ -5793,9 +5844,11 @@
|
||||
"Shutdown timeout": "Tempo limite de desligamento",
|
||||
"SiYuan access code": "Código de acesso SiYuan",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "O SickGear oferece gerenciamento de programas de TV e/ou Anime, detecta novos episódios, links para aplicativos de download e muito mais..",
|
||||
"Sign in to a registry": "Faça login em um registro",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Faça login no painel e crie um usuário Samba em Configurações antes de publicar um diretório no SMB.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal é um aplicativo de mensagens com privacidade em seu núcleo. É livre e fácil de usar, com criptografia de ponta a ponta forte que mantém sua comunicação completamente privada.",
|
||||
"Signatures removed. Partition table preserved.": "Assinaturas removidas. Tabela de partição preservada.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Conectado ao {registry} como {username}.\n\nAs credenciais são salvas para ProxMenux.\nSelecione a conta para verificar, baixar ou instalar uma imagem.",
|
||||
"Simple and easy to use DDNS": "Simples e fácil de usar DDNS",
|
||||
"Single GPU Warning": "Aviso de GPU única",
|
||||
"Single target found — selected automatically:": "Único alvo encontrado — selecionado automaticamente:",
|
||||
@@ -5821,6 +5874,8 @@
|
||||
"Skipping SR-IOV device": "Ignorando dispositivo SR-IOV",
|
||||
"Skipping installation.": "Ignorando a instalação.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Ignorando patches manuais – feranick fork já suporta este kernel.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo não está disponível. Restaure as dependências do ProxMenux OCI e tente novamente.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo retornou um arquivo de credenciais inválido; as credenciais salvas não foram alteradas.",
|
||||
"Sleek podcast downloader with GPodder sync": "Baixador de podcast elegante com sincronização GPodder",
|
||||
"Smart restore plan — hardware compatibility check": "Plano de restauração inteligente – verificação de compatibilidade de hardware",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping acompanha a latência da sua rede. Para um exemplo completo do que esta aplicação é capaz de visitar UCDavis.",
|
||||
@@ -6078,6 +6133,7 @@
|
||||
"TCP optimizations configuration completed": "Configuração de otimizações TCP concluída",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "Otimizações de TCP revertidas (padrões restaurados na próxima reinicialização)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "A porta TCP 5201 está acessível (firewall no servidor)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "Falha na verificação de TLS para {registry}. Instale a CA do registro em /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "Dispositivo TPM adicionado à VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "A seleção de armazenamento TPM falhou ou foi cancelada. Criação de VM abortada.",
|
||||
"TROUBLESHOOTING:": "SOLUÇÃO DE PROBLEMAS:",
|
||||
@@ -6271,6 +6327,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "A configuração deve ser executada como root no Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "A configuração de um novo membro mudou depois de ter sido criado",
|
||||
"The configuration stopped because of an unexpected error": "A configuração parou devido a um erro inesperado",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "O auxiliar de credencial configurado não pôde ser usado. Verifique sua instalação e armazenamento de credenciais.",
|
||||
"The console of the container could not be configured": "O console do contêiner não pôde ser configurado",
|
||||
"The consume/export volumes need at least 1 GB": "Os volumes de consumo/exportação necessitam de pelo menos 1 GB",
|
||||
"The container could not be removed automatically:": "O recipiente não pôde ser removido automaticamente:",
|
||||
@@ -6309,6 +6366,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Os recipientes não precisam mais deles; uma atualização baixa as novas versões quando existem.",
|
||||
"The containers were created from downloaded OCI images": "Os recipientes foram criados a partir de imagens OCI descarregadas",
|
||||
"The coordinated backup was modified": "O backup coordenado foi modificado",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "O arquivo de credenciais foi alterado durante esta operação. Tente novamente;não foi sobrescrito.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "O driver atual será completamente desinstalado antes de instalar a nova versão. Continuar?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "A imagem atual do canal salvo será verificada e baixada. Recursos, caminhos e GPU são mantidos. O CT é interrompido durante a substituição e um backup nativo é criado primeiro.",
|
||||
"The current record is missing for": "Falta o registro atual para",
|
||||
@@ -6391,7 +6449,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "A sub-rede do firewall do monitor host foi alterada;nenhuma regra de firewall foi adicionada",
|
||||
"The host-monitor web interface uses the host network.": "A interface web host-monitor usa a rede host.",
|
||||
"The identity of a member was replaced": "A identidade de um membro foi substituída",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "O caminho do cache de imagens não é seguro. Verifique o armazenamento do modelo antes de tentar novamente.",
|
||||
"The image changes the user expected by the adapter": "A imagem muda o usuário esperado pelo adaptador",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "A imagem não pôde ser baixada ou verificada. Verifique o registro e o acesso ao armazenamento e tente novamente.",
|
||||
"The image could not be read from its registry:": "Não foi possível ler a imagem do seu registo:",
|
||||
"The image declares data paths that are still stored in the rootfs": "A imagem declara os caminhos de dados que ainda estão armazenados nos rootfs",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "A imagem não concedeu ao usuário do aplicativo acesso aos dispositivos; verifique seu init nativo. As permissões do anfitrião não foram relaxadas.",
|
||||
@@ -6404,6 +6464,8 @@
|
||||
"The image is in its registry, for one architecture.": "A imagem está em seu registro, para uma arquitetura.",
|
||||
"The image is in its registry.": "A imagem está no seu registo.",
|
||||
"The image is in its registry:": "A imagem está em seu registro:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "O manifesto da imagem falhou na verificação de integridade. Tente novamente ou entre em contato com o editor da imagem.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "A imagem ou tag não foi encontrada em {registry} ou esta conta não pode acessá-la. Verifique a referência.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "A imagem solicita NVIDIA, mas a máquina não tem driver NVIDIA funcionando",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "A imagem solicita desativar parte do confinamento AppArmor ou seccomp. Continue apenas se você confiar na imagem e aceitar este risco.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "A imagem solicita desativar parte do confinamento AppArmor ou seccomp. O Compose oferece um relaxamento opcional AppArmor ou seccomp; ele ficará desativado a menos que o usuário o selecione. Continue apenas se você confiar na imagem e aceitar este risco.",
|
||||
@@ -6541,7 +6603,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "O registro ou diagnóstico não pôde ser concluído; nenhuma atualização foi realizada.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "A recuperação não terminou. Reveja o log e escolha \"Recover\" novamente para este recipiente no menu de gerenciamento OCI.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "A recuperação não foi concluída. Revise o log e escolha \"{choice}\" novamente para este contêiner no menu de gerenciamento OCI.",
|
||||
"The registry authentication file is invalid; it was not changed.": "O arquivo de autenticação do registro é inválido;não foi alterado.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "O arquivo de autenticação do registro deve pertencer ao root com modo 600.",
|
||||
"The registry authentication file must have an absolute path.": "O arquivo de autenticação do registro deve ter um caminho absoluto.",
|
||||
"The registry authentication path cannot contain symbolic links.": "O caminho de autenticação do registro não pode conter links simbólicos.",
|
||||
"The registry authentication path has an unsafe parent directory.": "O caminho de autenticação do registro possui um diretório pai inseguro.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "O diretório de credenciais do registro deve pertencer ao root com modo 700.",
|
||||
"The registry did not return the saved image digest": "O registro não retornou o digest de imagem salvo",
|
||||
"The registry returned incomplete or unsupported image metadata.": "O registro retornou metadados de imagem incompletos ou não suportados.",
|
||||
"The registry returned invalid or unsupported image metadata.": "O registro retornou metadados de imagem inválidos ou não suportados.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "O remoto não existe; crie e autorize-o primeiro na WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "O instalador remoto deve correr como root no Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "O controle remoto já deve ser criado e autorizado na interface web Rclone. Esta operation reinicia o CT e publica duas visualizações FUSE no host.",
|
||||
@@ -6700,6 +6770,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Esta GPU é considerada incompatível com a passagem de GPU para uma VM no ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Este compartilhamento NFS é totalmente restrito — até mesmo o host root não pode gravar nele.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Esta VM requer etapas extras de instalação. Consulte o guia de instalação em:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Esta conta é para {registry}. Insira uma imagem desse registro.",
|
||||
"This action will:": "Esta ação irá:",
|
||||
"This application cannot be recovered yet:": "Este aplicativo ainda não pode ser recuperado:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Este aplicativo ainda não pode ser recuperado; nada foi alterado:",
|
||||
@@ -6731,8 +6802,10 @@
|
||||
"This explicitly marks the container as privileged": "Isso marca explicitamente o contêiner como privilegiado",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Este arquivo decide o que é montado e com quais privilégios. Instale-o somente se vier de uma fonte em que você confia.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Isso garante que os nós do dispositivo estejam disponíveis antes de aplicar a configuração da GPU LXC.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Esta arquitetura de host não é suportada pelo importador de imagens OCI.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Este host não tem assinatura ativa, mudar para o repositório sem assinatura? A fonte Enterprise PVE inacessível será desativada. As fontes Enterprise Ceph, se presentes, serão desativadas sem a escolha de um canal substituto do Ceph; configure o Ceph separadamente, se necessário.",
|
||||
"This image cannot be installed as it is described:": "Esta imagem não pode ser instalada como está descrita:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Esta imagem não possui imagem Linux compatível para este host ({architecture}).",
|
||||
"This image requires the host module": "Esta imagem requires o módulo da máquina",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Esta importação rejeita estes caminhos sem verificar se são arquivos ou diretórios.",
|
||||
"This installation will:": "Esta instalação irá:",
|
||||
@@ -6848,6 +6921,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Para usar a GPU novamente no LXC, execute Adicionar GPU ao LXC em GPUs e menu Coral-TPU",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Para usar a VM sem problemas, o host deve ser reiniciado antes de iniciá-lo.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Para usar este compartilhamento de um LXC, monte-o por meio de:",
|
||||
"Token": "Token",
|
||||
"Tool exit code:": "Código de saída da ferramenta:",
|
||||
"Tool output:": "Saída da ferramenta:",
|
||||
"Tools": "Ferramentas",
|
||||
@@ -6992,6 +7066,7 @@
|
||||
"Unsafe private configuration path": "Caminho de configuração privado inseguro",
|
||||
"Unsafe qBittorrent configuration path": "Caminho de configuração não seguro do qBittorrent",
|
||||
"Unsafe record": "Registo inseguro",
|
||||
"Unsafe registry credential lock.": "Bloqueio de credencial de registro inseguro.",
|
||||
"Unsafe registry directory": "Diretório de registro inseguro",
|
||||
"Unsafe registry lock": "Bloqueio de registo inseguro",
|
||||
"Unsafe rootfs for the capture": "Rootfs inseguros para a captura",
|
||||
@@ -7004,6 +7079,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Perfil do AppArmor OCI-LXC não suportado:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Perfil OCI-LXC seccomp não suportado:",
|
||||
"Unsupported Terminal": "Terminal não suportado",
|
||||
"Unsupported architecture for Figurine:": "Arquitetura não suportada pelo Figurine:",
|
||||
"Unsupported architecture:": "Arquitetura não suportada:",
|
||||
"Unsupported backup compression": "Compressão de backup não suportada",
|
||||
"Unsupported credential pattern:": "Padrão credential não suportado:",
|
||||
@@ -7056,6 +7132,7 @@
|
||||
"Update cancelled by user": "Atualização cancelada pelo usuário",
|
||||
"Update completed. Data kept.": "Actualização concluída. Dados guardados.",
|
||||
"Update completed. Press Enter to continue...": "Atualização concluída. Pressione Enter para continuar...",
|
||||
"Update credentials": "Atualizar credenciais",
|
||||
"Update every container of the application": "Atualizar cada recipiente do aplicativo",
|
||||
"Update kernel to compatible version": "Atualize o kernel para uma versão compatível",
|
||||
"Update now?": "Actualizar agora?",
|
||||
@@ -7122,8 +7199,10 @@
|
||||
"Use a custom path": "use um caminho personalizado",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Use um LXC privilegiado para fluxos de trabalho de servidor/cliente NFS.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Use um LXC privilegiado para fluxos de trabalho cliente/servidor Samba.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Use um nome de host de registro, por exemplo ghcr.io ou registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Use um arquivo de chave privada SSH existente neste host",
|
||||
"Use an existing keyfile": "Use um arquivo-chave existente",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Use uma referência de imagem, por exemplo ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Use como está – mantenha os dados e o sistema de arquivos",
|
||||
"Use content types according to your use case.": "Use tipos de conteúdo de acordo com seu caso de uso.",
|
||||
"Use default": "usar padrão",
|
||||
@@ -7163,6 +7242,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "WebUI amigável para LLMs (formerly Ollama WebUI)",
|
||||
"Username": "Nome de usuário",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Nome de usuário (por exemplo, root@pam ou user@pbs!token):",
|
||||
"Username / token": "Nome de usuário/token",
|
||||
"Username and password": "Nome de usuário e senha",
|
||||
"Username and password will be cleared.": "O nome de usuário e a senha serão apagados.",
|
||||
"Username cannot be empty.": "O nome de usuário não pode ficar vazio.",
|
||||
@@ -7262,6 +7342,7 @@
|
||||
"Verifying Ceph packages availability...": "Verificando a disponibilidade dos pacotes do Ceph...",
|
||||
"Verifying all utilities status": "Verificando o status de todos os utilitários",
|
||||
"Verifying disk accessibility in CT": "Verificando a acessibilidade do disco no CT",
|
||||
"Verifying registry access. Please wait...": "Verificando o acesso ao registro. Por favor, aguarde...",
|
||||
"Verifying the backups...": "Verificando os backups...",
|
||||
"Verifying the image integrity...": "Verificando a integridade da imagem...",
|
||||
"Version": "Versão",
|
||||
@@ -7561,6 +7642,7 @@
|
||||
"assembling": "montagem",
|
||||
"automatically. Install it manually inside the container.": "automaticamente. Instale-o manualmente dentro do contêiner.",
|
||||
"automatically. Reboot LXC to fully release.": "automaticamente. Reinicie o LXC para liberar completamente.",
|
||||
"available": "Disponível",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "disponível para montagens vinculadas LXC via 'LXC Mount Manager'",
|
||||
"available in this same GPU and TPU menu.": "disponível neste mesmo menu GPU e TPU.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "backup em /etc/fstab.proxmenux.bak",
|
||||
@@ -7913,6 +7995,7 @@
|
||||
"runs in": "corre para dentro",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "caminhos seguros agora (configs, pacotes, /etc, /root, ...)",
|
||||
"same MAC": "mesmo MAC",
|
||||
"saved": "Salvo",
|
||||
"seconds (default)": "segundos (padrão)",
|
||||
"see log:": "veja o log:",
|
||||
"selected by default": "selecionado por padrão",
|
||||
@@ -8031,8 +8114,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot removido (instantâneos existentes preservados no pool)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "Comando zpool não encontrado. Instale zfsutils-linux e tente novamente.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool não encontrado. Instale zfsutils-linux e tente novamente.",
|
||||
"{count} saved account.": "Conta salva {count}.",
|
||||
"{count} saved accounts.": "Contas salvas {count}.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} já existe e pertence a outro usuário do host, portanto {app} não pode gravar nele.\n\nProxMenux pode adicionar regras de acesso (ACL) a este diretório, a tudo o que ele contém e ao que for criado nele depois, para os usuários e grupos com os quais {app} é executado no host (IDs {ids}). O proprietário dos arquivos não muda e o que hoje os lê ou grava continua fazendo isso; o proprietário do diretório também obtém acesso aos arquivos que {app} cria.\n\nConceder acesso ao {app} a este diretório?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} já existe e pertence a outro usuário do host, portanto {app} não pode gravar nele.\n\nProxMenux pode adicionar uma regra de acesso (ACL) para a identidade que {app} usa no host (UID {uid}).Nada do que existe muda o proprietário ou as permissões: tudo o que lê ou grava esses arquivos hoje continua fazendo isso, e o proprietário do diretório também obtém acesso aos arquivos que {app} cria.\n\nConceder acesso ao {app} a este diretório?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} respondeu com HTTP simples. Utilize um registro com HTTPS; A verificação TLS permanece habilitada.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} não respondeu em {timeout} segundos. Tente novamente mais tarde.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "Mensagem técnica para Proxmox e TI. Traduzindo: {registry} é uma solicitação de limitação de taxa. Espere um pouco e tente novamente.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} recusou acesso a esta imagem:\n{reference}\n\nSe a imagem for privada, faça login com uma conta que possa obtê-la.\n\nEntrar agora?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} relatou um erro no servidor. Tente novamente mais tarde.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} retornou metadados de imagem inválidos ou não suportados.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "- A restauração completa/personalizada irá ignorar os caminhos vinculados ao kernel",
|
||||
"— disk may be busy. Skipping fstab removal.": "— o disco pode estar ocupado. Ignorando a remoção do fstab.",
|
||||
"— restore proceeds as same-version (verified safe)": "- a restauração prossegue como a mesma versão (seguro verificado)",
|
||||
|
||||
+95
-4
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Prístupový mostík pre Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "Prístup nebolo možné úplne udeliť; aplikácia možno nebude môcť zapisovať do:",
|
||||
"Access could not be granted; the application cannot write to:": "Prístup nebolo možné udeliť; aplikácia nemôže písať na:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Prístup odmietnutý {registry}. Skontrolujte názov obrázka a prihláste sa z účtov Registry.",
|
||||
"Access granted to the application on:": "Prístup udelený aplikácii dňa:",
|
||||
"Access password of the web interface (optional)": "Heslo na prístup do webového rozhrania (voliteľné)",
|
||||
"Access profile:": "Profil prístupu:",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Pokročilé",
|
||||
"Advanced Diagnostics": "Pokročilá diagnostika",
|
||||
"Advanced Network Diagnostics": "Pokročilá diagnostika siete",
|
||||
"Advanced settings": "Rozšírené nastavenia",
|
||||
"Advanced: every setting of the container": "Pokročilé: každé nastavenie kontajnera",
|
||||
"Affected LXC containers": "Dotknuté LXC kontajnery",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "Po dokončení nastavenia GPU spustite VM ručne, keď bude server pripravený.",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Ďalšia OCI operation používa inštančný register. Počkajte, kým to dokončíte a znovu otvoríte toto menu; žiadna nádoba nie je upravená.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "Ďalšia operácia OCI používa register inštancií. Počkajte, kým to skončí.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "Ďalšia OCI operation používa register. Táto operation sa nezačala.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "Prebieha ďalšia operácia ProxMenux OCI. Skúste to znova, keď to skončí.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Existuje iná konfigurácia ZRAM alebo ju nebolo možné skontrolovať; systemd-zram-generator bol zachovaný",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "Existuje iná konfigurácia generátora ZRAM; refusing to overwrite it:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "Existuje ďalšie nastavenie výmeny ZRAM; odmietnutie jeho výmeny:",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Iný prípad použitia",
|
||||
"Another job that writes to the same storage still starts them.": "Iná úloha, ktorá zapisuje do rovnakého úložiska, ich spúšťa naďalej.",
|
||||
"Another node, typed by hand": "Ďalší uzol, zadaný ručne",
|
||||
"Another registry account operation is running. Try again when it finishes.": "Prebieha iná operácia registrového účtu. Skúste to znova, keď to skončí.",
|
||||
"Another stack operation is pending": "Ďalší zásobník operation čaká",
|
||||
"Application": "Uplatňovanie",
|
||||
"Application registered on this host:": "Aplikácia registrovaná na tomto hostiteľovi:",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Prihlásenie",
|
||||
"Authentication & Security": "Overovanie a zabezpečenie",
|
||||
"Authentication Error": "Chyba prihlásenia",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Autentifikácia pre {registry} zlyhala. Skontrolujte oprávnenia účtu a tokenu.",
|
||||
"Authentication failed.": "Prihlásenie zlyhalo.",
|
||||
"Authentication required:": "Vyžaduje prihlásenie:",
|
||||
"Authentication:": "Prihlásenie:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Nedá sa vyriešiť domovský adresár kontajnera:",
|
||||
"Cannot validate credentials - no shares available for testing.": "Prihlasovacie údaje sa nedajú overiť - nie sú dostupné žiadne zdieľania na test.",
|
||||
"Cannot verify the reused disk:": "Nie je možné overiť znovu použitý disk:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Nie je možné zapísať archív obrázkov do {storage}. Skontrolujte prístup k úložisku a stav pripojenia.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Nie je možné udržať si schopnosti a zároveň ich znížiť.",
|
||||
"Category": "Kategória",
|
||||
"Caution: Maximum mode generates more heat.": "Pozor: maximálny režim vytvára viac tepla.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Skontrolovať stav Samby",
|
||||
"Check VM disk/PCI slots": "Skontrolovať diskové/PCI sloty VM",
|
||||
"Check VM passthrough settings": "Skontrolovať nastavenie VM passthrough",
|
||||
"Check access to an image": "Kontrola prístupu k obrázku",
|
||||
"Check connectivity with another host": "Skontrolovať spojenie s iným hostom",
|
||||
"Check container mount points": "Skontrolovať body pripojenia kontajnera",
|
||||
"Check if container is unprivileged:": "Skontrolovať, či je kontajner neprivilegovaný:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Skontrolujte, že:",
|
||||
"Check the error messages above for details.": "Podrobnosti nájdete v chybových hláškach vyššie.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Skontrolujte odkaz na obraz a prístup k registru. Ak register nie je dostupný, skúste to neskôr. Súkromný register vyžaduje prihlasovacie údaje, ktoré zatiaľ nie sú podporované.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Skontrolujte odkaz na obrázok a prístup do registra. Ak register nie je dostupný, skúste to znova neskôr. Pre súkromný obrázok sa prihláste z účtov Registry v ponuke OCI.",
|
||||
"Check the service status manually if needed.": "V prípade potreby skontrolujte stav služieb ručne.",
|
||||
"Checking MOTD configuration...": "Kontrolujem nastavenie MOTD...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Kontrolujem stav ovládača NVIDIA pomocou nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Kontrolujem voľné miesto v /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Kontrolujem, či je systémový disk SSD alebo M.2...",
|
||||
"Checking if the server belongs to OVH...": "Kontrolujem, či server patrí pod OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Kontrola prístupu k obrázku a metadát. Čakajte prosím...",
|
||||
"Checking kernel headers and build tools...": "Kontrolujem kernel headers a nástroje na zostavenie...",
|
||||
"Checking remaining interfaces": "Kontrolujem zostávajúce rozhrania",
|
||||
"Checking that the container keeps running...": "Kontrola, či kontajner beží...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Vyberte režim iperf3:",
|
||||
"Choose options to configure:": "Vyberte možnosti, ktoré chcete nastaviť:",
|
||||
"Choose specific VMs/CTs": "Vyberte konkrétne VM/CT",
|
||||
"Choose storage for the downloaded image.": "Vyberte úložisko pre stiahnutý obrázok.",
|
||||
"Choose the driver version for Coral M.2:": "Vyberte verziu ovládača pre Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Vyberte súborový systém pre nový oddiel:",
|
||||
"Choose the release channel to use:": "Vyberte vetvu vydania, ktorú chcete používať:",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "Nepodarilo sa zverejniť čakajúce obnovenie. Predchádzajúce čakajúce obnovenie bolo zachované.",
|
||||
"Could not push the key. Check the password and that": "Kľúč sa nepodarilo odoslať. Skontrolujte heslo a to, že",
|
||||
"Could not query the image registry": "Nepodarilo sa nájsť obrazový register",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "Nepodarilo sa dosiahnuť {registry}. Skontrolujte jeho adresu, DNS a prístup k sieti.",
|
||||
"Could not read SMART data from": "SMART dáta sa nepodarilo prečítať z",
|
||||
"Could not read VM configuration.": "Nastavenie VM sa nepodarilo prečítať.",
|
||||
"Could not read the CUDA compute capability": "Nepodarilo sa prečítať výpočtovú schopnosť CUDA",
|
||||
"Could not read the NVIDIA driver version": "Nepodarilo sa prečítať verziu ovládača NVIDIA",
|
||||
"Could not read the host firewall rules": "Pravidlá firewallu hostiteľa sa nepodarilo načítať",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Nepodarilo sa prečítať obrázok z {registry}. Skontrolujte referenciu a prihláste sa z účtov Registra.",
|
||||
"Could not read this job.": "Túto úlohu sa nepodarilo prečítať.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "Nepodarilo sa uvoľniť stránky ZRAM; existujúci profil zostáva aktívny",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Automatické znovupripojenie zlyhalo. Skúste to ručne alebo skontrolujte prihlasovacie údaje.",
|
||||
"Could not remove VM automatically. Run manually:": "VM sa nepodarilo odstrániť automaticky. Spustite ručne:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "Nepodarilo sa odstrániť profil ZRAM; konfigurácia bola obnovená",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "Nepodarilo sa odstrániť profil ZRAM; konfigurácia bola obnovená, ale swap nebolo možné reštartovať",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Nepodarilo sa odstrániť poverenia pre {registry}; poverenia uloženého súboru neboli zmenené.",
|
||||
"Could not remove previous DKMS tree at": "Nepodarilo sa odstrániť predchádzajúci DKMS strom v",
|
||||
"Could not reserve a private network for the stack": "Nepodarilo sa rezervovať súkromnú sieť pre stack",
|
||||
"Could not resolve the Compose user:": "Nepodarilo sa vyriešiť používateľa Compose:",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Virtuálne zobrazenie VM sa nepodarilo nastaviť na vga: std",
|
||||
"Could not set boot order for": "Poradie bootovania sa nepodarilo nastaviť pre",
|
||||
"Could not set the container entrypoint": "Nepodarilo sa nastaviť vstupný bod kontajnera",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Nepodarilo sa prihlásiť do {registry}. Skontrolujte prístup k registrom a povolenia tokenov.",
|
||||
"Could not stage pending restore path:": "Nepodarilo sa pripraviť cestu obnovenia:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "Nepodarilo sa pripraviť čakajúce obnovenie. Nič nové nebolo naplánované.",
|
||||
"Could not stop LXC": "LXC sa nepodarilo zastaviť",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Vytváranie súkromnej siete...",
|
||||
"Creating the temporary data container": "Vytvorenie dočasného dátového kontajnera",
|
||||
"Creative & Design": "Kreativita a dizajn",
|
||||
"Credential helper": "Pomocník poverení",
|
||||
"Credential storage and access": "Úložisko poverení a prístup",
|
||||
"Credentials are correct": "Prihlasovacie údaje sú správne",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Prihlasovacie údaje sú vymazané. jwt_secret a API tokeny zostali zachované.",
|
||||
"Credentials file created securely.": "Súbor s prihlasovacími údajmi bol bezpečne vytvorený.",
|
||||
"Credentials file removed.": "Súbor s prihlasovacími údajmi bol odstránený.",
|
||||
"Credentials file:": "Súbor s prihlasovacími údajmi:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Súbor poverení:\n{path}\n\nVo vlastníctve root; režim adresárov 700 a režim súborov 600.\nZákladné poverenia sú zakódované pomocou base64, nie sú zašifrované.\nPomocníci poverení využívajú svoje vlastné úložisko.\n\nPoužite prístupový token s povolením na stiahnutie obrázkov.\nNakonfigurujte poverenia na každom uzle, ktorý sťahuje obrázky.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Súbor poverení:\n{path}\n\nVo vlastníctve root; režim adresárov 700 a režim súborov 600.\nZákladné poverenia sú zakódované pomocou base64, nie sú zašifrované.\nPomocníci poverení využívajú svoje vlastné úložisko.\n\nPoužite prístupový token s povolením na stiahnutie obrázkov.\nKaždý uzol klastra používa tu uložené účty.",
|
||||
"Credentials validated successfully": "Prihlasovacie údaje boli úspešne overené",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Obnova medzi hostami: ID hostí zo zálohy sa prekrývajú so živými ID na cieli:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Obnova medzi kernelmi - cesty viazané na kernel boli zlúčené, nie skopírované",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Štandardné prihlásenie",
|
||||
"Default options": "Predvolené možnosti",
|
||||
"Default options read/write": "Predvolené možnosti čítanie/zápis",
|
||||
"Default settings": "Predvolené nastavenia",
|
||||
"Default will be used:": "Použije sa predvolené:",
|
||||
"Default:": "Predvolené:",
|
||||
"Default: only what the application needs": "Štandardne: len to, čo aplikácia potrebuje",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs je robot Discord pre žiadanie médií cez arr backends, napísané v Rust.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander je free cross platform open source správca súborov s dvoma panelmi vedľa seba. Je inšpirovaný Total Commander a obsahuje niektoré nové nápady.",
|
||||
"Download Spotify music with album art and metadata": "Stiahnuť Spotify hudbu s albumom a metadátami",
|
||||
"Download an image to template storage": "Stiahnite si obrázok do úložiska šablón",
|
||||
"Download an oci-compose from an address": "Stiahnuť oci-compose z adresy",
|
||||
"Download failed for all attempted URLs": "Sťahovanie zlyhalo zo všetkých vyskúšaných adries",
|
||||
"Download its Compose file from an address": "Stiahnuť súbor Compose z URL adresy",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Sťahujem logo Proxmology...",
|
||||
"Downloading UUP converter...": "Sťahujem UUP konvertor...",
|
||||
"Downloading amdgpu_top": "Sťahujem amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Stiahnutie a overenie obrázka.\nMôže to trvať niekoľko minút. Čakajte prosím...",
|
||||
"Downloading official installer...": "Sťahujem oficiálny inštalátor...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "Stiahnutie už existujúcich šifrovaných záloh z tohto hosta zlyhá, ak ste si nenechali kópiu aktuálneho kľúča.",
|
||||
"Downloading the image:": "Sťahovanie obrázku:",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Zadajte názov ZFS poolu pre vybraný disk:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Zadajte názov mount pointu (použije sa ako /mnt/<name>):",
|
||||
"Enter a name for the new virtual machine:": "Zadajte názov novej virtuálnej mašiny:",
|
||||
"Enter a non-empty password or access token on a single line.": "Zadajte neprázdne heslo alebo prístupový token na jeden riadok.",
|
||||
"Enter a number, or write or paste a command:": "Zadajte číslo alebo napíšte či vložte príkaz:",
|
||||
"Enter a systemd calendar event, e.g.:": "Zadajte udalosť systémového kalendára, napr.:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Zadajte použiteľnú IPv4 adresu s predponou, napríklad",
|
||||
"Enter a valid registry username.": "Zadajte platné používateľské meno registra.",
|
||||
"Enter backup file (.zst):": "Zadajte súbor zálohy (.zst):",
|
||||
"Enter backup path (.tar.zst):": "Zadajte cestu k zálohe (.tar.zst):",
|
||||
"Enter backup path (.vma.zst):": "Zadajte cestu k zálohe (.vma.zst):",
|
||||
@@ -2287,12 +2310,12 @@
|
||||
"Failed to download Proxmology logo": "Logo Proxmology sa nepodarilo stiahnuť",
|
||||
"Failed to download VirtIO driver ISO.": "VirtIO ISO s ovládačmi sa nepodarilo stiahnuť.",
|
||||
"Failed to download amdgpu_top": "amdgpu_top sa nepodarilo stiahnuť",
|
||||
"Failed to download loader image.": "Nepodarilo sa stiahnuť obrázok načítania.",
|
||||
"Failed to download loader image.": "Nepodarilo sa stiahnuť obraz zavádzača.",
|
||||
"Failed to edit /etc/fstab — remove the line manually.": "Nepodarilo sa upraviť /etc/fstab. Riadok odstráňte ručne.",
|
||||
"Failed to enable ZFS autotrim for pool:": "ZFS autotrim sa nepodarilo zapnúť pre pool:",
|
||||
"Failed to enable automatic time synchronization": "Automatickú synchronizáciu času sa nepodarilo zapnúť",
|
||||
"Failed to extract OVA file:": "OVA súbor sa nepodarilo rozbaliť:",
|
||||
"Failed to extract a nonempty loader image.": "Nepodarilo sa extrahovať neprázdny obrázok načítania.",
|
||||
"Failed to extract a nonempty loader image.": "Nepodarilo sa extrahovať neprázdny obraz zavádzača.",
|
||||
"Failed to extract package": "Balík sa nepodarilo rozbaliť",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "Nepodarilo sa stiahnuť Google Coral GPG kľúč. Skontrolujte",
|
||||
"Failed to format disk as": "Disk sa nepodarilo naformátovať ako",
|
||||
@@ -2349,7 +2372,7 @@
|
||||
"Failed to retrieve Fastfetch download URL.": "Adresu na stiahnutie Fastfetch sa nepodarilo získať.",
|
||||
"Failed to retrieve loader release metadata.": "Nepodarilo sa načítať metadáta vydania zavádzača.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "Inštalátor log2ram sa nepodarilo spustiť. Skontrolujte /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "Nepodarilo sa uložiť obrázok načítania.",
|
||||
"Failed to save loader image.": "Nepodarilo sa uložiť obraz zavádzača.",
|
||||
"Failed to set VM description": "Popis VM sa nepodarilo nastaviť",
|
||||
"Failed to set timezone - keeping current settings": "Časové pásmo sa nepodarilo nastaviť - ponechávam aktuálne nastavenie",
|
||||
"Failed to start CT": "CT sa nepodarilo spustiť",
|
||||
@@ -2645,7 +2668,7 @@
|
||||
"HAOS One is a community image that runs Docker inside the container. The LXC stays unprivileged, but the inner AppArmor profiles may not be available. The first start downloads Home Assistant Core and its add-ons. If the check fails, the CT and /mnt/data are kept for diagnosis.": "HAOS One je obraz spoločenstva, ktorý prevádzkuje Docker vnútri kontajnera. LXC zostáva neprivilegovaný, ale vnútorné profily AppArmor nemusí byť k dispozícii. Prvý štart stiahne Home Assistant jadro a jeho doplnky. Ak kontrola zlyhá, CT a / mnt/ dáta sa uchovávajú na určenie diagnózy.",
|
||||
"HAOS One profile declined": "Profil HAOS One klesol",
|
||||
"HAOS One requires an unprivileged unmanaged LXC with nesting and keyctl, 2 cores, 2048 MB RAM, rootfs of at least 12 GB and /mnt/data of at least 16 GB on a container volume included in backups": "HAOS One requires an unprivileged unmanaged LXC with nestering and keyctl, 2 cores, 2048 MB RAM, rootfs najmenej 12 GB a /mnt/data najmenej 16 GB on a container volume included in backions",
|
||||
"HTML5 Network Speed Test Server.": "HTML5 Network Speed Test Server.",
|
||||
"HTML5 Network Speed Test Server.": "HTML5 Network Speed Test Server.",
|
||||
"HTTP service check without a saved URL": "Kontrola služby HTTP bez uloženého URL",
|
||||
"Habridge emulates Philips Hue API to other home automation gateways such as an Amazon Echo/Dot Gen 1 (gen 2 has issues discovering ha-bridge) or other systems that support Philips Hue. The Bridge handles basic commands such as On, Off and brightness commands of the hue protocol. This bridge can control most devices that have a distinct API.": "Habridge napodobňuje Philipsa Spoločnosť Amazon tvrdí, že spoločnosť LuxOpCo by mala mať prístup k webovým stránkam spoločnosti LuxOpCo. Most riadi základné príkazy, ako je On, Off a jas príkazy protokolu odtieňov. Tento most môže ovládať väčšinu zariadení, ktoré majú odlišné API.",
|
||||
"HandBrake is an open-source tool, built by volunteers, for converting video from nearly any format to a selection of modern, widely supported codecs.": "HandBrake je open-source nástroj, postavený dobrovoľníkmi, pre konverziu video z takmer akéhokoľvek formátu na výber moderných, široko podporovaných kodekov.",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Pomoc a informácie",
|
||||
"Help and Info Commands": "Pomocné a informačné príkazy",
|
||||
"Helper-Scripts logo applied": "Logo Helper-Scripts bolo použité",
|
||||
"Helper:": "Pomocník:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Skryté kvôli bezpečnosti",
|
||||
"Hidden:": "Skryté:",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Ak máte v DHCP statickú rezerváciu pre starú MAC adresu, aktualizujte ju.",
|
||||
"Image": "Image",
|
||||
"Image Source Directory": "Zdrojový priečinok obrazov",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Prístup k obrázku bol potvrdený.\n\n{reference}\n\nArchitektúra: {architecture}\nVerzia: {version}\nVeľkosť na stiahnutie: {size}\nZhrnutie: {digest}",
|
||||
"Image cache": "Comment",
|
||||
"Image compatibility restored:": "Kompatibilita s obrázkom obnovená:",
|
||||
"Image compatibility verified:": "Kompatibilita s obrázkom overená:",
|
||||
"Image directory:": "Priečinok s obrazmi:",
|
||||
"Image download failed:": "Sťahovanie obrázku zlyhalo:",
|
||||
"Image downloaded": "Stiahnutý obrázok",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Obrázok bol stiahnutý a overený.\n\n{reference}\n\nSkladovanie: {storage}\nVeľkosť archívu: {size}\nArchív: {archive}\n\nNebol vytvorený žiadny kontajner.\nProxMenux po úspešných aktualizáciách odstráni nepoužívané obrázky z vyrovnávacej pamäte.",
|
||||
"Image file not found:": "Súbor obrazu sa nenašiel:",
|
||||
"Image imported:": "Obraz importovaný:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "Overenie integrity obrázka zlyhalo. Čiastočné stiahnutie bolo zahodené; skúste to znova.",
|
||||
"Image integrity verified": "Potvrdená integrita obrázku",
|
||||
"Image not allowed for the host monitor profile": "Obrázok nie je povolený pre profil monitora hostiteľa",
|
||||
"Image reference": "Odkaz na obrázok",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Odkaz na image (napríklad ghcr.io/user/aplikácia:latest)",
|
||||
"Image selection was cancelled": "Výber image bol zrušený",
|
||||
"Image that is not in the catalog": "Image, ktorý nie je v katalógu",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Nainštalovať Sambu vo vnútri CT:",
|
||||
"Install ZFS auto-snapshot": "Nainštalovať ZFS auto-snapshot",
|
||||
"Install a version from the branch the kernel names.": "Nainštalujte verziu z vetvy s názvami jadra.",
|
||||
"Install an image as a native LXC": "Nainštalujte obrázok ako natívny LXC",
|
||||
"Install an image that is not in the catalog": "Inštalovať obraz, ktorý nie je v katalógu",
|
||||
"Install analysis tools": "Nainštalovať analytické nástroje",
|
||||
"Install and configure": "Nainštalovať a nastaviť",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "Inštalácia sa dokončila, ale ovládače nie sú načítané. Možno bude potrebný reštart.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Inštalácia neúplná. Tieto nádoby a ich údaje sa uchovávajú:",
|
||||
"Installation log:": "Záznam inštalácie:",
|
||||
"Installation settings": "Nastavenia inštalácie",
|
||||
"Installation summary": "Zhrnutie inštalácie",
|
||||
"Installed": "Nainštalované",
|
||||
"Installed at:": "Nainštalované v:",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Neplatná cesta k hostiteľovi:",
|
||||
"Invalid host-monitor firewall plan": "Neplatný plán firewallu pre monitor hostiteľa",
|
||||
"Invalid image probe descriptor": "Neplatný deskriptor obrazovej sondy",
|
||||
"Invalid image tag.": "Neplatná značka obrázka.",
|
||||
"Invalid input": "Neplatný vstup",
|
||||
"Invalid internal volume": "Neplatný vnútorný objem",
|
||||
"Invalid list:": "Neplatný zoznam:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Neplatná aplikácia",
|
||||
"Invalid sysctl value:": "Neplatná sysctl hodnota:",
|
||||
"Invalid template storage": "Neplatná pamäť šablóny",
|
||||
"Invalid template storage name.": "Neplatný názov úložiska šablóny.",
|
||||
"Invalid tmpfs options:": "Neplatné možnosti tmpfs:",
|
||||
"Invalid tmpfs path:": "Neplatná cesta tmpfs:",
|
||||
"Invalid tmpfs size:": "Neplatná veľkosť tmpfs:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Zápis z Log2RAM je naplánovaný každých",
|
||||
"Log:": "Záznam:",
|
||||
"Logged-in users": "Prihlásení používatelia",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "Prihlásenie do {registry} vypršalo. Uložené poverenia sa nezmenili.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "Odhlásenie z {registry} vypršalo. Prihlasovacie údaje uloženého súboru sa nezmenili.",
|
||||
"Logrotate optimization completed": "Optimalizácia logrotate je dokončená",
|
||||
"Logrotate service restarted successfully": "Služba logrotate bola úspešne reštartovaná",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop je ľahký moderný hudobný prehrávač navrhnutý tak, aby pracoval vynikajúco na GNOME desktop prostredí.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Spravovať vlastné cesty (pridať / odstrániť priečinky)",
|
||||
"Manage installed OCI applications": "Spravovať nainštalované aplikácie OCI",
|
||||
"Manage local backup target": "Spravovať lokálny cieľ záloh",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Správa súkromných registrov obrázkov.\nUložené poverenia umožňujú ProxMenux prístup k vašim súkromným obrázkom.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Spravujte účty registra ako root na uzle Proxmox.",
|
||||
"Managed disks must have backup enabled and a valid size": "Spravované disky musia mať zapnuté zálohovanie a platnú veľkosť",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Správa Nginx proxy hostiteľov s jednoduchým, výkonným rozhraním.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Ručný návod v termináli (disky a úložiská)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Nenašli sa dostupné Samba servery.",
|
||||
"No accessible exports found.": "Nenašli sa žiadne dostupné exporty.",
|
||||
"No accessible shares found.": "Nenašli sa dostupné zdieľania.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Žiadne aktívne úložisko Proxmox neakceptuje archívy šablón OCI.",
|
||||
"No active exports or showmount not available": "Nie sú aktívne exporty alebo príkaz showmount nie je dostupný",
|
||||
"No active session": "Žiadna aktívna relácia",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Žiadne aktívne predplatné a žiadne použiteľné úložisko PVE. Neinteraktívny režim nemôže zmeniť zdroje APT; nakonfigurujte ich v časti Uzol > Aktualizácie > Úložiská.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Žiadne nedávne",
|
||||
"No recent Samba servers found.": "Nenašli sa žiadne nedávne Samba servery.",
|
||||
"No registered OCI containers are available for selection on this host.": "Na tomto hostiteľovi nie sú dostupné žiadne registrované kontajnery OCI.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Na {registry} sa nenašlo žiadne API registra. Skontrolujte názov hostiteľa a port.",
|
||||
"No restored OCI application is waiting to be recovered.": "Žiadna obnovená aplikácia OCI nečaká na obnovenie.",
|
||||
"No results": "Žiadne výsledky",
|
||||
"No routing information found.": "Nenašli sa žiadne informácie o smerovaní.",
|
||||
@@ -4297,7 +4335,9 @@
|
||||
"Not an OVH server, skipping RTM installation": "Toto nie je OVH server, inštalácia RTM sa preskočí",
|
||||
"Not currently mounted": "Momentálne nepripojené",
|
||||
"Not currently mounted — skipping umount.": "Nie je pripojené, odpojenie preskakujem.",
|
||||
"Not declared": "Nedeklarované",
|
||||
"Not enough free space for the backup": "Nedostatok voľného priestoru pre zálohu",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Nedostatok voľného miesta na {storage}. Uvoľnite miesto alebo vyberte iné úložisko.",
|
||||
"Not found": "Nenájdené",
|
||||
"Not found in the OCI archive:": "Nenájdené v archíve OCI:",
|
||||
"Not imported:": "Neimportované:",
|
||||
@@ -4390,6 +4430,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Automaticky je možné prijať iba uzly Intel/AMD DRM, Coral a USB",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Automaticky je možné prijať iba uzly Intel/AMD DRM, Coral, NPU a USB",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Tieto nastavenia používa len roj Docker, takže sa nepoužívajú:",
|
||||
"Only a full sha256 image digest is supported.": "Podporovaný je iba úplný súhrn obrázkov sha256.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Externé zmeny môže prijať iba nainštalovaná samostatná inštancia OCI",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Je možné prijať iba zálohované zväzky Proxmox",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Na privilegovaný kontajner prevádzajte iba vtedy, keď je to naozaj potrebné.",
|
||||
@@ -4543,6 +4584,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Passthrough môže fungovať aj bez ROM súboru.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "Priame priradenie môže fungovať, ale spoľahlivý štart alebo reštart VM nie je zaručený.",
|
||||
"Password": "Heslo",
|
||||
"Password / access token (image pull permission)": "Heslo / prístupový token (povolenie na stiahnutie obrázka)",
|
||||
"Password Mismatch": "Heslá sa nezhodujú",
|
||||
"Password cannot be empty.": "Heslo nesmie byť prázdne.",
|
||||
"Password confirmation cannot be empty.": "Potvrdenie hesla nesmie byť prázdne.",
|
||||
@@ -4808,7 +4850,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux pripája adresáre, nie jednotlivé súbory, takže tento obrázok ešte nie je možné nainštalovať.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux môže na hostovi nastaviť otvorené oprávnenia pre tento NFS priečinok, aby kontajner mohol čítať aj zapisovať:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux ho môže znovu pripojiť s otvorenými oprávneniami, aby každý LXC mohol čítať aj zapisovať.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux nemôže nainštalovať tento obrázok automaticky. Namiesto toho importujte jeho súbor Compose.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux nevie z hosta prepísať oprávnenia nastavené na NFS serveri.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux nemohol preložiť tento obrázok. Skúste importovať jeho súbor Compose z OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "Úpravy ProxMenux boli odstránené z bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux nedáva kontajner systém svojho hostiteľa.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux ich neinštaluje. Inštalácia sa pýta, ako sa k nim pripojiť.",
|
||||
@@ -4929,6 +4973,7 @@
|
||||
"Reading SMART data...": "Čítam SMART dáta...",
|
||||
"Reading SMART self-test log...": "Čítam log SMART samo-testu...",
|
||||
"Reading full SMART report...": "Čítam úplnú SMART správu...",
|
||||
"Reading image metadata. Please wait...": "Čítanie metadát obrázkov. Čakajte prosím...",
|
||||
"Real-time Performance Monitoring": "Monitorovanie výkonnosti v reálnom čase",
|
||||
"Real-time bandwidth usage (press q to exit)": "Využitie priepustnosti v reálnom čase (ukončíte klávesom q)",
|
||||
"Real-time collaborative document editor": "Kolektívne editor dokumentov v reálnom čase",
|
||||
@@ -5021,6 +5066,9 @@
|
||||
"Register mount path in Proxmox:": "Zaregistrovať cestu pripojenia v Proxmoxe:",
|
||||
"Registering disk as Proxmox storage...": "Registrujem disk ako úložisko Proxmoxu...",
|
||||
"Registering module with DKMS...": "Registrujem modul v DKMS...",
|
||||
"Registry accounts": "Účty v registri",
|
||||
"Registry hostname": "Názov hostiteľa registra",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Register: {registry}\nÚčet: {account}\nOverenie: {method}\n\nUložené poverenia sa overia pri prístupe k obrázku.",
|
||||
"Reinstall / update Coral drivers": "Preinštalovať / aktualizovať ovládače Coral",
|
||||
"Reinstall Fail2Ban": "Preinštalovať Fail2Ban",
|
||||
"Reinstall Lynis": "Preinštalovať Lynis",
|
||||
@@ -5092,8 +5140,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Odstrániť zastaraný meta-balík systemd-boot",
|
||||
"Remove old repository files:": "Odstráňte staré súbory repozitárov:",
|
||||
"Remove passthrough device from VM": "Odstrániť passthrough zariadenie z VM",
|
||||
"Remove saved credentials": "Odstráňte uložené poverenia",
|
||||
"Remove subscription banner": "Odstrániť hlásenie o predplatnom",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Odstrániť aplikáciu? Jeho kontajnerové disky sa vymažú a iba záloha ich môže vrátiť späť.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Odstrániť uložené poverenia pre {registry}?\nSpustené aplikácie budú naďalej fungovať.",
|
||||
"Remove the unprivileged flag from configuration:": "Odstrániť príznak neprivilegovaného kontajnera z nastavenia:",
|
||||
"Remove unused packages and their config": "Odstrániť nepoužívané balíky aj ich nastavenia",
|
||||
"Remove: delete the application and its containers": "Odstrániť: odstrániť aplikáciu a jej obaly",
|
||||
@@ -5415,6 +5465,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Uložiť a klasifikovať články. Prečítajte si ich neskôr. Slobodne.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Uložte si frázu TERAZ na bezpečné miesto, ešte pred pokračovaním.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Uložiť tento Borg cieľ, aby ste údaje nemuseli zadávať znova?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Uložené poverenia pre {registry} boli odstránené.\nOstatné súbory poverení Skopeo/Docker sa spravujú samostatne.",
|
||||
"Saved record removed": "Uložený záznam odstránený",
|
||||
"Saving changes...": "Ukladajú sa zmeny...",
|
||||
"Saving the new configuration": "Ukladanie novej konfigurácie",
|
||||
@@ -5795,9 +5846,11 @@
|
||||
"Shutdown timeout": "Čas na vypnutie vypršal",
|
||||
"SiYuan access code": "Prístupový kód SiYuan",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear poskytuje správu televíznych relácií a / alebo Anime, detekuje nové epizódy, odkazy aplikácie pre downloader, a ďalšie..",
|
||||
"Sign in to a registry": "Prihláste sa do registra",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Pred publikovaním adresára cez SMB sa prihláste na panel a vytvorte používateľa Samba v Nastaveniach.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal je aplikácia správ s ochranou súkromia v jej jadre. Je zadarmo a ľahko použiteľný, so silným end-to-end šifrovaním, ktoré udržuje vašu komunikáciu úplne súkromnú.",
|
||||
"Signatures removed. Partition table preserved.": "Podpisy boli odstránené. Tabuľka oddielov zostala zachovaná.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Prihlásený do {registry} ako {username}.\n\nPoverenia sú uložené pre ProxMenux.\nVyberte účet, ktorý chcete skontrolovať, stiahnuť alebo nainštalovať obrázok.",
|
||||
"Simple and easy to use DDNS": "Jednoduché a jednoduché použitie DDNS",
|
||||
"Single GPU Warning": "Upozornenie na jednu GPU",
|
||||
"Single target found — selected automatically:": "Našiel sa jeden target - vybraný automaticky:",
|
||||
@@ -5823,6 +5876,8 @@
|
||||
"Skipping SR-IOV device": "Preskakujem SR-IOV zariadenie",
|
||||
"Skipping installation.": "Inštalácia sa preskakuje.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Ručné záplaty preskakujem - fork feranick už tento kernel podporuje.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo nie je k dispozícii. Obnovte závislosti ProxMenux OCI a skúste to znova.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo vrátilo neplatný súbor poverení; uložené prihlasovacie údaje neboli zmenené.",
|
||||
"Sleek podcast downloader with GPodder sync": "Sleek podcast downloader s GPodder synchronizácia",
|
||||
"Smart restore plan — hardware compatibility check": "Inteligentný plán obnovy - kontrola kompatibility hardvéru",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping sleduje latenciu vašej siete. Úplný príklad toho, čo je táto aplikácia schopná navštíviť UCDavis.",
|
||||
@@ -6080,6 +6135,7 @@
|
||||
"TCP optimizations configuration completed": "Nastavenie TCP optimalizácií je dokončené",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "TCP optimalizácie boli vrátené späť (predvolené hodnoty sa obnovia pri ďalšom reštarte)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "TCP port 5201 je dostupný (firewall na serveri)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "Overenie TLS pre {registry} zlyhalo. Nainštalujte certifikačnú autoritu registra v /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "TPM zariadenie bolo pridané do VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "Výber úložiska pre TPM zlyhal alebo bol zrušený. Vytvorenie VM bolo prerušené.",
|
||||
"TROUBLESHOOTING:": "RIEŠENIE PROBLÉMOV:",
|
||||
@@ -6272,6 +6328,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "Konfigurácia musí bežať ako koreň na Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "Nastavenie nového člena sa zmenilo po jeho vytvorení",
|
||||
"The configuration stopped because of an unexpected error": "Konfigurácia sa zastavila kvôli neočakávanej chybe",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "Nepodarilo sa použiť nakonfigurovaného pomocníka poverení. Skontrolujte jeho inštaláciu a úložisko poverení.",
|
||||
"The console of the container could not be configured": "Konzolu kontajnera nebolo možné nakonfigurovať",
|
||||
"The consume/export volumes need at least 1 GB": "Objem spotreby/vývozu potrebuje najmenej 1 GB",
|
||||
"The container could not be removed automatically:": "Nádoba sa nedala automaticky odstrániť:",
|
||||
@@ -6310,6 +6367,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Kontajnery ich už nepotrebujú; aktualizácia stiahne nové verzie, ak nejaké existujú.",
|
||||
"The containers were created from downloaded OCI images": "Kontajnery boli vytvorené zo stiahnutých obrázkov OCI",
|
||||
"The coordinated backup was modified": "Koordinovaná záloha bola zmenená",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "Počas tejto operácie sa zmenil súbor poverení. Skúste to znova;nebolo to prepísané.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "Aktuálny ovládač sa pred inštaláciou novej verzie úplne odinštaluje. Pokračovať?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "Aktuálny obraz uloženého kanála bude skontrolovaný a stiahnutý. Zdroje, cesty a GPU sú udržiavané. CT je zastavený počas výmeny a natívne zálohovanie je vytvorené ako prvé.",
|
||||
"The current record is missing for": "Aktuálny záznam chýba",
|
||||
@@ -6392,7 +6450,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "Podsieť firewallu pre monitor hostiteľa sa zmenila; žiadne pravidlo sa nepridalo",
|
||||
"The host-monitor web interface uses the host network.": "Webové rozhranie monitora hostiteľa používa sieť hostiteľa.",
|
||||
"The identity of a member was replaced": "Identita člena bola nahradená",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "Cesta vyrovnávacej pamäte obrázkov nie je bezpečná. Pred opätovným pokusom skontrolujte úložisko šablóny.",
|
||||
"The image changes the user expected by the adapter": "Obrázok mení používateľa očakávaný adaptérom",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "Obrázok sa nepodarilo stiahnuť alebo overiť. Skontrolujte prístup k registrom a ukladaciemu priestoru a skúste to znova.",
|
||||
"The image could not be read from its registry:": "Obrázok sa nepodarilo prečítať z jeho registra:",
|
||||
"The image declares data paths that are still stored in the rootfs": "Obrázok deklaruje dátové cesty, ktoré sú stále uložené v rootfs",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "Obrázok neumožňoval používateľovi aplikácie prístup k zariadeniam; skontrolujte jeho rodený init. Povolenie hostiteľa nebolo uvoľnené.",
|
||||
@@ -6405,6 +6465,8 @@
|
||||
"The image is in its registry, for one architecture.": "Obraz je vo svojom registri, pre jednu architektúru.",
|
||||
"The image is in its registry.": "Obrázok je v jeho registri.",
|
||||
"The image is in its registry:": "Obrázok je vo svojom registri:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "Overenie integrity manifestu obrázka zlyhalo. Skúste to znova alebo kontaktujte vydavateľa obrázkov.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "Obrázok alebo značka sa na {registry} nenašla alebo k nim tento účet nemá prístup. Skontrolujte referenciu.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "Obrázok požaduje NVIDIA, ale hostiteľ nemá žiadny funkčný ovládač NVIDIA",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "Obraz si vyžaduje vypnutie časti AppArmor alebo seccomp väzenia. Pokračujte len vtedy, ak dôverujete obrazu a prijmete toto riziko.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "Obraz si vyžaduje vypnutie časti AppArmor alebo seccomp väzenia. Skladba ponúka voliteľnú AppArmor alebo seccomp relaxáciu; zostane vypnutá, ak si ju užívateľ nevyberie. Pokračujte len vtedy, ak dôverujete obrazu a prijmete toto riziko.",
|
||||
@@ -6542,7 +6604,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "Záznam alebo diagnóza nemohla byť dokončená; žiadna aktualizácia nebola spustená.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "Obnova sa nedokončila. Skontrolujte záznam a v ponuke Správca OCI aplikácií pri tomto kontajneri znova vyberte \"Obnoviť\".",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "Obnova sa nedokončila. Skontrolujte záznam a v ponuke Správca OCI aplikácií pri tomto kontajneri znova vyberte \"{choice}\".",
|
||||
"The registry authentication file is invalid; it was not changed.": "Overovací súbor registra je neplatný;nebolo to zmenené.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "Overovací súbor registra musí vlastniť root s režimom 600.",
|
||||
"The registry authentication file must have an absolute path.": "Overovací súbor registra musí mať absolútnu cestu.",
|
||||
"The registry authentication path cannot contain symbolic links.": "Cesta na overenie registra nemôže obsahovať symbolické odkazy.",
|
||||
"The registry authentication path has an unsafe parent directory.": "Cesta na overenie registra obsahuje nebezpečný nadradený adresár.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "Adresár poverení registra musí vlastniť root s režimom 700.",
|
||||
"The registry did not return the saved image digest": "Register nevrátil uložený image digest",
|
||||
"The registry returned incomplete or unsupported image metadata.": "Register vrátil neúplné alebo nepodporované metadáta obrázka.",
|
||||
"The registry returned invalid or unsupported image metadata.": "Register vrátil neplatné alebo nepodporované metadáta obrázka.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "Vzdialenosť neexistuje; vytvoriť a schváliť ju ako prvý na WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "Diaľkový inštalátor musí bežať ako koreň na Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "Vzdialený musí byť už vytvorený a schválený v Rclone web UI. Tento operation reštartuje CT a zverejňuje dva pohľady FUSE na hostiteľa.",
|
||||
@@ -6701,6 +6771,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Táto GPU sa v ProxMenux považuje za nekompatibilnú s GPU passthrough do VM.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Toto NFS zdieľanie je úplne obmedzené - ani root na hostovi doň nevie zapisovať.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Táto VM vyžaduje ďalšie kroky inštalácie. Návod nájdete tu:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Tento účet je pre {registry}. Zadajte obrázok z tohto registra.",
|
||||
"This action will:": "Táto akcia vykoná:",
|
||||
"This application cannot be recovered yet:": "Túto aplikáciu zatiaľ nie je možné obnoviť:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Túto aplikáciu zatiaľ nie je možné obnoviť; nič sa nezmenilo:",
|
||||
@@ -6732,8 +6803,10 @@
|
||||
"This explicitly marks the container as privileged": "Týmto sa kontajner výslovne označí ako privilegovaný",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Tento súbor rozhoduje o tom, čo sa pripojí a s akými oprávneniami. Nainštalujte ho iba vtedy, ak pochádza zo zdroja, ktorému dôverujete.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Tým sa zabezpečí, že device nodes budú dostupné ešte pred použitím GPU nastavenia pre LXC.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Táto hostiteľská architektúra nie je podporovaná importérom obrázkov OCI.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Tento hostiteľ nemá žiadne aktívne predplatné, prepnúť na úložisko bez predplatného? Neprístupný zdroj Enterprise PVE bude zakázaný. Enterprise Ceph zdroje, ak sú prítomné, budú deaktivované bez výberu náhradného Ceph kanála; v prípade potreby nakonfigurujte Ceph samostatne.",
|
||||
"This image cannot be installed as it is described:": "Tento obrázok nie je možné nainštalovať, ako je popísané:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Tento obrázok nemá žiadny kompatibilný obraz Linuxu pre tohto hostiteľa ({architecture}).",
|
||||
"This image requires the host module": "Tento obrázok requires hostiteľský modul",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Tento import odmieta tieto cesty bez kontroly, či ide o súbory alebo adresáre.",
|
||||
"This installation will:": "Táto inštalácia urobí toto:",
|
||||
@@ -6849,6 +6922,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "Ak chcete GPU znova používať v LXC, spustite Pridať GPU do LXC v menu GPUs and Coral-TPU",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "Aby VM fungovala bez problémov, server musí byť pred jej spustením reštartovaný.",
|
||||
"To use this share from an LXC, bind-mount it via:": "Ak chcete toto zdieľanie používať z LXC, pripojte ho ako bind mount cez:",
|
||||
"Token": "Token",
|
||||
"Tool exit code:": "Návratový kód nástroja:",
|
||||
"Tool output:": "Výstup nástroja:",
|
||||
"Tools": "Nástroje",
|
||||
@@ -6993,6 +7067,7 @@
|
||||
"Unsafe private configuration path": "Nebezpečná konfiguračná dráha",
|
||||
"Unsafe qBittorrent configuration path": "Nebezpečná konfiguračná dráha qBittorrent",
|
||||
"Unsafe record": "Nebezpečný záznam",
|
||||
"Unsafe registry credential lock.": "Nebezpečný zámok poverení registra.",
|
||||
"Unsafe registry directory": "Nebezpečný adresár registrov",
|
||||
"Unsafe registry lock": "Nebezpečný zámok registra",
|
||||
"Unsafe rootfs for the capture": "Nebezpečné rootfs pre zachytenie",
|
||||
@@ -7005,6 +7080,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Nepodporovaný profil OCI-LXC AppArmor:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Nepodporovaný profil OCI-LXC seccomp:",
|
||||
"Unsupported Terminal": "Nepodporovaný terminál",
|
||||
"Unsupported architecture for Figurine:": "Nepodporovaná architektúra pre Figurine:",
|
||||
"Unsupported architecture:": "Nepodporovaná architektúra:",
|
||||
"Unsupported backup compression": "Nepodporovaná kompresia zálohy",
|
||||
"Unsupported credential pattern:": "Nepodporovaný credential vzor:",
|
||||
@@ -7057,6 +7133,7 @@
|
||||
"Update cancelled by user": "Aktualizácia zrušená používateľom",
|
||||
"Update completed. Data kept.": "Aktualizácia dokončená. Údaje uchovávané.",
|
||||
"Update completed. Press Enter to continue...": "Aktualizácia dokončená. Pokračujte stlačením Enter...",
|
||||
"Update credentials": "Aktualizujte poverenia",
|
||||
"Update every container of the application": "Aktualizovať každý kontajner aplikácie",
|
||||
"Update kernel to compatible version": "Aktualizovať kernel na kompatibilnú verziu",
|
||||
"Update now?": "Aktualizácia?",
|
||||
@@ -7123,8 +7200,10 @@
|
||||
"Use a custom path": "Použiť vlastnú cestu",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Pre NFS server/klient používajte privilegovaný LXC.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Pre Samba klient/server používajte privilegovaný LXC.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Použite názov hostiteľa registra, napríklad ghcr.io alebo registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Použiť existujúci súbor súkromného SSH kľúča na tomto hostovi",
|
||||
"Use an existing keyfile": "Použiť existujúci keyfile",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Použite odkaz na obrázok, napríklad ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Použiť tak, ako je - ponechať dáta aj súborový systém",
|
||||
"Use content types according to your use case.": "Typy obsahu zvoľte podľa toho, na čo bude úložisko slúžiť.",
|
||||
"Use default": "Použiť predvolené",
|
||||
@@ -7164,6 +7243,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "Užívateľsky prívetivé WebUI pre LLM (predovšetkým Ollama WebUI)",
|
||||
"Username": "Používateľské meno",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Používateľské meno (napr. root@pam alebo user@pbs!token):",
|
||||
"Username / token": "Používateľské meno / token",
|
||||
"Username and password": "Meno a heslo",
|
||||
"Username and password will be cleared.": "Meno používateľa a heslo sa vymažú.",
|
||||
"Username cannot be empty.": "Meno používateľa nesmie byť prázdne.",
|
||||
@@ -7263,6 +7343,7 @@
|
||||
"Verifying Ceph packages availability...": "Overujem dostupnosť balíkov Ceph...",
|
||||
"Verifying all utilities status": "Overujem stav všetkých nástrojov",
|
||||
"Verifying disk accessibility in CT": "Overujem dostupnosť disku v CT",
|
||||
"Verifying registry access. Please wait...": "Overenie prístupu do registra. Čakajte prosím...",
|
||||
"Verifying the backups...": "Overujem zálohy...",
|
||||
"Verifying the image integrity...": "Overuje integritu obrazu...",
|
||||
"Version": "Verzia",
|
||||
@@ -7562,6 +7643,7 @@
|
||||
"assembling": "montáž",
|
||||
"automatically. Install it manually inside the container.": "automaticky. Nainštalujte ho ručne vo vnútri kontajnera.",
|
||||
"automatically. Reboot LXC to fully release.": "automaticky. Pre úplné uvoľnenie reštartujte LXC.",
|
||||
"available": "K dispozícii",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "dostupné pre LXC bind mounty cez 'Správca LXC mountov'",
|
||||
"available in this same GPU and TPU menu.": "dostupnej v tomto istom GPU a TPU menu.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "záloha v /etc/fstab.proxmenux.bak",
|
||||
@@ -7914,6 +7996,7 @@
|
||||
"runs in": "beží v",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "bezpečné cesty teraz (nastavenia, balíky, /etc, /root, ...)",
|
||||
"same MAC": "rovnaká MAC",
|
||||
"saved": "Uložené",
|
||||
"seconds (default)": "sekúnd (predvolené)",
|
||||
"see log:": "pozrite záznam:",
|
||||
"selected by default": "vybrané štandardne",
|
||||
@@ -8032,8 +8115,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot bol odstránený (existujúce snapshoty v poole zostali zachované)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "Príkaz zpool sa nenašiel. Nainštalujte zfsutils-linux a skúste to znova.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool sa nenašiel. Nainštalujte zfsutils-linux a skúste to znova.",
|
||||
"{count} saved account.": "{count} uložený účet.",
|
||||
"{count} saved accounts.": "{count} uložené účty.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} už existuje a patrí inému používateľovi hostiteľa, takže {app} naň nemôže zapisovať.\n\nProxMenux môže pridať pravidlá prístupu (ACL) k tomuto adresáru, ku všetkému v ňom a k tomu, čo sa v ňom vytvorí neskôr, pre používateľov a skupiny, pod ktorými {app} beží na hostiteľovi (ID {ids}). Vlastník súborov sa nemení a čokoľvek, čo ich dnes číta alebo zapisuje, to robí aj naďalej; vlastník adresára tiež získa prístup k súborom, ktoré {app} vytvorí.\n\nUdeliť {app} prístup k tomuto adresáru?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} už existuje a patrí inému používateľovi hostiteľa, takže {app} naň nemôže zapisovať.\n\nProxMenux môže pridať pravidlo prístupu (ACL) pre identitu, ktorú {app} používa na hostiteľovi (UID {uid}).Nič z toho, čo tam je, nemení vlastníka ani oprávnenia: čokoľvek, čo dnes číta alebo zapisuje tieto súbory, to robí aj naďalej a vlastník adresára tiež získa prístup k súborom, ktoré {app} vytvorí.\n\nUdeliť {app} prístup k tomuto adresáru?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} odpovedal jednoduchým HTTP. Použite register s HTTPS; Overenie TLS zostáva povolené.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} neodpovedal do {timeout} sekúnd. Skúste to znova neskôr.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "{registry} sú požiadavky obmedzujúce rýchlosť. Chvíľu počkajte a skúste to znova.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} odmietol prístup k tomuto obrázku:\n{reference}\n\nAk je obrázok súkromný, prihláste sa pomocou účtu, ktorý ho môže stiahnuť.\n\nPrihláste sa teraz?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} ohlásil chybu servera. Skúste to znova neskôr.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} vrátilo neplatné alebo nepodporované metadáta obrázka.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "- úplná/vlastná obnova preskočí cesty viazané na kernel",
|
||||
"— disk may be busy. Skipping fstab removal.": "- disk sa možno používa. Preskakujem odstránenie z fstab.",
|
||||
"— restore proceeds as same-version (verified safe)": "- obnova pokračuje ako pri rovnakej verzii (overené ako bezpečné)",
|
||||
|
||||
+97
-6
@@ -192,6 +192,7 @@
|
||||
"Access bridge for Tandoor": "Tillgångsbro för Tandoor",
|
||||
"Access could not be granted completely; the application may be unable to write to:": "Åtkomst kunde inte beviljas fullständigt; applikationen kanske inte kan skriva till:",
|
||||
"Access could not be granted; the application cannot write to:": "Åtkomst kunde inte beviljas; ansökan kan inte skriva till:",
|
||||
"Access denied by {registry}. Check the image name and sign in from Registry accounts.": "Åtkomst nekad av {registry}. Kontrollera bildnamnet och logga in från registerkonton.",
|
||||
"Access granted to the application on:": "Tillgång beviljad till ansökan på:",
|
||||
"Access password of the web interface (optional)": "Åtkomstlösenord för webbgränssnittet (valfritt)",
|
||||
"Access profile:": "Åtkomstprofil:",
|
||||
@@ -310,6 +311,7 @@
|
||||
"Advanced": "Avancerad",
|
||||
"Advanced Diagnostics": "Avancerad diagnostik",
|
||||
"Advanced Network Diagnostics": "Avancerad nätverksdiagnostik",
|
||||
"Advanced settings": "Avancerade inställningar",
|
||||
"Advanced: every setting of the container": "Avancerad: varje inställning av behållaren",
|
||||
"Affected LXC containers": "Berörda LXC-behållare",
|
||||
"After completing GPU setup, start the VM manually when the host is ready.": "När du har slutfört GPU-installationen startar du den virtuella datorn manuellt när värden är klar.",
|
||||
@@ -328,7 +330,7 @@
|
||||
"After this LXC → VM switch, reboot the host so the new binding state is applied cleanly.": "Efter denna LXC → VM-switch, starta om värden så att det nya bindningsläget tillämpas korrekt.",
|
||||
"Airsonic Advanced web interface": "Airsonic Advanced webbgränssnitt",
|
||||
"Airsonic-advanced is a free, web-based media streamer, providing ubiquitious access to your music. Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple players simultaneously, for instance to one player in your kitchen and another in your living room.": "Airsonic-advanced är en gratis, webbaserad media streamer, som ger ubiquitious tillgång till din musik. Använd den för att dela din musik med vänner, eller för att lyssna på din egen musik på jobbet. Du kan strömma till flera spelare samtidigt, till exempel till en spelare i ditt kök och en annan i ditt vardagsrum.",
|
||||
"Aliases added to .bashrc": "Alias har lagts till i .bashrc",
|
||||
"Aliases added to .bashrc": "Alias har lagts till i .bashrc",
|
||||
"Alist Sync web interface": "Alist Sync webbgränssnitt",
|
||||
"All": "Alla",
|
||||
"All Available Scripts": "Alla tillgängliga skript",
|
||||
@@ -403,6 +405,7 @@
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "En annan OCI operation använder instansregistret. Vänta på att den ska slutföra och öppna den här menyn igen; ingen behållare modifieras.",
|
||||
"Another OCI operation is using the instance registry. Wait for it to finish.": "En annan OCI-operation använder instansregistret. Vänta tills det är klart.",
|
||||
"Another OCI operation is using the registry. This operation was not started.": "En annan OCI operation använder registret. Denna operation startades inte.",
|
||||
"Another ProxMenux OCI operation is running. Try again when it finishes.": "En annan ProxMenux OCI-operation körs. Försök igen när det är klart.",
|
||||
"Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "En annan ZRAM-konfiguration finns eller kunde inte inspekteras; systemd-zram-generator behölls",
|
||||
"Another ZRAM generator configuration exists; refusing to overwrite it:": "En annan ZRAM-generatorkonfiguration finns; vägrar att skriva över det:",
|
||||
"Another ZRAM swap setup exists; refusing to replace it:": "En annan ZRAM-bytesinstallation finns; vägrar att ersätta den:",
|
||||
@@ -410,6 +413,7 @@
|
||||
"Another instance uses": "Ett annat exempel använder",
|
||||
"Another job that writes to the same storage still starts them.": "Ett annat jobb som skriver till samma lagring startar dem fortfarande.",
|
||||
"Another node, typed by hand": "En annan nod, maskinskriven för hand",
|
||||
"Another registry account operation is running. Try again when it finishes.": "En annan registerkontooperation körs. Försök igen när det är klart.",
|
||||
"Another stack operation is pending": "En annan stack operation väntar",
|
||||
"Application": "Ansökan",
|
||||
"Application registered on this host:": "Applikation registrerad på denna värd:",
|
||||
@@ -502,6 +506,7 @@
|
||||
"Authentication": "Autentisering",
|
||||
"Authentication & Security": "Autentisering och säkerhet",
|
||||
"Authentication Error": "Autentiseringsfel",
|
||||
"Authentication failed for {registry}. Check the account and token permissions.": "Autentisering misslyckades för {registry}. Kontrollera konto- och tokenbehörigheterna.",
|
||||
"Authentication failed.": "Autentiseringen misslyckades.",
|
||||
"Authentication required:": "Autentisering krävs:",
|
||||
"Authentication:": "Autentisering:",
|
||||
@@ -739,6 +744,7 @@
|
||||
"Cannot resolve the container home directory:": "Kan inte lösa behållarens hemkatalog:",
|
||||
"Cannot validate credentials - no shares available for testing.": "Kan inte validera autentiseringsuppgifter - inga delningar tillgängliga för testning.",
|
||||
"Cannot verify the reused disk:": "Kan inte verifiera den återanvända disken:",
|
||||
"Cannot write the image archive to {storage}. Check storage access and mount status.": "Kan inte skriva bildarkivet till {storage}. Kontrollera lagringsåtkomst och monteringsstatus.",
|
||||
"Capabilities cannot be kept and all dropped at the same time": "Förmågor kan inte hållas och alla tappas samtidigt",
|
||||
"Category": "Kategori",
|
||||
"Caution: Maximum mode generates more heat.": "Varning: Maximalt läge genererar mer värme.",
|
||||
@@ -799,6 +805,7 @@
|
||||
"Check Samba Status": "Kontrollera Samba Status",
|
||||
"Check VM disk/PCI slots": "Kontrollera VM-disk/PCI-platser",
|
||||
"Check VM passthrough settings": "Kontrollera VM-passthrough-inställningarna",
|
||||
"Check access to an image": "Kontrollera åtkomst till en bild",
|
||||
"Check connectivity with another host": "Kontrollera anslutningen med en annan värd",
|
||||
"Check container mount points": "Kontrollera behållarens monteringspunkter",
|
||||
"Check if container is unprivileged:": "Kontrollera om behållaren är oprivilegierad:",
|
||||
@@ -811,6 +818,7 @@
|
||||
"Check that:": "Kontrollera att:",
|
||||
"Check the error messages above for details.": "Kontrollera felmeddelandena ovan för detaljer.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. A private registry needs credentials, which are not supported yet.": "Kontrollera avbildens referens och åtkomsten till registret. Om registret inte är tillgängligt, försök igen senare. Ett privat register kräver inloggningsuppgifter, som ännu inte stöds.",
|
||||
"Check the image reference and registry access. If the registry is unavailable, try again later. For a private image, sign in from Registry accounts in the OCI menu.": "Kontrollera bildreferensen och registeråtkomst. Om registret inte är tillgängligt, försök igen senare. För en privat bild, logga in från Registerkonton i OCI-menyn.",
|
||||
"Check the service status manually if needed.": "Kontrollera servicestatus manuellt vid behov.",
|
||||
"Checking MOTD configuration...": "Kontrollerar MOTD-konfiguration...",
|
||||
"Checking NVIDIA driver status with nvidia-smi": "Kontrollerar NVIDIA-drivrutinsstatus med nvidia-smi",
|
||||
@@ -824,6 +832,7 @@
|
||||
"Checking free space in /var/cache/apt/archives...": "Kontrollerar ledigt utrymme i /var/cache/apt/archives...",
|
||||
"Checking if system disk is SSD or M.2...": "Kontrollerar om systemdisken är SSD eller M.2...",
|
||||
"Checking if the server belongs to OVH...": "Kontrollerar om servern tillhör OVH...",
|
||||
"Checking image access and metadata. Please wait...": "Kontrollera bildåtkomst och metadata. Vänligen vänta...",
|
||||
"Checking kernel headers and build tools...": "Kontrollerar kärnrubriker och byggverktyg...",
|
||||
"Checking remaining interfaces": "Kontrollerar återstående gränssnitt",
|
||||
"Checking that the container keeps running...": "Kontrollera att behållaren håller igång...",
|
||||
@@ -897,6 +906,7 @@
|
||||
"Choose iperf3 mode:": "Välj iperf3-läge:",
|
||||
"Choose options to configure:": "Välj alternativ att konfigurera:",
|
||||
"Choose specific VMs/CTs": "Välj specifika virtuella datorer/CT:er",
|
||||
"Choose storage for the downloaded image.": "Välj lagringsutrymme för den nedladdade bilden.",
|
||||
"Choose the driver version for Coral M.2:": "Välj drivrutinsversion för Coral M.2:",
|
||||
"Choose the filesystem for the new partition:": "Välj filsystem för den nya partitionen:",
|
||||
"Choose the release channel to use:": "Välj utgivningskanalen att använda:",
|
||||
@@ -1364,17 +1374,20 @@
|
||||
"Could not publish pending restore. Previous pending restore was kept.": "Kunde inte publicera väntande återställning. Tidigare pågående återställning behölls.",
|
||||
"Could not push the key. Check the password and that": "Kunde inte trycka på nyckeln. Kolla lösenordet och så",
|
||||
"Could not query the image registry": "Kunde inte fråga bildregistret",
|
||||
"Could not reach {registry}. Check its address, DNS and network access.": "Kunde inte nå {registry}. Kontrollera dess adress, DNS och nätverksåtkomst.",
|
||||
"Could not read SMART data from": "Det gick inte att läsa SMART-data från",
|
||||
"Could not read VM configuration.": "Det gick inte att läsa VM-konfigurationen.",
|
||||
"Could not read the CUDA compute capability": "Kunde inte läsa CUDA-beräkningsförmågan",
|
||||
"Could not read the NVIDIA driver version": "Kan inte läsa NVIDIA-förarversionen",
|
||||
"Could not read the host firewall rules": "Kunde inte läsa värdbrandväggens regler",
|
||||
"Could not read the image from {registry}. Check the reference and sign in from Registry accounts.": "Kunde inte läsa bilden från {registry}. Kontrollera referensen och logga in från registerkonton.",
|
||||
"Could not read this job.": "Kunde inte läsa det här jobbet.",
|
||||
"Could not release ZRAM pages; existing profile remains active": "Kunde inte släppa ZRAM-sidor; befintlig profil förblir aktiv",
|
||||
"Could not remount automatically. Try manually or check credentials.": "Kunde inte montera om automatiskt. Försök manuellt eller kontrollera autentiseringsuppgifterna.",
|
||||
"Could not remove VM automatically. Run manually:": "Det gick inte att ta bort VM automatiskt. Kör manuellt:",
|
||||
"Could not remove ZRAM profile; configuration was restored": "Kunde inte ta bort ZRAM-profilen; konfigurationen återställdes",
|
||||
"Could not remove ZRAM profile; configuration was restored but swap could not be restarted": "Kunde inte ta bort ZRAM-profilen; konfigurationen återställdes men swap kunde inte startas om",
|
||||
"Could not remove credentials for {registry}; saved file credentials were not changed.": "Kunde inte ta bort inloggningsuppgifter för {registry}; sparade autentiseringsuppgifter för filen ändrades inte.",
|
||||
"Could not remove previous DKMS tree at": "Det gick inte att ta bort tidigare DKMS-träd kl",
|
||||
"Could not reserve a private network for the stack": "Kunde inte reservera ett privat nätverk för stacken",
|
||||
"Could not resolve the Compose user:": "Kunde inte lösa Compose-användaren:",
|
||||
@@ -1389,6 +1402,7 @@
|
||||
"Could not set VM virtual display to vga: std": "Det gick inte att ställa in virtuell skärm på vga: std",
|
||||
"Could not set boot order for": "Det gick inte att ställa in startordning för",
|
||||
"Could not set the container entrypoint": "Kan inte ställa in behållarens ingångspunkt",
|
||||
"Could not sign in to {registry}. Check registry access and token permissions.": "Kunde inte logga in på {registry}. Kontrollera registeråtkomst och tokenbehörigheter.",
|
||||
"Could not stage pending restore path:": "Kunde inte scenen väntande återställningssökväg:",
|
||||
"Could not stage pending restore. Nothing new was scheduled.": "Kunde inte scenen väntande återställning. Inget nytt var inplanerat.",
|
||||
"Could not stop LXC": "Kunde inte stoppa LXC",
|
||||
@@ -1475,11 +1489,15 @@
|
||||
"Creating the private network...": "Skapar det privata nätverket...",
|
||||
"Creating the temporary data container": "Skapa den tillfälliga databehållaren",
|
||||
"Creative & Design": "Kreativitet och design",
|
||||
"Credential helper": "Credential helper",
|
||||
"Credential storage and access": "Autentiseringslagring och åtkomst",
|
||||
"Credentials are correct": "Inloggningsuppgifterna är korrekta",
|
||||
"Credentials cleared. jwt_secret and API tokens preserved.": "Autentiseringsuppgifter rensade. jwt_secret och API-tokens bevarade.",
|
||||
"Credentials file created securely.": "Autentiseringsfil skapad på ett säkert sätt.",
|
||||
"Credentials file removed.": "Autentiseringsfilen har tagits bort.",
|
||||
"Credentials file:": "Autentiseringsfil:",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nConfigure credentials on each node that downloads images.": "Autentiseringsfil:\n{path}\n\nÄgs av roten; katalogläge 700 och filläge 600.\nGrundläggande referenser är base64-kodade, inte krypterade.\nCredential hjälpare använder sin egen förvaring.\n\nAnvänd en åtkomsttoken med behörighet att dra bilder.\nKonfigurera autentiseringsuppgifter på varje nod som laddar ner bilder.",
|
||||
"Credentials file:\n{path}\n\nOwned by root; directory mode 700 and file mode 600.\nBasic credentials are base64 encoded, not encrypted.\nCredential helpers use their own storage.\n\nUse an access token with permission to pull images.\nEvery node of the cluster uses the accounts saved here.": "Autentiseringsfil:\n{path}\n\nÄgs av roten; katalogläge 700 och filläge 600.\nGrundläggande referenser är base64-kodade, inte krypterade.\nCredential hjälpare använder sin egen förvaring.\n\nAnvänd en åtkomsttoken med behörighet att dra bilder.\nVarje nod i klustret använder de konton som sparats här.",
|
||||
"Credentials validated successfully": "Inloggningsuppgifterna har validerats",
|
||||
"Cross-host restore: guest IDs in backup overlap live IDs on target:": "Cross-host-återställning: gäst-ID:n i säkerhetskopia överlappar live-ID:n på målet:",
|
||||
"Cross-kernel restore — kernel-tied paths merged, not copied": "Korskärnåterställning — kärnbundna sökvägar sammanslagna, inte kopierade",
|
||||
@@ -1617,6 +1635,7 @@
|
||||
"Default login": "Standard inloggning",
|
||||
"Default options": "Standardalternativ",
|
||||
"Default options read/write": "Standardalternativ läs/skriv",
|
||||
"Default settings": "Standardinställningar",
|
||||
"Default will be used:": "Standard kommer att användas:",
|
||||
"Default:": "Standard:",
|
||||
"Default: only what the application needs": "Standard: endast vad programmet behöver",
|
||||
@@ -1851,6 +1870,7 @@
|
||||
"Doplarr_rs is a Discord bot for requesting media through *arr backends, written in Rust.": "Doplarr_rs är en Discord bot för att begära media genom *arr backends, skriven i Rust.",
|
||||
"Double Commander is a free cross platform open source file manager with two panels side by side. It is inspired by Total Commander and features some new ideas.": "Double Commander är en gratis plattform öppen källkod filhanterare med två paneler sida vid sida. Den är inspirerad av Total Commander och har några nya idéer.",
|
||||
"Download Spotify music with album art and metadata": "Ladda ner Spotify musik med albumkonst och metadata",
|
||||
"Download an image to template storage": "Ladda ner en bild till malllagring",
|
||||
"Download an oci-compose from an address": "Ladda ner en oci-compose från en adress",
|
||||
"Download failed for all attempted URLs": "Nedladdningen misslyckades för alla försök till webbadresser",
|
||||
"Download its Compose file from an address": "Ladda ner sin Compose-fil från en adress",
|
||||
@@ -1866,6 +1886,7 @@
|
||||
"Downloading Proxmology logo...": "Laddar ner Proxmology-logotypen...",
|
||||
"Downloading UUP converter...": "Laddar ned UUP-konverterare...",
|
||||
"Downloading amdgpu_top": "Laddar ner amdgpu_top",
|
||||
"Downloading and verifying the image.\nThis can take a few minutes. Please wait...": "Ladda ner och verifiera bilden.\nDetta kan ta några minuter. Vänligen vänta...",
|
||||
"Downloading official installer...": "Laddar ned det officiella installationsprogrammet...",
|
||||
"Downloading pre-existing encrypted backups from this host will fail unless you kept a copy of the current key.": "Nedladdning av redan existerande krypterade säkerhetskopior från denna värd kommer att misslyckas om du inte behåller en kopia av den aktuella nyckeln.",
|
||||
"Downloading the image:": "Ladda ner bilden:",
|
||||
@@ -1999,9 +2020,11 @@
|
||||
"Enter ZFS pool name for the selected disk:": "Ange ZFS-poolnamn för den valda disken:",
|
||||
"Enter a name for the mount point (used as /mnt/<name>):": "Ange ett namn för monteringspunkten (används som /mnt/<namn>):",
|
||||
"Enter a name for the new virtual machine:": "Ange ett namn för den nya virtuella maskinen:",
|
||||
"Enter a non-empty password or access token on a single line.": "Ange ett icke-tomt lösenord eller åtkomsttoken på en enda rad.",
|
||||
"Enter a number, or write or paste a command:": "Ange ett nummer, eller skriv eller klistra in ett kommando:",
|
||||
"Enter a systemd calendar event, e.g.:": "Ange en systemd kalenderhändelse, t.ex.:",
|
||||
"Enter a usable IPv4 address with its prefix, for example": "Ange en användbar IPv4-adress med dess prefix, till exempel",
|
||||
"Enter a valid registry username.": "Ange ett giltigt registeranvändarnamn.",
|
||||
"Enter backup file (.zst):": "Ange backupfil (.zst):",
|
||||
"Enter backup path (.tar.zst):": "Ange backupsökväg (.tar.zst):",
|
||||
"Enter backup path (.vma.zst):": "Ange backupsökväg (.vma.zst):",
|
||||
@@ -2120,7 +2143,7 @@
|
||||
"Etherpad admin page": "Etherpad admin sida",
|
||||
"Every 12 hours": "Var 12:e timme",
|
||||
"Every 3 hours": "Var 3:e timme",
|
||||
"Every 6 hours": "Var 6:e timme",
|
||||
"Every 6 hours": "Var 6:e timme",
|
||||
"Every fail2ban jail ships disabled. Enable the ones you need in /config/fail2ban/jail.local, taking the ready-made jails in /config/fail2ban/jail.d/ as reference, then restart the container.": "Varje fail2ban fängslade fartyg. Möjliggöra de du behöver i /config / fail2ban /jail.local, ta de färdiga fängelserna i /config / fail2ban /jail.d / som referens, sedan starta om behållaren.",
|
||||
"Every hour": "Varje timme",
|
||||
"Every member of the stack is back to its previous installation.": "Varje medlem av stacken är tillbaka till sin tidigare installation.",
|
||||
@@ -2287,12 +2310,12 @@
|
||||
"Failed to download Proxmology logo": "Det gick inte att ladda ner Proxmology-logotypen",
|
||||
"Failed to download VirtIO driver ISO.": "Det gick inte att ladda ner VirtIO-drivrutinen ISO.",
|
||||
"Failed to download amdgpu_top": "Det gick inte att ladda ner amdgpu_top",
|
||||
"Failed to download loader image.": "Det gick inte att ladda ned laddarbilden.",
|
||||
"Failed to download loader image.": "Det gick inte att ladda ned loader-avbilden.",
|
||||
"Failed to edit /etc/fstab — remove the line manually.": "Det gick inte att redigera /etc/fstab — ta bort raden manuellt.",
|
||||
"Failed to enable ZFS autotrim for pool:": "Det gick inte att aktivera ZFS autotrim för pool:",
|
||||
"Failed to enable automatic time synchronization": "Det gick inte att aktivera automatisk tidssynkronisering",
|
||||
"Failed to extract OVA file:": "Det gick inte att extrahera OVA-fil:",
|
||||
"Failed to extract a nonempty loader image.": "Det gick inte att extrahera en icke-tom laddarbild.",
|
||||
"Failed to extract a nonempty loader image.": "Det gick inte att extrahera en icke-tom loader-avbild.",
|
||||
"Failed to extract package": "Det gick inte att extrahera paketet",
|
||||
"Failed to fetch the Google Coral GPG key. Check": "Det gick inte att hämta Google Coral GPG-nyckeln. Kontrollera",
|
||||
"Failed to format disk as": "Det gick inte att formatera disken som",
|
||||
@@ -2349,7 +2372,7 @@
|
||||
"Failed to retrieve Fastfetch download URL.": "Det gick inte att hämta Fastfetch-nedladdnings-URL.",
|
||||
"Failed to retrieve loader release metadata.": "Det gick inte att hämta metadata för loader release.",
|
||||
"Failed to run log2ram installer. Check /tmp/log2ram_install.log": "Det gick inte att köra log2ram installationsprogrammet. Kontrollera /tmp/log2ram_install.log",
|
||||
"Failed to save loader image.": "Det gick inte att spara laddningsbilden.",
|
||||
"Failed to save loader image.": "Det gick inte att spara loader-avbilden.",
|
||||
"Failed to set VM description": "Det gick inte att ange VM-beskrivning",
|
||||
"Failed to set timezone - keeping current settings": "Det gick inte att ställa in tidszonen - behålla nuvarande inställningar",
|
||||
"Failed to start CT": "Det gick inte att starta CT",
|
||||
@@ -2645,7 +2668,7 @@
|
||||
"HAOS One is a community image that runs Docker inside the container. The LXC stays unprivileged, but the inner AppArmor profiles may not be available. The first start downloads Home Assistant Core and its add-ons. If the check fails, the CT and /mnt/data are kept for diagnosis.": "HAOS One är en gemenskapsbild som kör Docker inuti behållaren. LXC är oprivilegierad, men de inre AppArmor-profilerna kanske inte är tillgängliga. Den första starten hämtar Home Assistant Core och dess tillägg. Om kontrollen misslyckas, CT och /mnt / data hålls för diagnos.",
|
||||
"HAOS One profile declined": "HAOS One-profilen minskade",
|
||||
"HAOS One requires an unprivileged unmanaged LXC with nesting and keyctl, 2 cores, 2048 MB RAM, rootfs of at least 12 GB and /mnt/data of at least 16 GB on a container volume included in backups": "HAOS One requires en oprivilegierad ohanterad LXC med häckning och keyctl, 2 kärnor, 2048 MB RAM, rötter på minst 12 GB och /mnt / data på minst 16 GB på en behållarvolym som ingår i backups",
|
||||
"HTML5 Network Speed Test Server.": "HTML5 Network Speed Test Server.",
|
||||
"HTML5 Network Speed Test Server.": "HTML5 Network Speed Test Server.",
|
||||
"HTTP service check without a saved URL": "HTTP service check utan sparad URL",
|
||||
"Habridge emulates Philips Hue API to other home automation gateways such as an Amazon Echo/Dot Gen 1 (gen 2 has issues discovering ha-bridge) or other systems that support Philips Hue. The Bridge handles basic commands such as On, Off and brightness commands of the hue protocol. This bridge can control most devices that have a distinct API.": "Habridge emulerar Philips Hue API till andra hemautomatiseringsgateways som Amazon Echo / Dot Gen 1 (gen 2 har problem med att upptäcka ha-bro) eller andra system som stöder Philips Hue. Bron hanterar grundläggande kommandon som On, Off och ljusstyrka kommandon av nyansprotokollet. Denna bro kan styra de flesta enheter som har ett tydligt API.",
|
||||
"HandBrake is an open-source tool, built by volunteers, for converting video from nearly any format to a selection of modern, widely supported codecs.": "HandBrake är ett open-source verktyg, byggt av volontärer, för att konvertera video från nästan alla format till ett urval av moderna, allmänt stödda codecs.",
|
||||
@@ -2676,6 +2699,7 @@
|
||||
"Help and Info": "Hjälp och info",
|
||||
"Help and Info Commands": "Hjälp- och infokommandon",
|
||||
"Helper-Scripts logo applied": "Helper-Scripts logotyp applicerad",
|
||||
"Helper:": "Hjälpare:",
|
||||
"Hermes WebUI": "Hermes WebUI",
|
||||
"Hidden for safety": "Gömd för säkerhets skull",
|
||||
"Hidden:": "Dold:",
|
||||
@@ -2890,16 +2914,20 @@
|
||||
"If your DHCP has a static reservation for the old MAC, update it.": "Om din DHCP har en statisk reservation för den gamla MAC, uppdatera den.",
|
||||
"Image": "Bild",
|
||||
"Image Source Directory": "Bildkällkatalog",
|
||||
"Image access confirmed.\n\n{reference}\n\nArchitecture: {architecture}\nVersion: {version}\nDownload size: {size}\nDigest: {digest}": "Bildåtkomst bekräftad.\n\n{reference}\n\nArkitektur: {architecture}\nVersion: {version}\nNedladdningsstorlek: {size}\nSammanfattning: {digest}",
|
||||
"Image cache": "Bild cache",
|
||||
"Image compatibility restored:": "Bildkompatibilitet återställd:",
|
||||
"Image compatibility verified:": "Bildkompatibilitet verifierad:",
|
||||
"Image directory:": "Bildkatalog:",
|
||||
"Image download failed:": "Bildnedladdning misslyckades:",
|
||||
"Image downloaded": "Bild nedladdad",
|
||||
"Image downloaded and verified.\n\n{reference}\n\nStorage: {storage}\nArchive size: {size}\nArchive: {archive}\n\nNo container was created.\nProxMenux removes unused cached images after successful updates.": "Bild har laddats ner och verifierats.\n\n{reference}\n\nLagring: {storage}\nArkivstorlek: {size}\nArkiv: {archive}\n\nIngen behållare skapades.\nProxMenux tar bort oanvända cachade bilder efter lyckade uppdateringar.",
|
||||
"Image file not found:": "Bildfilen hittades inte:",
|
||||
"Image imported:": "Bild importerad:",
|
||||
"Image integrity verification failed. The partial download was discarded; try again.": "Verifiering av bildintegritet misslyckades. Den partiella nedladdningen kasserades; försök igen.",
|
||||
"Image integrity verified": "Bildintegritet verifierad",
|
||||
"Image not allowed for the host monitor profile": "Bild som inte är tillåten för värdmonitorprofilen",
|
||||
"Image reference": "Bildreferens",
|
||||
"Image reference (for example ghcr.io/user/application:latest)": "Bildreferens (till exempel ghcr.io/user/application:latest)",
|
||||
"Image selection was cancelled": "Valet av avbild avbröts",
|
||||
"Image that is not in the catalog": "Bild som inte finns i katalogen",
|
||||
@@ -3027,6 +3055,7 @@
|
||||
"Install Samba inside CT:": "Installera Samba inuti CT:",
|
||||
"Install ZFS auto-snapshot": "Installera ZFS auto-snapshot",
|
||||
"Install a version from the branch the kernel names.": "Installera en version från grenen kärnan namnger.",
|
||||
"Install an image as a native LXC": "Installera en bild som en inbyggd LXC",
|
||||
"Install an image that is not in the catalog": "Installera en bild som inte finns i katalogen",
|
||||
"Install analysis tools": "Installera analysverktyg",
|
||||
"Install and configure": "Installera och konfigurera",
|
||||
@@ -3066,6 +3095,7 @@
|
||||
"Installation finished but drivers are not loaded. A reboot may be required.": "Installationen är klar men drivrutinerna är inte laddade. En omstart kan krävas.",
|
||||
"Installation incomplete. These containers and their data are kept:": "Installation ofullständig. Dessa behållare och deras data hålls:",
|
||||
"Installation log:": "Installationslogg:",
|
||||
"Installation settings": "Installationsinställningar",
|
||||
"Installation summary": "Sammanfattning av installationen",
|
||||
"Installed": "Installerad",
|
||||
"Installed at:": "Installerad på:",
|
||||
@@ -3239,6 +3269,7 @@
|
||||
"Invalid host path:": "Invalid värdväg:",
|
||||
"Invalid host-monitor firewall plan": "Ogiltig värd-monitor brandväggsplan",
|
||||
"Invalid image probe descriptor": "Ogiltig bildsondsbeskrivning",
|
||||
"Invalid image tag.": "Ogiltig bildtagg.",
|
||||
"Invalid input": "Ogiltig inmatning",
|
||||
"Invalid internal volume": "Invalid intern volym",
|
||||
"Invalid list:": "Invalid lista:",
|
||||
@@ -3296,6 +3327,7 @@
|
||||
"Invalid suite application": "Invalid suite applikation",
|
||||
"Invalid sysctl value:": "Invalid sysctl värde:",
|
||||
"Invalid template storage": "Invalid mall lagring",
|
||||
"Invalid template storage name.": "Ogiltigt malllagringsnamn.",
|
||||
"Invalid tmpfs options:": "Ogiltiga tmpfs alternativ:",
|
||||
"Invalid tmpfs path:": "Invalid tmpfs väg:",
|
||||
"Invalid tmpfs size:": "Invalid tmpfs storlek:",
|
||||
@@ -3535,6 +3567,8 @@
|
||||
"Log2RAM write scheduled every": "Log2RAM-skrivning schemalagt varje",
|
||||
"Log:": "Logga:",
|
||||
"Logged-in users": "Inloggade användare",
|
||||
"Login to {registry} timed out. Saved credentials were not changed.": "Inloggningen till {registry} tog timeout. Sparade autentiseringsuppgifter ändrades inte.",
|
||||
"Logout from {registry} timed out. Saved file credentials were not changed.": "Logga ut från {registry} tog timeout. Sparade filuppgifter ändrades inte.",
|
||||
"Logrotate optimization completed": "Logrotate-optimering slutförd",
|
||||
"Logrotate service restarted successfully": "Logrotate-tjänsten startades om",
|
||||
"Lollypop is a lightweight modern music player designed to work excellently on the GNOME desktop environment.": "Lollypop är en lätt modern musikspelare utformad för att fungera utmärkt på GNOME-skrivbordsmiljön.",
|
||||
@@ -3597,6 +3631,8 @@
|
||||
"Manage custom paths (add / remove your folders)": "Hantera anpassade sökvägar (lägg till / ta bort dina mappar)",
|
||||
"Manage installed OCI applications": "Hantera installerade OCI-program",
|
||||
"Manage local backup target": "Hantera lokalt mål för säkerhetskopiering",
|
||||
"Manage private image registries.\nSaved credentials let ProxMenux access your private images.": "Hantera privata bildregister.\nSparade referenser låter ProxMenux komma åt dina privata bilder.",
|
||||
"Manage registry accounts as root on the Proxmox node.": "Hantera registerkonton som root på Proxmox-noden.",
|
||||
"Managed disks must have backup enabled and a valid size": "Hanterade diskar måste ha backup aktiverad och en giltig storlek",
|
||||
"Managing Nginx proxy hosts with a simple, powerful interface.": "Hantera Nginx proxy värdar med ett enkelt, kraftfullt gränssnitt.",
|
||||
"Manual CLI Guide (Disk and Storage Manager)": "Manuell CLI-guide (disk- och lagringshanterare)",
|
||||
@@ -4114,6 +4150,7 @@
|
||||
"No accessible Samba servers found.": "Inga tillgängliga Samba-servrar hittades.",
|
||||
"No accessible exports found.": "Inga tillgängliga exporter hittades.",
|
||||
"No accessible shares found.": "Inga tillgängliga delningar hittades.",
|
||||
"No active Proxmox storage accepts OCI template archives.": "Ingen aktiv Proxmox-lagring accepterar OCI-mallarkiv.",
|
||||
"No active exports or showmount not available": "Inga aktiva exporter eller showmount är inte tillgängligt",
|
||||
"No active session": "Ingen aktiv session",
|
||||
"No active subscription and no usable PVE repository. Noninteractive mode cannot change APT sources; configure them in Node > Updates > Repositories.": "Ingen aktiv prenumeration och inget användbart PVE-arkiv. Icke-interaktivt läge kan inte ändra APT-källor; konfigurera dem i Node > Updates > Repositories.",
|
||||
@@ -4233,6 +4270,7 @@
|
||||
"No recent": "Inga nya",
|
||||
"No recent Samba servers found.": "Inga nya Samba-servrar hittades.",
|
||||
"No registered OCI containers are available for selection on this host.": "Inga registrerade OCI-behållare är tillgängliga för val på denna värd.",
|
||||
"No registry API was found at {registry}. Check the hostname and port.": "Inget register-API hittades på {registry}. Kontrollera värdnamnet och porten.",
|
||||
"No restored OCI application is waiting to be recovered.": "Ingen återställd OCI-applikation väntar på att återställas.",
|
||||
"No results": "Inga resultat",
|
||||
"No routing information found.": "Ingen ruttinformation hittades.",
|
||||
@@ -4297,7 +4335,9 @@
|
||||
"Not an OVH server, skipping RTM installation": "Inte en OVH-server, hoppar över RTM-installation",
|
||||
"Not currently mounted": "Ej monterad just nu",
|
||||
"Not currently mounted — skipping umount.": "Ej monterad för närvarande — hoppar över umount.",
|
||||
"Not declared": "Ej deklarerad",
|
||||
"Not enough free space for the backup": "Inte tillräckligt med ledigt utrymme för backup",
|
||||
"Not enough free space on {storage}. Free some space or select another storage.": "Inte tillräckligt med ledigt utrymme på {storage}. Frigör lite utrymme eller välj ett annat lagringsutrymme.",
|
||||
"Not found": "Hittade inte",
|
||||
"Not found in the OCI archive:": "Finns inte i OCI-arkivet:",
|
||||
"Not imported:": "Ej importerad:",
|
||||
@@ -4388,6 +4428,7 @@
|
||||
"Only Intel/AMD DRM, Coral and USB nodes can be adopted automatically": "Endast Intel/AMD DRM, Coral och USB-noder kan användas automatiskt",
|
||||
"Only Intel/AMD DRM, Coral, NPU and USB nodes can be adopted automatically": "Endast Intel/AMD DRM, Coral, NPU och USB-noder kan antas automatiskt",
|
||||
"Only a Docker Swarm uses these settings, so they are not applied:": "Endast en Docker Swarm använder dessa inställningar, så de tillämpas inte:",
|
||||
"Only a full sha256 image digest is supported.": "Endast en fullständig sha256-bildsammandragning stöds.",
|
||||
"Only an installed standalone OCI instance can adopt external changes": "Endast en installerad fristående OCI-instans kan anta externa ändringar",
|
||||
"Only backed-up Proxmox volumes can be adopted": "Endast säkerhetskopierade Proxmox-volymer kan användas",
|
||||
"Only convert to privileged if absolutely necessary for your use case.": "Konvertera endast till privilegierad om det är absolut nödvändigt för ditt användningsfall.",
|
||||
@@ -4541,6 +4582,7 @@
|
||||
"Passthrough may still work without a ROM file.": "Passthrough kan fortfarande fungera utan en ROM-fil.",
|
||||
"Passthrough may work, but startup/restart reliability is not guaranteed.": "Passthrough kan fungera, men tillförlitlighet vid start/omstart kan inte garanteras.",
|
||||
"Password": "Lösenord",
|
||||
"Password / access token (image pull permission)": "Lösenord / åtkomsttoken (tillstånd för bilddrag)",
|
||||
"Password Mismatch": "Lösenordet matchar inte",
|
||||
"Password cannot be empty.": "Lösenordet får inte vara tomt.",
|
||||
"Password confirmation cannot be empty.": "Lösenordsbekräftelsen kan inte vara tom.",
|
||||
@@ -4806,7 +4848,9 @@
|
||||
"ProxMenux attaches directories, not single files, so this image cannot be installed yet.": "ProxMenux fäster kataloger, inte enstaka filer, så denna bild kan inte installeras ännu.",
|
||||
"ProxMenux can apply open permissions on this NFS directory from the host so the container can read and write:": "ProxMenux kan tillämpa öppna behörigheter på denna NFS-katalog från värden så att behållaren kan läsa och skriva:",
|
||||
"ProxMenux can remount it with open permissions so any LXC can read and write.": "ProxMenux kan montera om den med öppna behörigheter så att alla LXC kan läsa och skriva.",
|
||||
"ProxMenux cannot install this image automatically. Import its Compose file instead.": "ProxMenux kan inte installera den här bilden automatiskt. Importera dess Compose-fil istället.",
|
||||
"ProxMenux cannot override NFS server-side permissions from the host.": "ProxMenux kan inte åsidosätta NFS-serversidans behörigheter från värden.",
|
||||
"ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.": "ProxMenux kunde inte översätta den här bilden. Försök att importera dess Compose-fil från OCI manager Apps.",
|
||||
"ProxMenux customizations removed from bashrc": "ProxMenux-anpassningar har tagits bort från bashrc",
|
||||
"ProxMenux does not give a container the system of its host.": "ProxMenux ger inte en behållare systemet för dess värd.",
|
||||
"ProxMenux does not install them. The installation asks how to connect to them.": "ProxMenux installerar dem inte. Installationen frågar hur man ansluter till dem.",
|
||||
@@ -4927,6 +4971,7 @@
|
||||
"Reading SMART data...": "Läser SMART-data...",
|
||||
"Reading SMART self-test log...": "Läser SMART självtestlogg...",
|
||||
"Reading full SMART report...": "Läser hela SMART-rapporten...",
|
||||
"Reading image metadata. Please wait...": "Läser bildmetadata. Vänligen vänta...",
|
||||
"Real-time Performance Monitoring": "Prestandaövervakning i realtid",
|
||||
"Real-time bandwidth usage (press q to exit)": "Användning av bandbredd i realtid (tryck på q för att avsluta)",
|
||||
"Real-time collaborative document editor": "Realtidssamverkan dokument redaktör",
|
||||
@@ -5019,6 +5064,9 @@
|
||||
"Register mount path in Proxmox:": "Registrera monteringssökväg i Proxmox:",
|
||||
"Registering disk as Proxmox storage...": "Registrerar disk som Proxmox-lagring...",
|
||||
"Registering module with DKMS...": "Registrerar modul med DKMS...",
|
||||
"Registry accounts": "Registerkonton",
|
||||
"Registry hostname": "Registrets värdnamn",
|
||||
"Registry: {registry}\nAccount: {account}\nAuthentication: {method}\n\nSaved credentials are verified when an image is accessed.": "Register: {registry}\nKonto: {account}\nAutentisering: {method}\n\nSparade autentiseringsuppgifter verifieras när en bild öppnas.",
|
||||
"Reinstall / update Coral drivers": "Installera om / uppdatera Coral-drivrutiner",
|
||||
"Reinstall Fail2Ban": "Installera om Fail2Ban",
|
||||
"Reinstall Lynis": "Installera om Lynis",
|
||||
@@ -5090,8 +5138,10 @@
|
||||
"Remove obsolete systemd-boot meta-package": "Ta bort föråldrat systemd-boot-metapaket",
|
||||
"Remove old repository files:": "Ta bort gamla arkivsfiler:",
|
||||
"Remove passthrough device from VM": "Ta bort passthrough-enhet från virtuell dator",
|
||||
"Remove saved credentials": "Ta bort sparade autentiseringsuppgifter",
|
||||
"Remove subscription banner": "Ta bort prenumerationsbanner",
|
||||
"Remove the application? Its container disks are deleted, and only a backup can bring them back.": "Vill du ta bort programmet? Dess containerdiskar raderas och endast en säkerhetskopia kan ta tillbaka dem.",
|
||||
"Remove the saved credentials for {registry}?\nRunning apps will keep working.": "Ta bort de sparade referenserna för {registry}?\nAppar som körs fortsätter att fungera.",
|
||||
"Remove the unprivileged flag from configuration:": "Ta bort den oprivilegierade flaggan från konfigurationen:",
|
||||
"Remove unused packages and their config": "Ta bort oanvända paket och deras konfiguration",
|
||||
"Remove: delete the application and its containers": "Ta bort: ta bort programmet och dess behållare",
|
||||
@@ -5413,6 +5463,7 @@
|
||||
"Save and classify articles. Read them later. Freely.": "Spara och klassificera artiklar. Läs dem senare. Fritt.",
|
||||
"Save the passphrase somewhere safe NOW, before continuing.": "Spara lösenfrasen någonstans säkert NU, innan du fortsätter.",
|
||||
"Save this Borg target so you don't need to enter the details again?": "Spara detta Borgmål så att du inte behöver ange detaljerna igen?",
|
||||
"Saved credentials for {registry} were removed.\nOther Skopeo/Docker credential files are managed separately.": "Sparade inloggningsuppgifter för {registry} togs bort.\nAndra Skopeo/Docker autentiseringsfiler hanteras separat.",
|
||||
"Saved record removed": "Saved Record bort",
|
||||
"Saving changes...": "Sparar ändringar...",
|
||||
"Saving the new configuration": "Spara den nya konfigurationen",
|
||||
@@ -5793,9 +5844,11 @@
|
||||
"Shutdown timeout": "Timeout för avstängning",
|
||||
"SiYuan access code": "SiYuan åtkomstkod",
|
||||
"SickGear provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more..": "SickGear tillhandahåller hantering av TV-program och / eller Anime, det upptäcker nya episoder, länkar nedladdningsprogram och mer.",
|
||||
"Sign in to a registry": "Logga in på ett register",
|
||||
"Sign in to the panel and create a Samba user in Settings before publishing a directory over SMB.": "Logga in på panelen och skapa en Samba-användare i Inställningar innan du publicerar en katalog över SMB.",
|
||||
"Signal is a messaging app with privacy at its core. It is free and easy to use, with strong end-to-end encryption that keeps your communication completely private.": "Signal är en meddelandeapp med integritet i kärnan. Det är gratis och lätt att använda, med stark end-to-end-kryptering som håller din kommunikation helt privat.",
|
||||
"Signatures removed. Partition table preserved.": "Signaturer har tagits bort. Partitionstabell bevarad.",
|
||||
"Signed in to {registry} as {username}.\n\nCredentials are saved for ProxMenux.\nSelect the account to check, download or install an image.": "Inloggad på {registry} som {username}.\n\nInloggningsuppgifter sparas för ProxMenux.\nVälj kontot för att kontrollera, ladda ner eller installera en bild.",
|
||||
"Simple and easy to use DDNS": "Enkelt och enkelt att använda DDNS",
|
||||
"Single GPU Warning": "Varning för enkel GPU",
|
||||
"Single target found — selected automatically:": "Enstaka mål hittades — väljs automatiskt:",
|
||||
@@ -5821,6 +5874,8 @@
|
||||
"Skipping SR-IOV device": "Hoppa över SR-IOV-enhet",
|
||||
"Skipping installation.": "Hoppa över installationen.",
|
||||
"Skipping manual patches — feranick fork already supports this kernel.": "Hoppa över manuella patchar — feranick fork stöder redan denna kärna.",
|
||||
"Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.": "Skopeo är inte tillgängligt. Återställ ProxMenux OCI beroenden och försök igen.",
|
||||
"Skopeo returned an invalid credential file; saved credentials were not changed.": "Skopeo returnerade en ogiltig autentiseringsfil; sparade referenser ändrades inte.",
|
||||
"Sleek podcast downloader with GPodder sync": "Sleek podcast downloader med GPodder sync",
|
||||
"Smart restore plan — hardware compatibility check": "Smart återställningsplan — kontroll av hårdvarukompatibilitet",
|
||||
"Smokeping keeps track of your network latency. For a full example of what this application is capable of visit UCDavis.": "Smokeping håller reda på din nätverks latens. För ett fullständigt exempel på vad denna ansökan kan besöka UCDavis.",
|
||||
@@ -6078,6 +6133,7 @@
|
||||
"TCP optimizations configuration completed": "TCP-optimeringskonfigurationen är klar",
|
||||
"TCP optimizations reverted (defaults restored on next reboot)": "TCP-optimeringar har återställts (standarderna återställs vid nästa omstart)",
|
||||
"TCP port 5201 is reachable (firewall on server)": "TCP-port 5201 är nåbar (brandvägg på servern)",
|
||||
"TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.": "TLS-verifiering misslyckades för {registry}. Installera registret CA i /etc/containers/certs.d/{registry}/ca.crt.",
|
||||
"TPM device added to VM": "TPM-enhet har lagts till VM",
|
||||
"TPM storage selection failed or was cancelled. VM creation aborted.": "Val av TPM-lagring misslyckades eller avbröts. VM-skapandet avbröts.",
|
||||
"TROUBLESHOOTING:": "FELSÖKNING:",
|
||||
@@ -6271,6 +6327,7 @@
|
||||
"The configuration must run as root on Proxmox VE": "Konfigurationen måste köras som rot på Proxmox VE",
|
||||
"The configuration of a new member changed after it was created": "Konfigurationen av en ny medlem ändrades efter att den skapades",
|
||||
"The configuration stopped because of an unexpected error": "Konfigurationen stannade på grund av ett oväntat fel",
|
||||
"The configured credential helper could not be used. Check its installation and credential store.": "Den konfigurerade autentiseringshjälpen kunde inte användas. Kontrollera dess installation och inloggningsarkiv.",
|
||||
"The console of the container could not be configured": "Behållarens konsol kunde inte konfigureras",
|
||||
"The consume/export volumes need at least 1 GB": "Förbruknings-/exportvolymerna behöver minst 1 GB",
|
||||
"The container could not be removed automatically:": "Behållaren kunde inte tas bort automatiskt:",
|
||||
@@ -6309,6 +6366,7 @@
|
||||
"The containers do not need them any more; an update downloads the new versions when there are any.": "Behållarna behöver dem inte längre; en uppdatering laddar ner de nya versionerna när det finns några.",
|
||||
"The containers were created from downloaded OCI images": "Behållarna skapades från nedladdade OCI-bilder",
|
||||
"The coordinated backup was modified": "Den samordnade backupen modifierades",
|
||||
"The credential file changed during this operation. Try again; it was not overwritten.": "Autentiseringsfilen ändrades under denna operation. Försök igen; den skrevs inte över.",
|
||||
"The current driver will be completely uninstalled before installing the new version. Continue?": "Den aktuella drivrutinen kommer att avinstalleras helt innan den nya versionen installeras. Fortsätta?",
|
||||
"The current image of the saved channel will be checked and downloaded. Resources, paths and GPU are kept. The CT is stopped during the replacement and a native backup is created first.": "Den aktuella bilden av den sparade kanalen kontrolleras och laddas ner. Resurser, vägar och GPU hålls. CT stoppas under ersättningen och en infödd säkerhetskopia skapas först.",
|
||||
"The current record is missing for": "Nuvarande rekord saknas för",
|
||||
@@ -6391,7 +6449,9 @@
|
||||
"The host-monitor firewall subnet changed; no firewall rule was added": "Värd-monitorns brandväggsundernät har ändrats;ingen brandväggsregel har lagts till",
|
||||
"The host-monitor web interface uses the host network.": "Värd-monitor-webbgränssnittet använder värdnätverket.",
|
||||
"The identity of a member was replaced": "En medlems identitet ersattes",
|
||||
"The image cache path is unsafe. Check the template storage before trying again.": "Bildcachesökvägen är osäker. Kontrollera malllagringen innan du försöker igen.",
|
||||
"The image changes the user expected by the adapter": "Bilden ändrar användaren som förväntas av adaptern",
|
||||
"The image could not be downloaded or verified. Check registry and storage access, then try again.": "Bilden kunde inte laddas ner eller verifieras. Kontrollera register- och lagringsåtkomst och försök sedan igen.",
|
||||
"The image could not be read from its registry:": "Bilden kunde inte läsas från dess register:",
|
||||
"The image declares data paths that are still stored in the rootfs": "Bilden förklarar datavägar som fortfarande lagras i rötterna",
|
||||
"The image did not grant the application user access to the devices; check its native init. Host permissions were not relaxed.": "Bilden gav inte applikationsanvändaren tillgång till enheterna; kontrollera dess inhemska init. Värdbehörigheter var inte avslappnade.",
|
||||
@@ -6404,6 +6464,8 @@
|
||||
"The image is in its registry, for one architecture.": "Bilden finns i dess register, för en arkitektur.",
|
||||
"The image is in its registry.": "Bilden finns i dess register.",
|
||||
"The image is in its registry:": "Bilden finns i dess register:",
|
||||
"The image manifest failed integrity verification. Try again or contact the image publisher.": "Bildmanifestet misslyckades med integritetsverifieringen. Försök igen eller kontakta bildutgivaren.",
|
||||
"The image or tag was not found on {registry}, or this account cannot access it. Check the reference.": "Bilden eller taggen hittades inte på {registry}, eller så kan det här kontot inte komma åt den. Kontrollera referensen.",
|
||||
"The image requests NVIDIA, but the host has no working NVIDIA driver": "Bilden begär NVIDIA, men värden har ingen fungerande NVIDIA-förare",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. Continue only if you trust the image and accept this risk.": "Bilden begär inaktivering av en del av AppArmor eller seccomp confinement. Fortsätt bara om du litar på bilden och accepterar denna risk.",
|
||||
"The image requests disabling part of the AppArmor or seccomp confinement. The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk.": "Bilden begär inaktivering av en del av AppArmor eller seccomp confinement. Komponera erbjuder en valfri AppArmor eller seccomp avslappning; det kommer att vara inaktiverat om inte användaren väljer det. Fortsätt bara om du litar på bilden och accepterar denna risk.",
|
||||
@@ -6541,7 +6603,15 @@
|
||||
"The record or diagnosis could not be completed; no update was run.": "Rekordet eller diagnosen kunde inte slutföras; ingen uppdatering kördes.",
|
||||
"The recovery did not complete. Review the log and choose \"Recover\" again for this container in the OCI management menu.": "Återhämtningen slutfördes inte. Granska loggen och välj \"Recover\" igen för den här behållaren i OCI-hanteringsmenyn.",
|
||||
"The recovery did not complete. Review the log and choose \"{choice}\" again for this container in the OCI management menu.": "Återställningen slutfördes inte. Granska loggen och välj \"{choice}\" igen för den här containern i OCI-hanteringsmenyn.",
|
||||
"The registry authentication file is invalid; it was not changed.": "Registerautentiseringsfilen är ogiltig; det ändrades inte.",
|
||||
"The registry authentication file must be owned by root with mode 600.": "Registerautentiseringsfilen måste ägas av root med läge 600.",
|
||||
"The registry authentication file must have an absolute path.": "Registerautentiseringsfilen måste ha en absolut sökväg.",
|
||||
"The registry authentication path cannot contain symbolic links.": "Registerautentiseringssökvägen kan inte innehålla symboliska länkar.",
|
||||
"The registry authentication path has an unsafe parent directory.": "Registerautentiseringssökvägen har en osäker överordnad katalog.",
|
||||
"The registry credential directory must be owned by root with mode 700.": "Registerreferenskatalogen måste ägas av root med läge 700.",
|
||||
"The registry did not return the saved image digest": "Registret returnerade inte den sparade avbildsdigesten",
|
||||
"The registry returned incomplete or unsupported image metadata.": "Registret returnerade ofullständig eller ostödd bildmetadata.",
|
||||
"The registry returned invalid or unsupported image metadata.": "Registret returnerade ogiltig eller ostödd bildmetadata.",
|
||||
"The remote does not exist; create and authorize it first in the WebUI:": "Fjärrkontrollen finns inte; skapa och godkänna den först i WebUI:",
|
||||
"The remote installer must run as root on Proxmox VE": "Fjärrinstallatören måste köras som rot på Proxmox VE",
|
||||
"The remote must already be created and authorized in the Rclone web UI. This operation restarts the CT and publishes two FUSE views on the host.": "Fjärrkontrollen måste redan skapas och auktoriseras i Rclone webb-UI. Denna operation startar om CT och publicerar två FUSE-vyer på värden.",
|
||||
@@ -6700,6 +6770,7 @@
|
||||
"This GPU is considered incompatible with GPU passthrough to a VM in ProxMenux.": "Denna GPU anses vara inkompatibel med GPU-genomföring till en virtuell dator i ProxMenux.",
|
||||
"This NFS share is fully restricted — even the host root cannot write to it.": "Denna NFS-resurs är helt begränsad — även värdroten kan inte skriva till den.",
|
||||
"This VM requires extra installation steps, see install guide at:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144": "Denna virtuella dator kräver extra installationssteg, se installationsguiden på:\nhttps://github.com/community-scripts/ProxmoxVE/discussions/144",
|
||||
"This account is for {registry}. Enter an image from that registry.": "Detta konto är för {registry}. Ange en bild från det registret.",
|
||||
"This action will:": "Denna åtgärd kommer att:",
|
||||
"This application cannot be recovered yet:": "Denna applikation kan inte återställas ännu:",
|
||||
"This application cannot be recovered yet; nothing was changed:": "Denna applikation kan inte återställas ännu; ingenting ändrades:",
|
||||
@@ -6731,8 +6802,10 @@
|
||||
"This explicitly marks the container as privileged": "Detta markerar uttryckligen behållaren som privilegierad",
|
||||
"This file decides what is mounted and with which privileges. Install it only if it comes from a source you trust.": "Den här filen bestämmer vad som monteras och med vilka privilegier. Installera den bara om den kommer från en källa du litar på.",
|
||||
"This guarantees that device nodes are available before applying LXC GPU config.": "Detta garanterar att enhetsnoder är tillgängliga innan du använder LXC GPU-konfiguration.",
|
||||
"This host architecture is not supported by the OCI image importer.": "Denna värdarkitektur stöds inte av OCI-bildimportören.",
|
||||
"This host has no active subscription, switch to the no-subscription repository? The inaccessible Enterprise PVE source will be disabled. Enterprise Ceph sources, if present, will be disabled without choosing a replacement Ceph channel; configure Ceph separately if needed.": "Den här värden har ingen aktiv prenumeration, byta till arkivet utan prenumeration? Den otillgängliga Enterprise PVE-källan inaktiveras. Enterprise Ceph-källor, om sådana finns, inaktiveras utan att en ersättande Ceph-kanal väljs; konfigurera Ceph separat om det behövs.",
|
||||
"This image cannot be installed as it is described:": "Denna bild kan inte installeras eftersom den beskrivs:",
|
||||
"This image has no compatible Linux image for this host ({architecture}).": "Den här bilden har ingen kompatibel Linux-bild för denna värd ({architecture}).",
|
||||
"This image requires the host module": "Denna bild requires värdmodulen",
|
||||
"This import rejects these paths without checking whether they are files or directories.": "Den här importen avvisar sökvägarna utan att kontrollera om de är filer eller kataloger.",
|
||||
"This installation will:": "Denna installation kommer att:",
|
||||
@@ -6848,6 +6921,7 @@
|
||||
"To use the GPU again in LXC, run Add GPU to LXC from GPUs and Coral-TPU Menu": "För att använda GPU igen i LXC, kör Lägg till GPU till LXC från GPU:er och Coral-TPU Menu",
|
||||
"To use the VM without issues, the host must be restarted before starting it.": "För att använda den virtuella datorn utan problem måste värden startas om innan den startas.",
|
||||
"To use this share from an LXC, bind-mount it via:": "För att använda denna del från en LXC, bind-montera den via:",
|
||||
"Token": "Token",
|
||||
"Tool exit code:": "Verktygsutgångskod:",
|
||||
"Tool output:": "Verktygsutgång:",
|
||||
"Tools": "Verktyg",
|
||||
@@ -6992,6 +7066,7 @@
|
||||
"Unsafe private configuration path": "Osäkra privata konfigurationsvägar",
|
||||
"Unsafe qBittorrent configuration path": "Osäker qBittorrent konfigurationsväg",
|
||||
"Unsafe record": "Osäker rekord",
|
||||
"Unsafe registry credential lock.": "Osäkert registerlås.",
|
||||
"Unsafe registry directory": "Osäker registerkatalog",
|
||||
"Unsafe registry lock": "Osäkra register lås",
|
||||
"Unsafe rootfs for the capture": "Osäkra rötter för fångsten",
|
||||
@@ -7004,6 +7079,7 @@
|
||||
"Unsupported OCI-LXC AppArmor profile:": "Ostödd OCI-LXC AppArmor-profil:",
|
||||
"Unsupported OCI-LXC seccomp profile:": "Unsupported OCI-LXC seccomp profil:",
|
||||
"Unsupported Terminal": "Terminal som inte stöds",
|
||||
"Unsupported architecture for Figurine:": "Arkitekturen stöds inte av Figurine:",
|
||||
"Unsupported architecture:": "Ostödd arkitektur:",
|
||||
"Unsupported backup compression": "Unsupported backup komprimering",
|
||||
"Unsupported credential pattern:": "Unsupported credential mönster:",
|
||||
@@ -7056,6 +7132,7 @@
|
||||
"Update cancelled by user": "Uppdateringen avbröts av användaren",
|
||||
"Update completed. Data kept.": "Uppdatering färdig. Data hålls.",
|
||||
"Update completed. Press Enter to continue...": "Uppdatering slutförd. Tryck på Enter för att fortsätta...",
|
||||
"Update credentials": "Uppdatera användaruppgifter",
|
||||
"Update every container of the application": "Uppdatera varje behållare av programmet",
|
||||
"Update kernel to compatible version": "Uppdatera kärnan till kompatibel version",
|
||||
"Update now?": "Uppdatera nu?",
|
||||
@@ -7122,8 +7199,10 @@
|
||||
"Use a custom path": "Använd en anpassad sökväg",
|
||||
"Use a privileged LXC for NFS server/client workflows.": "Använd en privilegierad LXC för NFS-server/klient-arbetsflöden.",
|
||||
"Use a privileged LXC for Samba client/server workflows.": "Använd en privilegierad LXC för Samba klient/server arbetsflöden.",
|
||||
"Use a registry hostname, for example ghcr.io or registry.example.com:5000.": "Använd ett registervärdnamn, till exempel ghcr.io eller registry.example.com:5000.",
|
||||
"Use an existing SSH private key file on this host": "Använd en befintlig privat SSH-nyckelfil på denna värd",
|
||||
"Use an existing keyfile": "Använd en befintlig nyckelfil",
|
||||
"Use an image reference, for example ghcr.io/owner/app:latest.": "Använd en bildreferens, till exempel ghcr.io/owner/app:latest.",
|
||||
"Use as-is — keep data and filesystem": "Använd som det är — behåll data och filsystem",
|
||||
"Use content types according to your use case.": "Använd innehållstyper enligt ditt användningsfall.",
|
||||
"Use default": "Använd standard",
|
||||
@@ -7163,6 +7242,7 @@
|
||||
"User-friendly WebUI for LLMs (Formerly Ollama WebUI)": "Användarvänlig WebUI för LLMs (tidigare Ollama WebUI)",
|
||||
"Username": "Användarnamn",
|
||||
"Username (e.g. root@pam or user@pbs!token):": "Användarnamn (t.ex. root@pam eller user@pbs!token):",
|
||||
"Username / token": "Användarnamn / token",
|
||||
"Username and password": "Användarnamn och lösenord",
|
||||
"Username and password will be cleared.": "Användarnamn och lösenord kommer att raderas.",
|
||||
"Username cannot be empty.": "Användarnamnet får inte vara tomt.",
|
||||
@@ -7262,6 +7342,7 @@
|
||||
"Verifying Ceph packages availability...": "Verifierar tillgängligheten av Ceph-paket...",
|
||||
"Verifying all utilities status": "Verifierar alla verktygs status",
|
||||
"Verifying disk accessibility in CT": "Verifierar disktillgänglighet i CT",
|
||||
"Verifying registry access. Please wait...": "Verifierar registeråtkomst. Vänligen vänta...",
|
||||
"Verifying the backups...": "Verifiera backups...",
|
||||
"Verifying the image integrity...": "Verifiera bildintegriteten...",
|
||||
"Version": "Version",
|
||||
@@ -7561,6 +7642,7 @@
|
||||
"assembling": "montering",
|
||||
"automatically. Install it manually inside the container.": "automatiskt. Installera den manuellt inuti behållaren.",
|
||||
"automatically. Reboot LXC to fully release.": "automatiskt. Starta om LXC för att släppa helt.",
|
||||
"available": "Tillgänglig",
|
||||
"available for LXC bind-mounts via 'LXC Mount Manager'": "tillgänglig för LXC bind-mounts via \"LXC Mount Manager\"",
|
||||
"available in this same GPU and TPU menu.": "tillgänglig i samma GPU- och TPU-meny.",
|
||||
"backup at /etc/fstab.proxmenux.bak": "säkerhetskopia på /etc/fstab.proxmenux.bak",
|
||||
@@ -7913,6 +7995,7 @@
|
||||
"runs in": "springs in",
|
||||
"safe paths now (configs, packages, /etc, /root, ...)": "säkra sökvägar nu (konfigurationer, paket, /etc, /root, ...)",
|
||||
"same MAC": "samma MAC",
|
||||
"saved": "Sparad",
|
||||
"seconds (default)": "sekunder (standard)",
|
||||
"see log:": "se logg:",
|
||||
"selected by default": "valt som standard",
|
||||
@@ -8031,8 +8114,16 @@
|
||||
"zfs-auto-snapshot removed (existing snapshots preserved on the pool)": "zfs-auto-snapshot har tagits bort (befintliga ögonblicksbilder bevarade på poolen)",
|
||||
"zpool command not found. Install zfsutils-linux and retry.": "zpool-kommandot hittades inte. Installera zfsutils-linux och försök igen.",
|
||||
"zpool not found. Install zfsutils-linux and retry.": "zpool hittades inte. Installera zfsutils-linux och försök igen.",
|
||||
"{count} saved account.": "{count} sparat konto.",
|
||||
"{count} saved accounts.": "{count} sparade konton.",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add access rules (ACL) to this directory, to everything inside it and to what is created there later, for the users and groups {app} runs as on the host (IDs {ids}). The owner of the files does not change and whatever reads or writes them today keeps doing so; the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} finns redan och tillhör en annan användare på värden, så {app} kan inte skriva till den.\n\nProxMenux kan lägga till åtkomstregler (ACL) för den här katalogen, för allt i den och för det som skapas där senare, för de användare och grupper som {app} körs som på värden (ID {ids}). Ägaren till filerna ändras inte och det som läser eller skriver dem i dag fortsätter att göra det; katalogens ägare får också åtkomst till filerna som {app} skapar.\n\nGe {app} åtkomst till den här katalogen?",
|
||||
"{path} already exists and belongs to another user of the host, so {app} cannot write to it.\n\nProxMenux can add an access rule (ACL) for the identity {app} uses on the host (UID {uid}). Nothing that is there changes owner or permissions: whatever reads or writes those files today keeps doing so, and the owner of the directory also gets access to the files {app} creates.\n\nGrant {app} access to this directory?": "{path} finns redan och tillhör en annan användare av värden, så {app} kan inte skriva till den.\n\nProxMenux kan lägga till en åtkomstregel (ACL) för identiteten {app} använder på värden (UID {uid}).Inget som finns där ändrar ägare eller behörigheter: vad som än läser eller skriver dessa filer idag fortsätter att göra det, och ägaren av katalogen får också tillgång till filerna som {app} skapar.\n\nGe {app} åtkomst till den här katalogen?",
|
||||
"{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.": "{registry} besvarades med vanlig HTTP. Använd ett register med HTTPS; TLS-verifiering förblir aktiverad.",
|
||||
"{registry} did not respond within {timeout} seconds. Try again later.": "{registry} svarade inte inom {timeout} sekunder. Försök igen senare.",
|
||||
"{registry} is rate limiting requests. Wait a while and try again.": "{registry} är hastighetsbegränsande förfrågningar. Vänta ett tag och försök igen.",
|
||||
"{registry} refused access to this image:\n{reference}\n\nIf the image is private, sign in with an account that can pull it.\n\nSign in now?": "{registry} vägrade tillgång till denna bild:\n{reference}\n\nOm bilden är privat, logga in med ett konto som kan dra den.\n\nLogga in nu?",
|
||||
"{registry} reported a server error. Try again later.": "{registry} rapporterade ett serverfel. Försök igen senare.",
|
||||
"{registry} returned invalid or unsupported image metadata.": "{registry} returnerade ogiltig eller ostödd bildmetadata.",
|
||||
"— Full/Custom restore will skip kernel-tied paths": "— Full/Custom-återställning hoppar över kärnbundna sökvägar",
|
||||
"— disk may be busy. Skipping fstab removal.": "— disken kan vara upptagen. Hoppa över fstab-borttagning.",
|
||||
"— restore proceeds as same-version (verified safe)": "— återställning fortsätter som samma version (verifierad säker)",
|
||||
|
||||
@@ -10,6 +10,7 @@ This document describes the engine in this directory: how it is organised, how a
|
||||
- [Structure](#structure)
|
||||
- [How a container is created](#how-a-container-is-created)
|
||||
- [Update, modify, recreate and remove](#update-modify-recreate-and-remove)
|
||||
- [Private image registries](#private-image-registries)
|
||||
- [From a Compose file or a docker run command to an oci-compose](#from-a-compose-file-or-a-docker-run-command-to-an-oci-compose)
|
||||
- [The oci-compose, block by block](#the-oci-compose-block-by-block)
|
||||
- [Writing and testing an oci-compose](#writing-and-testing-an-oci-compose)
|
||||
@@ -60,6 +61,46 @@ There are three places an oci-compose comes from:
|
||||
|
||||
On a node, the engine is installed in `/usr/local/share/proxmenux/oci/engine/`. Every installation keeps its record in `/usr/local/share/proxmenux/oci/instances/<VMID>/oci-compose.json`: the oci-compose it was installed from, under `template`, together with the answers given during the installation and the configuration Proxmox VE ended with. Updates, changes and removals read that record.
|
||||
|
||||
## Private image registries
|
||||
|
||||
Open **OCI manager Apps → Registry accounts** on the Proxmox node. Sign in
|
||||
with a registry hostname (for example `ghcr.io` or `registry.example.com:5443`),
|
||||
a username and a password or token with image pull permission. Passwords are
|
||||
entered in hidden fields and confirmed before the registry is contacted.
|
||||
|
||||
Select a saved account to check access to an image, download it to template
|
||||
storage, install it with the existing LXC wizard, update its credentials or
|
||||
remove them. Image references retain their tag or full `sha256` digest.
|
||||
The normal custom-image importer can also use the saved credentials, including
|
||||
Compose files whose services come from private registries. When a registry
|
||||
refuses an image there, the importer offers to sign in on the spot and reads
|
||||
the image again. Updates, Modify, Recreate, the watchdog and the update check
|
||||
of the Monitor use the saved accounts too.
|
||||
|
||||
ProxMenux keeps the accounts in `/etc/pve/priv/proxmenux/registry-auth.json`,
|
||||
where Proxmox keeps its own storage passwords: readable only by root and shared
|
||||
by every node of the cluster. The host backup includes it, and uninstalling
|
||||
ProxMenux removes it. A `REGISTRY_AUTH_FILE` set by the user is respected;
|
||||
without the cluster filesystem, Skopeo's default `/root/.config/containers/auth.json`
|
||||
is used. The
|
||||
credential directory must be owned by root with mode `700`, and the file with
|
||||
mode `600`. Basic credentials are base64 encoded, not encrypted. Configured
|
||||
Skopeo credential helpers use their own stores. Failed sign-in attempts leave
|
||||
the previous file credentials intact; removing an account leaves running
|
||||
applications unchanged. Other Skopeo/Docker authentication files are managed
|
||||
separately and may still grant access.
|
||||
|
||||
TLS verification remains enabled. Install a private registry CA in
|
||||
`/etc/containers/certs.d/REGISTRY[:PORT]/ca.crt` when required, on each node
|
||||
that pulls images. Registry credentials are not written into the application
|
||||
template or copied into its LXC.
|
||||
|
||||
Image access checks have a 30-second timeout per request; sign-in has a 45-second
|
||||
timeout. Errors identify rejected credentials, missing images, incompatible
|
||||
architectures, network/TLS failures, rate limits and registry outages. Downloads
|
||||
reuse the native update cache and layer integrity checks. Damaged cached images
|
||||
are downloaded again, and storage failures leave existing applications alone.
|
||||
|
||||
## How a container is created
|
||||
|
||||
Selecting an application, or giving a definition, opens the same sequence.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
if [[ -z ${REGISTRY_AUTH_FILE:-} && -f /etc/pve/priv/proxmenux/registry-auth.json ]]; then
|
||||
export REGISTRY_AUTH_FILE=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
fi
|
||||
|
||||
TEMPLATE_FILE=${1:?template JSON required}
|
||||
DEPLOYMENT_FILE=${2:?deployment JSON required}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
if [[ -z ${REGISTRY_AUTH_FILE:-} && -f /etc/pve/priv/proxmenux/registry-auth.json ]]; then
|
||||
export REGISTRY_AUTH_FILE=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
fi
|
||||
|
||||
TEMPLATE_FILE=${1:?template JSON required}
|
||||
DEPLOYMENT_FILE=${2:?deployment JSON required}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
if [[ -z ${REGISTRY_AUTH_FILE:-} && -f /etc/pve/priv/proxmenux/registry-auth.json ]]; then
|
||||
export REGISTRY_AUTH_FILE=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
fi
|
||||
|
||||
TEMPLATE_FILE=${1:?template JSON required}
|
||||
DEPLOYMENT_FILE=${2:?deployment JSON required}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
if [[ -z ${REGISTRY_AUTH_FILE:-} && -f /etc/pve/priv/proxmenux/registry-auth.json ]]; then
|
||||
export REGISTRY_AUTH_FILE=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
fi
|
||||
|
||||
TEMPLATE_FILE=${1:?template JSON required}
|
||||
DEPLOYMENT_FILE=${2:?deployment JSON required}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
if [[ -z ${REGISTRY_AUTH_FILE:-} && -f /etc/pve/priv/proxmenux/registry-auth.json ]]; then
|
||||
export REGISTRY_AUTH_FILE=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
fi
|
||||
|
||||
TEMPLATE_FILE=${1:?template JSON required}
|
||||
DEPLOYMENT_FILE=${2:?deployment JSON required}
|
||||
|
||||
@@ -19,6 +19,11 @@ import uuid
|
||||
|
||||
from oci_ui import translate, msg_error, msg_ok
|
||||
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
REGISTRY_AUTH_FILE = '/etc/pve/priv/proxmenux/registry-auth.json'
|
||||
if not os.environ.get('REGISTRY_AUTH_FILE') and os.path.isfile(REGISTRY_AUTH_FILE):
|
||||
os.environ['REGISTRY_AUTH_FILE'] = REGISTRY_AUTH_FILE
|
||||
|
||||
ROOT = Path('/var/lib/proxmenux/oci-installations')
|
||||
FIELDS = ('Entrypoint', 'Cmd', 'Env', 'User', 'WorkingDir', 'StopSignal', 'Volumes', 'ExposedPorts', 'Healthcheck')
|
||||
VERSION_ENV_RE = re.compile(r'^([A-Z][A-Z0-9_]*)_VERSION$')
|
||||
|
||||
@@ -16,6 +16,11 @@ import oci_work_backup as work_backup
|
||||
from oci_installation_state import image_from_archive, same_image
|
||||
from oci_ui import translate, msg_info, msg_ok, msg_warn, msg_error, msg_info2
|
||||
|
||||
# A registry login saved by ProxMenux lets skopeo read private images.
|
||||
REGISTRY_AUTH_FILE = '/etc/pve/priv/proxmenux/registry-auth.json'
|
||||
if not os.environ.get('REGISTRY_AUTH_FILE') and os.path.isfile(REGISTRY_AUTH_FILE):
|
||||
os.environ['REGISTRY_AUTH_FILE'] = REGISTRY_AUTH_FILE
|
||||
|
||||
|
||||
def repository(reference):
|
||||
repo = reference.split('@', 1)[0]
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
"""ProxMenux LinuxServer-to-Proxmox OCI laboratory tools."""
|
||||
|
||||
from .registry_auth import use_cluster_auth_file as _use_cluster_auth_file
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
# Every skopeo call of the engine reads the registry accounts kept for the cluster.
|
||||
_use_cluster_auth_file()
|
||||
|
||||
@@ -559,6 +559,7 @@ def interactive(catalog: Catalog) -> int:
|
||||
("search", translate("Search applications")),
|
||||
("all", f"{translate('All applications'):<35} ({len(applications):>3})"),
|
||||
("manage", translate("Manage installed OCI applications")),
|
||||
("registries", translate("Registry accounts")),
|
||||
("custom", translate("Install an image that is not in the catalog")),
|
||||
("", ""),
|
||||
] + [(number, f"{translate(labels[key]):<35} ({len(categories[key]):>3})")
|
||||
@@ -580,6 +581,9 @@ def interactive(catalog: Catalog) -> int:
|
||||
console.show_logo()
|
||||
console.msg_title(translate("Manage installed OCI applications"))
|
||||
interactive_management(PROJECT_ROOT, ui)
|
||||
elif selection == "registries":
|
||||
from .registry_accounts import open_registry_accounts
|
||||
open_registry_accounts(ui)
|
||||
elif selection == "custom":
|
||||
from .custom import explore
|
||||
explore(ui)
|
||||
|
||||
@@ -22,9 +22,17 @@ from .i18n import source_text
|
||||
from .installer import ADVANCED_MODE, DEFAULT_MODE
|
||||
from .converter import ConversionError
|
||||
from .i18n import translate
|
||||
from .registry_auth import RegistryError, refuses_access, validate_image
|
||||
from .ui import UserCancelled
|
||||
|
||||
IMAGE_REFERENCE = re.compile(r'^[A-Za-z0-9][A-Za-z0-9._/-]*(?::[A-Za-z0-9._-]+)?(?:@sha256:[a-f0-9]{64})?$')
|
||||
def _valid_image_reference(reference: str) -> bool:
|
||||
try:
|
||||
validate_image(reference)
|
||||
return True
|
||||
except RegistryError:
|
||||
return False
|
||||
|
||||
|
||||
MAX_COMPOSE_BYTES = 256 * 1024
|
||||
# An oci-compose: the file ProxMenux installs an application from. The catalog
|
||||
# keeps one for each of its applications and every installation records its own.
|
||||
@@ -176,7 +184,7 @@ def template_from_compose(text: str, title: str | None = None) -> dict[str, Any]
|
||||
def compose_from_image(reference: str, title: str | None = None) -> str:
|
||||
"""A Compose file written from what the image declares: its ports, its
|
||||
persistent paths and its variables."""
|
||||
if not IMAGE_REFERENCE.fullmatch(reference):
|
||||
if not _valid_image_reference(reference):
|
||||
raise ConversionError(f"{translate('This is not a valid image reference:')} {reference}")
|
||||
result = subprocess.run(['skopeo', 'inspect', '--config', f'docker://{reference}'],
|
||||
capture_output=True, text=True, check=False, timeout=120)
|
||||
@@ -283,7 +291,7 @@ def compose_from_docker_run(command: str, title: str | None = None) -> str:
|
||||
f"{', '.join(sorted(set(unsupported)))}")
|
||||
if not image:
|
||||
raise ConversionError(translate('The command does not name an image'))
|
||||
if not IMAGE_REFERENCE.fullmatch(image):
|
||||
if not _valid_image_reference(image):
|
||||
raise ConversionError(f"{translate('This is not a valid image reference:')} {image}")
|
||||
service['image'] = image
|
||||
name = normalize_app_id(title or service.get('container_name')
|
||||
@@ -402,7 +410,7 @@ def template_from_oci_compose(text: str) -> dict[str, Any]:
|
||||
reference = image.get('reference') if isinstance(image, dict) else None
|
||||
if not isinstance(reference, str) or not reference.strip():
|
||||
raise ConversionError(translate('The oci-compose is incomplete: it does not say which image to install.'))
|
||||
if not IMAGE_REFERENCE.fullmatch(reference):
|
||||
if not _valid_image_reference(reference):
|
||||
raise ConversionError(f"{translate('This is not a valid image reference:')} {reference}")
|
||||
faulty = translate('The oci-compose has errors:')
|
||||
|
||||
@@ -515,6 +523,12 @@ def read_definition(ui) -> tuple[str, str]:
|
||||
return compose_from_docker_run(_read_pasted(ui, translate('docker run command of the application'))), \
|
||||
translate('docker run command')
|
||||
reference = ui.ask(translate('Image reference (for example ghcr.io/user/application:latest)'), '')
|
||||
try:
|
||||
return compose_from_image(reference), translate('image itself')
|
||||
except ConversionError as error:
|
||||
from .registry_accounts import offer_sign_in
|
||||
if not (refuses_access(error) and offer_sign_in(ui, reference)):
|
||||
raise
|
||||
return compose_from_image(reference), translate('image itself')
|
||||
|
||||
|
||||
@@ -610,6 +624,16 @@ def registry_report(reference: str) -> tuple[bool, str]:
|
||||
return True, f"{translate('The image is in its registry:')} {', '.join(architectures)}"
|
||||
|
||||
|
||||
def _registry_refused(reference: str) -> bool:
|
||||
"""Whether the registry answered that the image needs an account."""
|
||||
try:
|
||||
result = subprocess.run(['skopeo', 'inspect', '--raw', f'docker://{reference}'],
|
||||
capture_output=True, text=True, check=False, timeout=120)
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return False
|
||||
return result.returncode != 0 and refuses_access(result.stderr)
|
||||
|
||||
|
||||
def describe(template: dict[str, Any]) -> str:
|
||||
"""What the translation understood, in the words of the installer, with
|
||||
everything that changes how the container is created."""
|
||||
@@ -720,13 +744,18 @@ def explore(ui) -> None:
|
||||
template = template_from_compose(text)
|
||||
title = translate('Image that is not in the catalog')
|
||||
summary = describe(template) + (describe_oci_compose(template) if written else '')
|
||||
available, report = registry_report(template['container_contract']['image']['reference'])
|
||||
reference = template['container_contract']['image']['reference']
|
||||
available, report = registry_report(reference)
|
||||
if not available and _registry_refused(reference):
|
||||
from .registry_accounts import offer_sign_in
|
||||
if offer_sign_in(ui, reference, title):
|
||||
available, report = registry_report(reference)
|
||||
summary += '\n\n' + report
|
||||
if notes:
|
||||
summary += '\n\n' + '\n'.join(notes)
|
||||
if not available:
|
||||
advice = translate('Check the image reference and registry access. If the registry is unavailable, '
|
||||
'try again later. A private registry needs credentials, which are not supported yet.')
|
||||
'try again later. For a private image, sign in from Registry accounts in the OCI menu.')
|
||||
ui.message(f'{summary}\n\n{advice}', title)
|
||||
return
|
||||
if not template.get('compatibility', {}).get('automatic_install_candidate'):
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
# ==========================================================
|
||||
# ProxMenux - Private OCI registry accounts
|
||||
# ==========================================================
|
||||
# Author : Jonatan
|
||||
# GitHub : github.com/jcastro
|
||||
# Maintainer : MacRimi
|
||||
# Copyright : (c) 2026 MacRimi & contributors
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.0
|
||||
# Last Updated: 16/10/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Manage private registry accounts from the native OCI menu.
|
||||
# Check image access, download verified archives and hand image
|
||||
# installation to the existing ProxMenux LXC wizard.
|
||||
# ==========================================================
|
||||
|
||||
"""Private image registry accounts in the native ProxMenux OCI menu."""
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager, redirect_stdout
|
||||
import errno
|
||||
import importlib
|
||||
import io
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from .i18n import translate
|
||||
from .registry_auth import (RegistryAuth, RegistryError, clean, require_root,
|
||||
validate_registry, validate_image, registry_of,
|
||||
registry_error, registry_environment)
|
||||
|
||||
ENGINE_ROOT = Path(__file__).resolve().parents[2]
|
||||
REGISTRY_QUERY_TIMEOUT = 30
|
||||
|
||||
|
||||
@contextmanager
|
||||
def image_queries(reference):
|
||||
"""Keep the native resolver while retaining safe, useful transport errors."""
|
||||
images = importlib.import_module('oci_installation_state')
|
||||
original = images.command
|
||||
registry = registry_of(reference)
|
||||
|
||||
def query(*args):
|
||||
if args[:2] != ('skopeo', 'inspect'):
|
||||
return original(*args)
|
||||
try:
|
||||
result = subprocess.run(args, capture_output=True, timeout=REGISTRY_QUERY_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
raise RegistryError(translate('{registry} did not respond within {timeout} seconds. Try again later.').format(registry=registry, timeout=REGISTRY_QUERY_TIMEOUT)) from None
|
||||
except FileNotFoundError:
|
||||
raise RegistryError(translate('Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.')) from None
|
||||
if result.returncode:
|
||||
raise RegistryError(registry_error(registry, result.stderr.decode(errors='replace')))
|
||||
return result.stdout
|
||||
|
||||
images.command = query
|
||||
try:
|
||||
yield images
|
||||
finally:
|
||||
images.command = original
|
||||
|
||||
|
||||
def bytes_label(size):
|
||||
value = float(size)
|
||||
for unit in ('B', 'KiB', 'MiB', 'GiB', 'TiB'):
|
||||
if value < 1024 or unit == 'TiB':
|
||||
return f'{value:.0f} {unit}' if unit == 'B' else f'{value:.1f} {unit}'
|
||||
value /= 1024
|
||||
|
||||
|
||||
def host_architecture():
|
||||
architecture = {'x86_64': 'amd64', 'aarch64': 'arm64'}.get(os.uname().machine)
|
||||
if not architecture:
|
||||
raise RegistryError(translate('This host architecture is not supported by the OCI image importer.'))
|
||||
return architecture
|
||||
|
||||
|
||||
def image_template(reference):
|
||||
reference = validate_image(reference)
|
||||
custom = importlib.import_module('proxmenux_oci.custom')
|
||||
try:
|
||||
compose = custom.compose_from_image(reference)
|
||||
except (custom.ConversionError, subprocess.TimeoutExpired, ValueError) as error:
|
||||
raise RegistryError(registry_error(registry_of(reference), error)) from None
|
||||
try:
|
||||
template = custom.template_from_compose(compose)
|
||||
custom._ask_secrets(template)
|
||||
except custom.ConversionError:
|
||||
raise RegistryError(translate('ProxMenux could not translate this image. Try importing its Compose file from OCI manager Apps.')) from None
|
||||
return template
|
||||
|
||||
|
||||
def inspect_registry_image(reference):
|
||||
reference = validate_image(reference)
|
||||
try:
|
||||
with registry_environment(), image_queries(reference) as images:
|
||||
candidate = images.resolve_candidate(reference, host_architecture())
|
||||
except RegistryError:
|
||||
raise
|
||||
except ValueError as error:
|
||||
detail = str(error).casefold()
|
||||
if 'platform' in detail or 'architecture' in detail:
|
||||
raise RegistryError(translate('This image has no compatible Linux image for this host ({architecture}).').format(architecture=host_architecture())) from None
|
||||
if 'manifest does not match' in detail or 'integrity' in detail:
|
||||
raise RegistryError(translate('The image manifest failed integrity verification. Try again or contact the image publisher.')) from None
|
||||
raise RegistryError(translate('The registry returned invalid or unsupported image metadata.')) from None
|
||||
except (KeyError, AttributeError, TypeError):
|
||||
raise RegistryError(translate('The registry returned incomplete or unsupported image metadata.')) from None
|
||||
except (RuntimeError, subprocess.TimeoutExpired) as error:
|
||||
raise RegistryError(registry_error(registry_of(reference), error)) from None
|
||||
return {'reference': reference, 'architecture': host_architecture(), 'version': clean(candidate.get('version')) or None,
|
||||
'digest': candidate['manifest_digest'], 'size': candidate.get('size') or 0}
|
||||
|
||||
|
||||
def download_registry_image(reference, storage):
|
||||
"""Download and verify with the exact native updater cache implementation."""
|
||||
reference = validate_image(reference)
|
||||
if not re.fullmatch(r'[A-Za-z0-9_-]+', storage):
|
||||
raise RegistryError(translate('Invalid template storage name.'))
|
||||
inspect_registry_image(reference)
|
||||
native = importlib.import_module('oci_update_current')
|
||||
desired = {'template': {'container_contract': {'image': {'reference': reference}}},
|
||||
'deployment': {'template_storage': storage}}
|
||||
try:
|
||||
with native.instances.locked(native.instances.ROOT), registry_environment(), redirect_stdout(io.StringIO()):
|
||||
path, digest = native.resolve_archive(desired, f'arch: {host_architecture()}\n'.encode())
|
||||
except BlockingIOError:
|
||||
raise RegistryError(translate('Another ProxMenux OCI operation is running. Try again when it finishes.')) from None
|
||||
except RegistryError:
|
||||
raise
|
||||
except (RuntimeError, ValueError, OSError, subprocess.TimeoutExpired) as error:
|
||||
detail = str(error).casefold()
|
||||
if getattr(error, 'errno', None) == errno.ENOSPC or 'does not fit' in detail or 'no space left' in detail:
|
||||
raise RegistryError(translate('Not enough free space on {storage}. Free some space or select another storage.').format(storage=storage)) from None
|
||||
if isinstance(error, PermissionError) or getattr(error, 'errno', None) == errno.EROFS:
|
||||
raise RegistryError(translate('Cannot write the image archive to {storage}. Check storage access and mount status.').format(storage=storage)) from None
|
||||
if 'unsafe' in detail or 'symbolic link' in detail:
|
||||
raise RegistryError(translate('The image cache path is unsafe. Check the template storage before trying again.')) from None
|
||||
if 'integrity' in detail or 'intact image' in detail:
|
||||
raise RegistryError(translate('Image integrity verification failed. The partial download was discarded; try again.')) from None
|
||||
raise RegistryError(translate('The image could not be downloaded or verified. Check registry and storage access, then try again.')) from None
|
||||
return {'reference': reference, 'archive': str(path), 'digest': digest, 'storage': storage,
|
||||
'size': Path(path).stat().st_size, 'architecture': host_architecture()}
|
||||
|
||||
|
||||
def registry_accounts_menu(ui, engine=ENGINE_ROOT, auth=None):
|
||||
"""Manage private registry accounts and images in ProxMenux."""
|
||||
require_root()
|
||||
engine = Path(engine)
|
||||
if str(engine / 'remote') not in sys.path:
|
||||
sys.path.insert(0, str(engine / 'remote'))
|
||||
auth = auth or RegistryAuth()
|
||||
cancelled = importlib.import_module('proxmenux_oci.ui').UserCancelled
|
||||
title = translate('Registry accounts')
|
||||
while True:
|
||||
# A broken authfile must let the user return to ProxMenux instead of
|
||||
# showing the same error indefinitely before a menu can be displayed.
|
||||
try:
|
||||
rows = auth.accounts()
|
||||
except (RegistryError, OSError, ValueError) as error:
|
||||
ui.message(clean(error, 600), title)
|
||||
return
|
||||
try:
|
||||
options = [('add', translate('Sign in to a registry'))]
|
||||
options += [(f'account-{index}', f"{row['registry']:<28} {row['account'] or row['method']} [{translate('saved')}]")
|
||||
for index, row in enumerate(rows)]
|
||||
options += [('storage', translate('Credential storage and access'))]
|
||||
count = translate('{count} saved account.') if len(rows) == 1 else translate('{count} saved accounts.')
|
||||
choice = ui.choose(translate('Manage private image registries.\n'
|
||||
'Saved credentials let ProxMenux access your private images.')
|
||||
+ '\n\n' + count.format(count=len(rows)),
|
||||
options, 'account-0' if rows else 'add', title=title, show_tags=False)
|
||||
if choice is None:
|
||||
return
|
||||
row = None
|
||||
if choice.startswith('account-'):
|
||||
try:
|
||||
row = rows[int(choice.partition('-')[2])]
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
choice = ui.choose(translate('Registry: {registry}\nAccount: {account}\n'
|
||||
'Authentication: {method}\n\n'
|
||||
'Saved credentials are verified when an image is accessed.').format(
|
||||
registry=row['registry'], account=row['account'] or translate('Credential helper'),
|
||||
method=row['method']),
|
||||
[('inspect', translate('Check access to an image')),
|
||||
('download', translate('Download an image to template storage')),
|
||||
('install', translate('Install an image as a native LXC')),
|
||||
('login', translate('Update credentials')),
|
||||
('logout', translate('Remove saved credentials'))], 'inspect', title=title, show_tags=False)
|
||||
if choice is None:
|
||||
continue
|
||||
if choice == 'storage':
|
||||
ui.message(translate('Credentials file:\n{path}\n\n'
|
||||
'Owned by root; directory mode 700 and file mode 600.\n'
|
||||
'Basic credentials are base64 encoded, not encrypted.\n'
|
||||
'Credential helpers use their own storage.\n\n'
|
||||
'Use an access token with permission to pull images.\n'
|
||||
'Every node of the cluster uses the accounts saved here.').format(path=auth.path), title)
|
||||
elif choice in {'add', 'login'}:
|
||||
registry = row['registry'].split('/', 1)[0] if row else ui.ask(translate('Registry hostname'), 'ghcr.io')
|
||||
try:
|
||||
registry = validate_registry(registry)
|
||||
except RegistryError as error:
|
||||
raise RegistryError(str(error)) from None
|
||||
username = ui.ask(translate('Username'), row['account'] if row else None)
|
||||
password = ui.password(translate('Password / access token (image pull permission)'))
|
||||
ui.info(translate('Verifying registry access. Please wait...'))
|
||||
auth.login(registry, username, password)
|
||||
del password
|
||||
ui.message(translate('Signed in to {registry} as {username}.\n\n'
|
||||
'Credentials are saved for ProxMenux.\n'
|
||||
'Select the account to check, download or install an image.').format(
|
||||
registry=registry, username=clean(username)), title)
|
||||
elif choice == 'logout' and row:
|
||||
registry = row['registry'].split('/', 1)[0]
|
||||
if ui.confirm(translate('Remove the saved credentials for {registry}?\nRunning apps will keep working.').format(registry=registry),
|
||||
False, title=title):
|
||||
auth.logout(registry)
|
||||
ui.message(translate('Saved credentials for {registry} were removed.\n'
|
||||
'Other Skopeo/Docker credential files are managed separately.').format(registry=registry), title)
|
||||
elif choice in {'inspect', 'download', 'install'} and row:
|
||||
registry = row['registry'].split('/', 1)[0]
|
||||
owner = row['account'] or 'owner'
|
||||
reference = validate_image(ui.ask(translate('Image reference'), f'{registry}/{owner}/app:latest'))
|
||||
if registry_of(reference) != registry:
|
||||
raise RegistryError(translate('This account is for {registry}. Enter an image from that registry.').format(registry=registry))
|
||||
if choice == 'inspect':
|
||||
ui.info(translate('Checking image access and metadata. Please wait...'))
|
||||
result = inspect_registry_image(reference)
|
||||
ui.message(translate('Image access confirmed.\n\n{reference}\n\n'
|
||||
'Architecture: {architecture}\nVersion: {version}\n'
|
||||
'Download size: {size}\nDigest: {digest}').format(
|
||||
reference=reference, architecture=result['architecture'],
|
||||
version=result['version'] or translate('Not declared'),
|
||||
size=bytes_label(result['size']), digest=result['digest']), title)
|
||||
elif choice == 'download':
|
||||
host = importlib.import_module('proxmenux_oci.host')
|
||||
storages = host.storages('vztmpl')
|
||||
if not storages:
|
||||
raise RegistryError(translate('No active Proxmox storage accepts OCI template archives.'))
|
||||
names = [item['storage'] for item in storages]
|
||||
storage = ui.choose(translate('Choose storage for the downloaded image.'),
|
||||
[(item['storage'], f"{item['storage']} ({bytes_label(item.get('avail', 0))} {translate('available')})")
|
||||
for item in storages], 'local' if 'local' in names else names[0], title=title)
|
||||
if storage is None:
|
||||
continue
|
||||
ui.info(translate('Downloading and verifying the image.\nThis can take a few minutes. Please wait...'))
|
||||
result = download_registry_image(reference, storage)
|
||||
ui.message(translate('Image downloaded and verified.\n\n{reference}\n\n'
|
||||
'Storage: {storage}\nArchive size: {size}\n'
|
||||
'Archive: {archive}\n\nNo container was created.\n'
|
||||
'ProxMenux removes unused cached images after successful updates.').format(
|
||||
reference=reference, storage=storage, size=bytes_label(result['size']),
|
||||
archive=result['archive']), title)
|
||||
else:
|
||||
ui.info(translate('Reading image metadata. Please wait...'))
|
||||
with registry_environment():
|
||||
template = image_template(reference)
|
||||
if not template.get('compatibility', {}).get('automatic_install_candidate'):
|
||||
raise RegistryError(translate('ProxMenux cannot install this image automatically. Import its Compose file instead.'))
|
||||
installer = importlib.import_module('proxmenux_oci.installer')
|
||||
native_cli = importlib.import_module('proxmenux_oci.cli')
|
||||
mode = ui.choose(translate('Installation settings'), [(installer.DEFAULT_MODE, translate('Default settings')),
|
||||
(installer.ADVANCED_MODE, translate('Advanced settings'))], installer.DEFAULT_MODE, title=title)
|
||||
if mode is not None:
|
||||
native_cli.install_template(ui, template, template['id'], mode)
|
||||
except cancelled:
|
||||
continue
|
||||
except (RegistryError, OSError, ValueError) as error:
|
||||
ui.message(clean(error, 600), title)
|
||||
|
||||
|
||||
def open_registry_accounts(ui):
|
||||
try:
|
||||
registry_accounts_menu(ui)
|
||||
except (RegistryError, OSError, ValueError) as error:
|
||||
ui.message(clean(error, 600), translate('Registry accounts'))
|
||||
|
||||
|
||||
def offer_sign_in(ui, reference, title=None):
|
||||
"""When a registry refuses an image, an account for it can be added on the
|
||||
spot; the image is then read again with it."""
|
||||
try:
|
||||
registry = validate_registry(registry_of(reference))
|
||||
except RegistryError:
|
||||
return False
|
||||
question = translate('{registry} refused access to this image:\n{reference}\n\n'
|
||||
'If the image is private, sign in with an account that can pull it.\n\n'
|
||||
'Sign in now?').format(registry=registry, reference=clean(reference, 300))
|
||||
if not ui.confirm(question, True, title=title):
|
||||
return False
|
||||
cancelled = importlib.import_module('proxmenux_oci.ui').UserCancelled
|
||||
try:
|
||||
require_root()
|
||||
username = ui.ask(translate('Username'))
|
||||
password = ui.password(translate('Password / access token (image pull permission)'))
|
||||
ui.info(translate('Verifying registry access. Please wait...'))
|
||||
RegistryAuth().login(registry, username, password)
|
||||
del password
|
||||
except cancelled:
|
||||
return False
|
||||
except (RegistryError, OSError, ValueError) as error:
|
||||
ui.message(clean(error, 600), title)
|
||||
return False
|
||||
return True
|
||||
@@ -0,0 +1,351 @@
|
||||
# ==========================================================
|
||||
# ProxMenux - Private OCI registry accounts
|
||||
# ==========================================================
|
||||
# Author : Jonatan
|
||||
# GitHub : github.com/jcastro
|
||||
# Maintainer : MacRimi
|
||||
# Copyright : (c) 2026 MacRimi & contributors
|
||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
||||
# Version : 1.0
|
||||
# Last Updated: 16/10/2026
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# Manage persistent Skopeo credentials for private registries.
|
||||
# Validate accounts without exposing tokens and preserve saved
|
||||
# file credentials when authentication fails.
|
||||
# ==========================================================
|
||||
|
||||
"""Persistent Skopeo authentication for private ProxMenux OCI images."""
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
from contextlib import contextmanager
|
||||
import fcntl
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import stat
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from .i18n import translate
|
||||
|
||||
ANSI = re.compile(r'\x1b\][^\x07]*(?:\x07|\x1b\\)|\x1b\[[0-?]*[ -/]*[@-~]')
|
||||
# Where Proxmox keeps its own storage passwords: readable only by root and
|
||||
# shared by every node of the cluster.
|
||||
CLUSTER_AUTH_FILE = Path('/etc/pve/priv/proxmenux/registry-auth.json')
|
||||
ACCESS_REFUSED = ('unauthorized', 'authentication required', 'denied', 'forbidden', 'invalid username',
|
||||
'invalid password', 'invalid credentials', 'username/password',
|
||||
'statuscode: 401', 'statuscode: 403', 'status code from registry 401',
|
||||
'status code from registry 403')
|
||||
|
||||
|
||||
class RegistryError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def clean(value, limit=180):
|
||||
text = ANSI.sub('', str(value or ''))
|
||||
return ''.join(c for c in text if ord(c) >= 32 and ord(c) != 127)[:limit]
|
||||
|
||||
|
||||
def image_repository(reference):
|
||||
repository = reference.split('@', 1)[0]
|
||||
if ':' in repository.rsplit('/', 1)[-1]:
|
||||
repository = repository.rsplit(':', 1)[0]
|
||||
return repository
|
||||
|
||||
|
||||
def require_root():
|
||||
if os.geteuid() != 0:
|
||||
raise RegistryError(translate('Manage registry accounts as root on the Proxmox node.'))
|
||||
|
||||
|
||||
def validate_registry(value):
|
||||
"""Accept a registry authority, never a URL, image path or credentials."""
|
||||
value = str(value).strip().lower()
|
||||
invalid = translate('Use a registry hostname, for example ghcr.io or registry.example.com:5000.')
|
||||
if not value or len(value) > 260 or any(c in value for c in '/@?#\\'):
|
||||
raise RegistryError(invalid)
|
||||
if value.startswith('['):
|
||||
match = re.fullmatch(r'\[([^]]+)\](?::([0-9]+))?', value)
|
||||
try:
|
||||
if not match or ipaddress.ip_address(match[1]).version != 6:
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
raise RegistryError(invalid) from None
|
||||
port = match[2]
|
||||
else:
|
||||
match = re.fullmatch(r'([a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::([0-9]+))?', value)
|
||||
if not match or any(not re.fullmatch(r'[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?', part)
|
||||
for part in match[1].split('.')):
|
||||
raise RegistryError(invalid)
|
||||
port = match[2]
|
||||
if port and not 1 <= int(port) <= 65535:
|
||||
raise RegistryError(invalid)
|
||||
return {'index.docker.io': 'docker.io', 'registry-1.docker.io': 'docker.io'}.get(value, value)
|
||||
|
||||
|
||||
def credential_key(value):
|
||||
"""Compare existing Docker aliases without exposing credential contents."""
|
||||
value = str(value).removeprefix('https://').removeprefix('http://').rstrip('/')
|
||||
return {'index.docker.io/v1': 'docker.io', 'index.docker.io': 'docker.io',
|
||||
'registry-1.docker.io': 'docker.io'}.get(value, value)
|
||||
|
||||
|
||||
def registry_of(reference):
|
||||
first = image_repository(reference).split('/', 1)[0]
|
||||
if '/' in reference and ('.' in first or ':' in first or first == 'localhost'):
|
||||
return first
|
||||
return 'docker.io'
|
||||
|
||||
|
||||
def validate_image(value):
|
||||
"""Validate before the native importer, including registry ports and IPv6."""
|
||||
invalid = translate('Use an image reference, for example ghcr.io/owner/app:latest.')
|
||||
if not value or len(value) > 512 or any(c.isspace() or ord(c) < 32 for c in value):
|
||||
raise RegistryError(invalid)
|
||||
name, separator, digest = value.partition('@')
|
||||
if separator and not re.fullmatch(r'sha256:[a-f0-9]{64}', digest):
|
||||
raise RegistryError(translate('Only a full sha256 image digest is supported.'))
|
||||
last = name.rsplit('/', 1)[-1]
|
||||
if ':' in last:
|
||||
name, tag = name.rsplit(':', 1)
|
||||
if not re.fullmatch(r'[A-Za-z0-9_][A-Za-z0-9._-]{0,127}', tag):
|
||||
raise RegistryError(translate('Invalid image tag.'))
|
||||
parts = name.split('/')
|
||||
if len(parts) > 1 and ('.' in parts[0] or ':' in parts[0] or parts[0] == 'localhost'):
|
||||
try:
|
||||
validate_registry(parts.pop(0))
|
||||
except RegistryError:
|
||||
raise RegistryError(invalid) from None
|
||||
component = r'[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*'
|
||||
if not parts or len(name) > 255 or any(not re.fullmatch(component, part) for part in parts):
|
||||
raise RegistryError(invalid)
|
||||
return value
|
||||
|
||||
|
||||
def use_cluster_auth_file(environment=os.environ):
|
||||
"""ProxMenux keeps its registry accounts in the cluster filesystem, so
|
||||
every node installs and updates private images with them."""
|
||||
if not environment.get('REGISTRY_AUTH_FILE') and os.path.ismount(CLUSTER_AUTH_FILE.parents[2]):
|
||||
environment['REGISTRY_AUTH_FILE'] = str(CLUSTER_AUTH_FILE)
|
||||
|
||||
|
||||
def refuses_access(error) -> bool:
|
||||
"""Whether a registry error says the image needs an account."""
|
||||
detail = str(error).casefold()
|
||||
return any(word in detail for word in ACCESS_REFUSED)
|
||||
|
||||
|
||||
def registry_error(registry, error='', login=False):
|
||||
"""Classify errors without echoing registry-controlled text or a token."""
|
||||
detail = str(error).casefold()
|
||||
if any(word in detail for word in ('credential helper', 'docker-credential-', 'error getting credentials', 'error storing credentials')):
|
||||
return translate('The configured credential helper could not be used. Check its installation and credential store.')
|
||||
if any(word in detail for word in ('too many requests', 'toomanyrequests', 'statuscode: 429', 'status code: 429', 'status: 429')):
|
||||
return translate('{registry} is rate limiting requests. Wait a while and try again.').format(registry=registry)
|
||||
if any(word in detail for word in ('statuscode: 500', 'status code: 500', 'status: 500',
|
||||
'statuscode: 502', 'status code: 502', 'status: 502',
|
||||
'statuscode: 503', 'status code: 503', 'status: 503',
|
||||
'statuscode: 504', 'status code: 504', 'status: 504',
|
||||
'internal server error', 'service unavailable', 'bad gateway')):
|
||||
return translate('{registry} reported a server error. Try again later.').format(registry=registry)
|
||||
if refuses_access(detail):
|
||||
return (translate('Authentication failed for {registry}. Check the account and token permissions.').format(registry=registry) if login else
|
||||
translate('Access denied by {registry}. Check the image name and sign in from Registry accounts.').format(registry=registry))
|
||||
if any(word in detail for word in ('http response to https client',
|
||||
'first record does not look like a tls handshake')):
|
||||
return translate('{registry} answered with plain HTTP. Use a registry with HTTPS; TLS verification remains enabled.').format(registry=registry)
|
||||
if any(word in detail for word in ('x509', 'certificate', 'tls handshake')):
|
||||
return translate('TLS verification failed for {registry}. Install the registry CA in /etc/containers/certs.d/{registry}/ca.crt.').format(registry=registry)
|
||||
if any(word in detail for word in ('no such host', 'connection refused', 'deadline exceeded', 'timeout', 'timed out',
|
||||
'network is unreachable', 'connection reset', 'unexpected eof')):
|
||||
return translate('Could not reach {registry}. Check its address, DNS and network access.').format(registry=registry)
|
||||
if any(word in detail for word in ('manifest unknown', 'name unknown', 'not found', 'statuscode: 404', 'status code: 404')):
|
||||
return (translate('No registry API was found at {registry}. Check the hostname and port.').format(registry=registry) if login else
|
||||
translate('The image or tag was not found on {registry}, or this account cannot access it. Check the reference.').format(registry=registry))
|
||||
if any(word in detail for word in ('invalid manifest', 'invalid character', 'unsupported manifest', 'unsupported schema')):
|
||||
return translate('{registry} returned invalid or unsupported image metadata.').format(registry=registry)
|
||||
return (translate('Could not sign in to {registry}. Check registry access and token permissions.').format(registry=registry) if login else
|
||||
translate('Could not read the image from {registry}. Check the reference and sign in from Registry accounts.').format(registry=registry))
|
||||
|
||||
|
||||
class RegistryAuth:
|
||||
"""Persistent Skopeo credentials for the native ProxMenux menu.
|
||||
|
||||
Only the selected authfile is managed. Login is staged so failed attempts
|
||||
never replace saved file credentials. Skopeo still manages credential helpers.
|
||||
"""
|
||||
def __init__(self, path=None):
|
||||
configured = os.environ.get('REGISTRY_AUTH_FILE')
|
||||
config_home = Path(os.environ.get('XDG_CONFIG_HOME') or Path.home() / '.config')
|
||||
self.path = Path(path if path is not None else configured or config_home / 'containers/auth.json')
|
||||
if not self.path.is_absolute() or '..' in self.path.parts:
|
||||
raise RegistryError(translate('The registry authentication file must have an absolute path.'))
|
||||
|
||||
def _validate_path(self):
|
||||
for path in [self.path, *self.path.parents]:
|
||||
if path.is_symlink():
|
||||
raise RegistryError(translate('The registry authentication path cannot contain symbolic links.'))
|
||||
for path in self.path.parents:
|
||||
if not path.exists():
|
||||
continue
|
||||
info = path.stat()
|
||||
shared_temporary = info.st_uid == 0 and info.st_mode & stat.S_ISVTX
|
||||
if (not stat.S_ISDIR(info.st_mode) or info.st_uid not in {0, os.geteuid()}
|
||||
or info.st_mode & 0o022 and not shared_temporary):
|
||||
raise RegistryError(translate('The registry authentication path has an unsafe parent directory.'))
|
||||
parent = self.path.parent
|
||||
if parent.exists():
|
||||
info = parent.stat()
|
||||
if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o077:
|
||||
raise RegistryError(translate('The registry credential directory must be owned by root with mode 700.'))
|
||||
|
||||
def _read(self):
|
||||
self._validate_path()
|
||||
try:
|
||||
fd = os.open(self.path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
||||
except FileNotFoundError:
|
||||
return {}, None
|
||||
with os.fdopen(fd, 'rb') as source:
|
||||
info = os.fstat(source.fileno())
|
||||
if not stat.S_ISREG(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o077:
|
||||
raise RegistryError(translate('The registry authentication file must be owned by root with mode 600.'))
|
||||
raw = source.read(1024 * 1024 + 1)
|
||||
try:
|
||||
data = json.loads(raw) if len(raw) <= 1024 * 1024 else None
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict) or any(not isinstance(data.get(key, {}), dict) for key in ('auths', 'credHelpers')):
|
||||
raise RegistryError(translate('The registry authentication file is invalid; it was not changed.'))
|
||||
return data, raw
|
||||
|
||||
def accounts(self):
|
||||
data, _ = self._read()
|
||||
rows = {}
|
||||
for key, credential in data.get('auths', {}).items():
|
||||
if not isinstance(credential, dict):
|
||||
continue
|
||||
username = None
|
||||
encoded = credential.get('auth')
|
||||
if isinstance(encoded, str) and len(encoded) < 65536:
|
||||
try:
|
||||
decoded = base64.b64decode(encoded, validate=True).decode('utf-8')
|
||||
if ':' in decoded:
|
||||
username = clean(decoded.split(':', 1)[0], 120)
|
||||
except (ValueError, UnicodeError):
|
||||
pass
|
||||
if encoded or credential.get('identitytoken') or credential.get('registrytoken'):
|
||||
rows[credential_key(key)] = {'registry': clean(credential_key(key), 320), 'account': username,
|
||||
'method': translate('Token') if not encoded else translate('Username / token'), 'status': 'Saved'}
|
||||
for key, helper in data.get('credHelpers', {}).items():
|
||||
rows[credential_key(key)] = {'registry': clean(credential_key(key), 320), 'account': None,
|
||||
'method': translate('Helper:') + ' ' + clean(helper, 80), 'status': 'Configured'}
|
||||
return sorted(rows.values(), key=lambda row: row['registry'])
|
||||
|
||||
@contextmanager
|
||||
def _staged(self):
|
||||
self._validate_path()
|
||||
self.path.parent.mkdir(parents=True, mode=0o700, exist_ok=True)
|
||||
self._validate_path()
|
||||
lock = self.path.with_name('.' + self.path.name + '.proxmenux.lock')
|
||||
fd = os.open(lock, os.O_CREAT | os.O_WRONLY | os.O_NOFOLLOW | os.O_NONBLOCK, 0o600)
|
||||
try:
|
||||
info = os.fstat(fd)
|
||||
if not stat.S_ISREG(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o077:
|
||||
raise RegistryError(translate('Unsafe registry credential lock.'))
|
||||
try:
|
||||
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except BlockingIOError:
|
||||
raise RegistryError(translate('Another registry account operation is running. Try again when it finishes.')) from None
|
||||
data, before = self._read()
|
||||
stage_fd, name = tempfile.mkstemp(prefix='.proxmenux-auth-', dir=self.path.parent)
|
||||
stage = Path(name)
|
||||
try:
|
||||
with os.fdopen(stage_fd, 'wb') as out:
|
||||
out.write(before if before is not None else b'{"auths":{}}\n')
|
||||
yield stage, data
|
||||
self._read_stage(stage)
|
||||
if self._read()[1] != before:
|
||||
raise RegistryError(translate('The credential file changed during this operation. Try again; it was not overwritten.'))
|
||||
stage.chmod(0o600)
|
||||
with stage.open('rb') as saved:
|
||||
os.fsync(saved.fileno())
|
||||
os.replace(stage, self.path)
|
||||
finally:
|
||||
stage.unlink(missing_ok=True)
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
@staticmethod
|
||||
def _read_stage(stage):
|
||||
try:
|
||||
data = json.loads(stage.read_text())
|
||||
if not isinstance(data, dict) or any(not isinstance(data.get(k, {}), dict) for k in ('auths', 'credHelpers')):
|
||||
raise ValueError()
|
||||
return data
|
||||
except (OSError, ValueError):
|
||||
raise RegistryError(translate('Skopeo returned an invalid credential file; saved credentials were not changed.')) from None
|
||||
|
||||
def login(self, registry, username, password, timeout=45):
|
||||
registry = validate_registry(registry)
|
||||
if not username or not username.strip() or len(username) > 512 or any(ord(c) < 32 or ord(c) == 127 or c == ':' for c in username):
|
||||
raise RegistryError(translate('Enter a valid registry username.'))
|
||||
if not password or len(password) > 65536 or any(c in password for c in '\r\n\0'):
|
||||
raise RegistryError(translate('Enter a non-empty password or access token on a single line.'))
|
||||
with self._staged() as (stage, _):
|
||||
try:
|
||||
process = subprocess.run(['skopeo', 'login', '--authfile', str(stage), '--username', username,
|
||||
'--password-stdin', registry], input=password + '\n', text=True,
|
||||
capture_output=True, timeout=timeout)
|
||||
except subprocess.TimeoutExpired:
|
||||
raise RegistryError(translate('Login to {registry} timed out. Saved credentials were not changed.').format(registry=registry)) from None
|
||||
except FileNotFoundError:
|
||||
raise RegistryError(translate('Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.')) from None
|
||||
if process.returncode:
|
||||
raise RegistryError(registry_error(registry, process.stderr, login=True))
|
||||
|
||||
def logout(self, registry):
|
||||
registry = validate_registry(registry)
|
||||
data, _ = self._read()
|
||||
matches = lambda key: credential_key(key).split('/', 1)[0] == registry
|
||||
if not any(matches(key) for group in ('auths', 'credHelpers') for key in data.get(group, {})):
|
||||
return False
|
||||
with self._staged() as (stage, data):
|
||||
# Skopeo logs out the authority itself; entries scoped to a
|
||||
# repository are also removed from this managed authfile below.
|
||||
if any(credential_key(key) == registry for group in ('auths', 'credHelpers') for key in data.get(group, {})):
|
||||
try:
|
||||
process = subprocess.run(['skopeo', 'logout', '--authfile', str(stage), registry],
|
||||
capture_output=True, text=True, timeout=30)
|
||||
except subprocess.TimeoutExpired:
|
||||
raise RegistryError(translate('Logout from {registry} timed out. Saved file credentials were not changed.').format(registry=registry)) from None
|
||||
except FileNotFoundError:
|
||||
raise RegistryError(translate('Skopeo is not available. Restore the ProxMenux OCI dependencies and try again.')) from None
|
||||
if process.returncode:
|
||||
raise RegistryError(translate('Could not remove credentials for {registry}; saved file credentials were not changed.').format(registry=registry))
|
||||
data = self._read_stage(stage)
|
||||
for group in ('auths', 'credHelpers'):
|
||||
data[group] = {key: value for key, value in data.get(group, {}).items() if not matches(key)}
|
||||
stage.write_text(json.dumps(data))
|
||||
return True
|
||||
|
||||
|
||||
@contextmanager
|
||||
def registry_environment():
|
||||
"""Use durable credentials for every descendant, including update probes."""
|
||||
previous = os.environ.get('REGISTRY_AUTH_FILE')
|
||||
auth = RegistryAuth()
|
||||
if auth.path.exists():
|
||||
auth._read()
|
||||
os.environ['REGISTRY_AUTH_FILE'] = str(auth.path)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if previous is None:
|
||||
os.environ.pop('REGISTRY_AUTH_FILE', None)
|
||||
else:
|
||||
os.environ['REGISTRY_AUTH_FILE'] = previous
|
||||
@@ -0,0 +1,168 @@
|
||||
import contextlib
|
||||
import io
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from types import SimpleNamespace
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT / "remote"))
|
||||
from proxmenux_oci import registry_accounts as accounts
|
||||
|
||||
|
||||
class Cancelled(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class UI:
|
||||
def __init__(self, choices, answers=(), password='MENU_TEST_TOKEN'):
|
||||
self.choices = iter(choices)
|
||||
self.answers = iter(answers)
|
||||
self.password_value = password
|
||||
self.seen = []
|
||||
|
||||
def choose(self, text, options, default=None, **kwargs):
|
||||
self.seen.append((text, options, kwargs))
|
||||
return next(self.choices)
|
||||
|
||||
def ask(self, text, default=None):
|
||||
self.seen.append(text)
|
||||
return next(self.answers)
|
||||
|
||||
def password(self, text):
|
||||
self.seen.append(text)
|
||||
if isinstance(self.password_value, Exception):
|
||||
raise self.password_value
|
||||
return self.password_value
|
||||
|
||||
def message(self, text, title=None):
|
||||
self.seen.append((title, text))
|
||||
|
||||
def info(self, text, title=None):
|
||||
self.seen.append((title, text))
|
||||
|
||||
def confirm(self, text, default=False, **kwargs):
|
||||
self.seen.append(text)
|
||||
return False
|
||||
|
||||
|
||||
class RegistryMenuTests(unittest.TestCase):
|
||||
def run_menu(self, ui, auth, extra_modules=None):
|
||||
modules = {'proxmenux_oci.ui': SimpleNamespace(UserCancelled=Cancelled),
|
||||
'proxmenux_oci.host': SimpleNamespace(storages=lambda content: [{'storage': 'local', 'avail': 10**9}])}
|
||||
modules.update(extra_modules or {})
|
||||
with patch.object(accounts, 'require_root'), patch.object(accounts.importlib, 'import_module', side_effect=lambda name: modules[name]):
|
||||
accounts.registry_accounts_menu(ui, engine='/fake/engine', auth=auth)
|
||||
|
||||
def account(self):
|
||||
return {'registry': 'ghcr.io', 'account': 'example', 'method': 'Username / token', 'status': 'Saved'}
|
||||
|
||||
def auth(self, rows=None):
|
||||
return SimpleNamespace(accounts=MagicMock(return_value=rows or []), login=MagicMock(), logout=MagicMock())
|
||||
|
||||
def test_native_menu_can_add_an_account_without_exposing_the_token(self):
|
||||
auth = self.auth()
|
||||
ui = UI(['add', None], ['ghcr.io', 'example'])
|
||||
self.run_menu(ui, auth)
|
||||
auth.login.assert_called_once_with('ghcr.io', 'example', 'MENU_TEST_TOKEN')
|
||||
self.assertNotIn('MENU_TEST_TOKEN', repr(ui.seen))
|
||||
|
||||
def test_cancelled_password_does_not_change_credentials(self):
|
||||
auth = self.auth()
|
||||
ui = UI(['add', None], ['ghcr.io', 'example'], password=Cancelled())
|
||||
self.run_menu(ui, auth)
|
||||
auth.login.assert_not_called()
|
||||
|
||||
def test_invalid_authority_cannot_reach_login(self):
|
||||
auth = self.auth()
|
||||
ui = UI(['add', None], ['https://ghcr.io'])
|
||||
self.run_menu(ui, auth)
|
||||
auth.login.assert_not_called()
|
||||
self.assertIn('registry hostname', repr(ui.seen))
|
||||
|
||||
def test_account_can_download_through_the_shared_native_cache_helper(self):
|
||||
auth = self.auth([self.account()])
|
||||
ui = UI(['account-0', 'download', 'local', None], ['ghcr.io/example/private:latest'])
|
||||
result = {'archive': '/cache/proxmenux-update-amd64-fixture.tar', 'size': 1024}
|
||||
with patch.object(accounts, 'download_registry_image', return_value=result) as download:
|
||||
self.run_menu(ui, auth)
|
||||
download.assert_called_once_with('ghcr.io/example/private:latest', 'local')
|
||||
self.assertIn('Image downloaded and verified', repr(ui.seen))
|
||||
|
||||
def test_selected_account_does_not_pull_from_another_registry(self):
|
||||
auth = self.auth([self.account()])
|
||||
ui = UI(['account-0', 'download', None], ['quay.io/example/private:latest'])
|
||||
with patch.object(accounts, 'download_registry_image') as download:
|
||||
self.run_menu(ui, auth)
|
||||
download.assert_not_called()
|
||||
|
||||
def test_logout_requires_confirmation_in_the_menu(self):
|
||||
auth = self.auth([self.account()])
|
||||
ui = UI(['account-0', 'logout', None])
|
||||
self.run_menu(ui, auth)
|
||||
auth.logout.assert_not_called()
|
||||
|
||||
def test_menu_offers_install_download_and_credential_management(self):
|
||||
auth = self.auth([self.account()])
|
||||
ui = UI(['account-0', None, None])
|
||||
self.run_menu(ui, auth)
|
||||
actions = ui.seen[1][1]
|
||||
self.assertEqual([tag for tag, label in actions], ['inspect', 'download', 'install', 'login', 'logout'])
|
||||
|
||||
def test_menu_preserves_the_configured_language_when_an_operation_fails(self):
|
||||
from proxmenux_oci import i18n
|
||||
cache = {'Saved': 'Guardado'}
|
||||
with patch.object(i18n, '_language', 'es'), patch.object(i18n, '_cache', cache), \
|
||||
patch.object(accounts, 'registry_accounts_menu', side_effect=RuntimeError('test')):
|
||||
with self.assertRaises(RuntimeError):
|
||||
accounts.open_registry_accounts(UI([]))
|
||||
self.assertEqual(i18n._language, 'es')
|
||||
self.assertIs(i18n._cache, cache)
|
||||
|
||||
def test_native_main_menu_dispatches_to_registry_accounts(self):
|
||||
from proxmenux_oci import cli
|
||||
catalog = SimpleNamespace(index_path=SimpleNamespace(exists=lambda: True),
|
||||
load_index=lambda: {'applications': []})
|
||||
ui = UI(['registries', None])
|
||||
with patch.object(cli, 'interactive_ui', return_value=ui), \
|
||||
patch.object(accounts, 'open_registry_accounts') as open_accounts:
|
||||
self.assertEqual(cli.interactive(catalog), 0)
|
||||
open_accounts.assert_called_once_with(ui)
|
||||
|
||||
def test_terminal_fallback_can_sign_in_without_exposing_the_password(self):
|
||||
from proxmenux_oci.ui import TerminalUI
|
||||
auth = self.auth()
|
||||
output = io.StringIO()
|
||||
with patch.object(accounts, 'require_root'), \
|
||||
patch('builtins.input', side_effect=['1', 'registry.test', 'example', '0']), \
|
||||
patch('getpass.getpass', return_value='MENU_TEST_TOKEN'), \
|
||||
contextlib.redirect_stdout(output):
|
||||
accounts.registry_accounts_menu(TerminalUI(), auth=auth)
|
||||
auth.login.assert_called_once_with('registry.test', 'example', 'MENU_TEST_TOKEN')
|
||||
self.assertIn('Signed in to registry.test', output.getvalue())
|
||||
self.assertNotIn('MENU_TEST_TOKEN', output.getvalue())
|
||||
|
||||
def test_startup_configuration_errors_return_a_message_to_the_main_menu(self):
|
||||
from proxmenux_oci.registry_auth import RegistryError
|
||||
ui = UI([])
|
||||
with patch.object(accounts, 'registry_accounts_menu', side_effect=RegistryError('Invalid auth path')):
|
||||
accounts.open_registry_accounts(ui)
|
||||
self.assertIn('Invalid auth path', repr(ui.seen))
|
||||
|
||||
def test_private_image_install_uses_the_existing_native_lxc_wizard(self):
|
||||
auth = self.auth([self.account()])
|
||||
ui = UI(['account-0', 'install', 'default', None], ['ghcr.io/example/private:latest'])
|
||||
template = {'id': 'private-app', 'compatibility': {'automatic_install_candidate': True}}
|
||||
install = MagicMock()
|
||||
modules = {'proxmenux_oci.installer': SimpleNamespace(DEFAULT_MODE='default', ADVANCED_MODE='advanced'),
|
||||
'proxmenux_oci.cli': SimpleNamespace(install_template=install)}
|
||||
with patch.object(accounts, 'image_template', return_value=template), \
|
||||
patch.object(accounts, 'registry_environment', contextlib.nullcontext):
|
||||
self.run_menu(ui, auth, modules)
|
||||
install.assert_called_once_with(ui, template, 'private-app', 'default')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,224 @@
|
||||
import base64
|
||||
import contextlib
|
||||
import errno
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from types import SimpleNamespace
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT / "remote"))
|
||||
from proxmenux_oci import registry_auth as auth_module
|
||||
|
||||
|
||||
class AuthenticationTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.directory = Path(self.temp.name).resolve() / 'containers'
|
||||
self.directory.mkdir(mode=0o700)
|
||||
self.path = self.directory / 'auth.json'
|
||||
self.auth = auth_module.RegistryAuth(self.path)
|
||||
self.token = 'TEST_TOKEN_MUST_NEVER_APPEAR_IN_OUTPUT'
|
||||
self.output = io.StringIO()
|
||||
|
||||
def save(self, registry='ghcr.io', username='example', token='old-token'):
|
||||
data = {'auths': {registry: {'auth': base64.b64encode(f'{username}:{token}'.encode()).decode()}}}
|
||||
self.path.write_text(json.dumps(data))
|
||||
self.path.chmod(0o600)
|
||||
return data
|
||||
|
||||
def skopeo_login(self, argv, **kwargs):
|
||||
self.assertEqual(argv[:2], ['skopeo', 'login'])
|
||||
self.assertNotIn(self.token, ' '.join(argv))
|
||||
self.assertNotIn('env', kwargs)
|
||||
self.assertEqual(kwargs['input'], self.token + '\n')
|
||||
stage = Path(argv[argv.index('--authfile') + 1])
|
||||
self.assertEqual(stage.stat().st_mode & 0o777, 0o600)
|
||||
data = json.loads(stage.read_text())
|
||||
data.setdefault('auths', {})[argv[-1]] = {'auth': base64.b64encode(f'new-user:{self.token}'.encode()).decode()}
|
||||
stage.write_text(json.dumps(data))
|
||||
return SimpleNamespace(returncode=0, stderr='', stdout='Login Succeeded!')
|
||||
|
||||
def test_login_is_atomic_private_and_preserves_other_accounts(self):
|
||||
original = self.save('docker.io')
|
||||
with patch.object(auth_module.subprocess, 'run', side_effect=self.skopeo_login):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
data = json.loads(self.path.read_text())
|
||||
self.assertEqual(data['auths']['docker.io'], original['auths']['docker.io'])
|
||||
self.assertIn('ghcr.io', data['auths'])
|
||||
self.assertEqual(self.path.stat().st_mode & 0o777, 0o600)
|
||||
self.assertEqual(list(self.directory.glob('.proxmenux-auth-*')), [])
|
||||
|
||||
def test_failed_login_retains_previous_file_and_never_echoes_registry_error(self):
|
||||
self.save()
|
||||
before = self.path.read_bytes()
|
||||
result = SimpleNamespace(returncode=1, stderr='unauthorized: ' + self.token)
|
||||
with patch.object(auth_module.subprocess, 'run', return_value=result), self.assertRaises(auth_module.RegistryError) as error:
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
self.assertIn('Authentication failed', str(error.exception))
|
||||
self.assertNotIn(self.token, str(error.exception))
|
||||
self.assertEqual(self.path.read_bytes(), before)
|
||||
self.assertEqual(list(self.directory.glob('.proxmenux-auth-*')), [])
|
||||
|
||||
def test_timed_out_login_does_not_create_a_credential_file(self):
|
||||
with patch.object(auth_module.subprocess, 'run', side_effect=subprocess.TimeoutExpired('skopeo', 5)), \
|
||||
self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token, 5)
|
||||
self.assertFalse(self.path.exists())
|
||||
|
||||
def test_external_credential_edit_is_not_overwritten(self):
|
||||
self.save()
|
||||
def concurrent_edit(argv, **kwargs):
|
||||
result = self.skopeo_login(argv, **kwargs)
|
||||
self.save('quay.io', 'other-task')
|
||||
return result
|
||||
with patch.object(auth_module.subprocess, 'run', side_effect=concurrent_edit), self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
self.assertEqual(set(json.loads(self.path.read_text())['auths']), {'quay.io'})
|
||||
|
||||
def test_empty_listing_does_not_create_paths(self):
|
||||
path = self.directory / 'new' / 'auth.json'
|
||||
auth = auth_module.RegistryAuth(path)
|
||||
self.assertEqual(auth.accounts(), [])
|
||||
self.assertFalse(path.parent.exists())
|
||||
|
||||
def test_logout_preserves_unrelated_accounts(self):
|
||||
self.save()
|
||||
data = json.loads(self.path.read_text())
|
||||
data['auths']['docker.io'] = {'auth': base64.b64encode(b'user:other-token').decode()}
|
||||
self.path.write_text(json.dumps(data))
|
||||
def logout(argv, **kwargs):
|
||||
stage = Path(argv[argv.index('--authfile') + 1])
|
||||
saved = json.loads(stage.read_text())
|
||||
saved['auths'].pop('ghcr.io')
|
||||
stage.write_text(json.dumps(saved))
|
||||
return SimpleNamespace(returncode=0)
|
||||
with patch.object(auth_module.subprocess, 'run', side_effect=logout):
|
||||
self.assertTrue(self.auth.logout('ghcr.io'))
|
||||
self.assertEqual(set(json.loads(self.path.read_text())['auths']), {'docker.io'})
|
||||
|
||||
def test_logout_unknown_registry_does_not_modify_file(self):
|
||||
self.save()
|
||||
before = self.path.read_bytes()
|
||||
with patch.object(auth_module.subprocess, 'run') as run:
|
||||
self.assertFalse(self.auth.logout('quay.io'))
|
||||
run.assert_not_called()
|
||||
self.assertEqual(self.path.read_bytes(), before)
|
||||
|
||||
def test_logout_removes_repository_scopes_without_affecting_other_registries(self):
|
||||
self.save('ghcr.io/private/team')
|
||||
with patch.object(auth_module.subprocess, 'run') as run:
|
||||
self.assertTrue(self.auth.logout('ghcr.io'))
|
||||
run.assert_not_called()
|
||||
self.assertFalse(json.loads(self.path.read_text())['auths'])
|
||||
|
||||
def test_symlink_authfile_is_rejected_without_reading_target(self):
|
||||
target = self.directory / 'other'
|
||||
target.write_text('sensitive target')
|
||||
self.path.symlink_to(target)
|
||||
with self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.accounts()
|
||||
self.assertEqual(target.read_text(), 'sensitive target')
|
||||
|
||||
def test_insecure_directory_or_file_permissions_are_rejected(self):
|
||||
self.save()
|
||||
self.path.chmod(0o644)
|
||||
with self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.accounts()
|
||||
self.path.chmod(0o600)
|
||||
self.directory.chmod(0o755)
|
||||
with self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.accounts()
|
||||
|
||||
def test_non_regular_credential_file_cannot_block_the_command(self):
|
||||
os.mkfifo(self.path, mode=0o600)
|
||||
with self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.accounts()
|
||||
|
||||
def test_writable_parent_directory_is_rejected(self):
|
||||
self.directory.parent.chmod(0o777)
|
||||
self.addCleanup(self.directory.parent.chmod, 0o700)
|
||||
with self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.accounts()
|
||||
|
||||
def test_corrupt_file_is_not_overwritten(self):
|
||||
self.path.write_text('{invalid')
|
||||
self.path.chmod(0o600)
|
||||
with patch.object(auth_module.subprocess, 'run') as run, self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
run.assert_not_called()
|
||||
self.assertEqual(self.path.read_text(), '{invalid')
|
||||
|
||||
def test_durable_authfile_is_used_by_descendants_and_environment_is_restored(self):
|
||||
self.save()
|
||||
with patch.dict(os.environ, {'REGISTRY_AUTH_FILE': str(self.path)}):
|
||||
with auth_module.registry_environment():
|
||||
self.assertEqual(os.environ['REGISTRY_AUTH_FILE'], str(self.path))
|
||||
self.assertEqual(os.environ['REGISTRY_AUTH_FILE'], str(self.path))
|
||||
with patch.dict(os.environ, clear=True), patch.object(auth_module.Path, 'home', return_value=self.directory.parent):
|
||||
# Use the normal XDG_CONFIG_HOME fallback without touching /root.
|
||||
os.environ['XDG_CONFIG_HOME'] = str(self.directory.parent)
|
||||
with auth_module.registry_environment():
|
||||
self.assertEqual(os.environ['REGISTRY_AUTH_FILE'], str(self.path))
|
||||
self.assertNotIn('REGISTRY_AUTH_FILE', os.environ)
|
||||
|
||||
def test_account_listing_never_returns_a_password_or_token(self):
|
||||
self.save(token=self.token)
|
||||
with patch.object(auth_module.subprocess, 'run') as run:
|
||||
rows = self.auth.accounts()
|
||||
run.assert_not_called()
|
||||
text = json.dumps(rows)
|
||||
self.assertEqual(rows[0]['account'], 'example')
|
||||
self.assertNotIn(self.token, text)
|
||||
self.assertNotIn(base64.b64encode(f'example:{self.token}'.encode()).decode(), text)
|
||||
|
||||
def test_invalid_staged_credentials_cannot_replace_a_working_account(self):
|
||||
self.save()
|
||||
before = self.path.read_bytes()
|
||||
def corrupt_login(argv, **kwargs):
|
||||
Path(argv[argv.index('--authfile') + 1]).write_text('{invalid')
|
||||
return SimpleNamespace(returncode=0, stderr='')
|
||||
with patch.object(auth_module.subprocess, 'run', side_effect=corrupt_login), \
|
||||
self.assertRaises(auth_module.RegistryError):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
self.assertEqual(self.path.read_bytes(), before)
|
||||
self.assertEqual(list(self.directory.glob('.proxmenux-auth-*')), [])
|
||||
|
||||
def test_credential_commit_failure_preserves_saved_file_and_cleans_staging(self):
|
||||
for failure in (OSError(errno.ENOSPC, 'No space left on device'),
|
||||
PermissionError(errno.EACCES, 'Permission denied')):
|
||||
self.save()
|
||||
before = self.path.read_bytes()
|
||||
with self.subTest(error=type(failure).__name__), \
|
||||
patch.object(auth_module.subprocess, 'run', side_effect=self.skopeo_login), \
|
||||
patch.object(auth_module.os, 'replace', side_effect=failure), \
|
||||
self.assertRaises(OSError):
|
||||
self.auth.login('ghcr.io', 'new-user', self.token)
|
||||
self.assertEqual(self.path.read_bytes(), before)
|
||||
self.assertEqual(list(self.directory.glob('.proxmenux-auth-*')), [])
|
||||
|
||||
def test_failed_or_timed_out_logout_keeps_saved_accounts(self):
|
||||
self.save()
|
||||
before = self.path.read_bytes()
|
||||
for failure in (None, subprocess.TimeoutExpired('skopeo', 30), FileNotFoundError()):
|
||||
response = SimpleNamespace(returncode=1, stderr=self.token)
|
||||
with self.subTest(error=type(failure).__name__), \
|
||||
patch.object(auth_module.subprocess, 'run', side_effect=failure, return_value=response), \
|
||||
self.assertRaises(auth_module.RegistryError) as error:
|
||||
self.auth.logout('ghcr.io')
|
||||
self.assertNotIn(self.token, str(error.exception))
|
||||
self.assertEqual(self.path.read_bytes(), before)
|
||||
self.assertEqual(list(self.directory.glob('.proxmenux-auth-*')), [])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,145 @@
|
||||
"""Registry accounts are kept for the whole cluster, offered when a registry
|
||||
refuses an image, and read by every program that downloads images."""
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from types import SimpleNamespace
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
from proxmenux_oci import custom, registry_accounts, registry_auth
|
||||
from proxmenux_oci.ui import UserCancelled
|
||||
|
||||
CLUSTER_FILE = "/etc/pve/priv/proxmenux/registry-auth.json"
|
||||
GHCR_PRIVATE = ('time="2026-10-16T18:06:24+02:00" level=fatal msg="Error parsing image name '
|
||||
'\\"docker://ghcr.io/macrimi/private-test:latest\\": Requesting bearer token: '
|
||||
'invalid status code from registry 403 (Forbidden)"')
|
||||
HUB_PRIVATE = 'reading manifest latest in docker.io/macrimi/private-test: requested access to the resource is denied'
|
||||
|
||||
|
||||
class FakeUI:
|
||||
def __init__(self, answers=(), confirms=(True,)):
|
||||
self.answers = list(answers)
|
||||
self.confirms = list(confirms)
|
||||
self.messages = []
|
||||
|
||||
def ask(self, text, default=None, required=True):
|
||||
answer = self.answers.pop(0)
|
||||
if answer is UserCancelled:
|
||||
raise UserCancelled(text)
|
||||
return answer
|
||||
|
||||
def password(self, text, required=True):
|
||||
return self.answers.pop(0)
|
||||
|
||||
def confirm(self, text, default=False, title=None):
|
||||
return self.confirms.pop(0)
|
||||
|
||||
def info(self, text, title=None):
|
||||
pass
|
||||
|
||||
def message(self, text, title=None):
|
||||
self.messages.append(text)
|
||||
|
||||
|
||||
class ClusterFile(unittest.TestCase):
|
||||
def test_the_cluster_file_is_used_when_the_cluster_filesystem_is_mounted(self):
|
||||
environment = {}
|
||||
with patch.object(registry_auth.os.path, "ismount", return_value=True):
|
||||
registry_auth.use_cluster_auth_file(environment)
|
||||
self.assertEqual(environment, {"REGISTRY_AUTH_FILE": CLUSTER_FILE})
|
||||
|
||||
def test_nothing_is_chosen_without_the_cluster_filesystem(self):
|
||||
environment = {}
|
||||
with patch.object(registry_auth.os.path, "ismount", return_value=False):
|
||||
registry_auth.use_cluster_auth_file(environment)
|
||||
self.assertEqual(environment, {})
|
||||
|
||||
def test_a_file_chosen_by_the_user_is_kept(self):
|
||||
environment = {"REGISTRY_AUTH_FILE": "/root/own.json"}
|
||||
with patch.object(registry_auth.os.path, "ismount", return_value=True):
|
||||
registry_auth.use_cluster_auth_file(environment)
|
||||
self.assertEqual(environment, {"REGISTRY_AUTH_FILE": "/root/own.json"})
|
||||
|
||||
def test_the_accounts_menu_reads_and_writes_the_cluster_file(self):
|
||||
with patch.dict(registry_auth.os.environ, {"REGISTRY_AUTH_FILE": CLUSTER_FILE}):
|
||||
self.assertEqual(str(registry_auth.RegistryAuth().path), CLUSTER_FILE)
|
||||
|
||||
|
||||
class RefusedAccess(unittest.TestCase):
|
||||
def test_a_refusal_is_told_apart_from_other_failures(self):
|
||||
for text in (GHCR_PRIVATE, HUB_PRIVATE, "unauthorized: authentication required"):
|
||||
self.assertTrue(registry_auth.refuses_access(text), text)
|
||||
for text in ("dial tcp: lookup ghcr.io: no such host", "manifest unknown", ""):
|
||||
self.assertFalse(registry_auth.refuses_access(text), text)
|
||||
|
||||
def test_the_classifier_still_names_the_refusal(self):
|
||||
self.assertIn("Access denied by ghcr.io", registry_auth.registry_error("ghcr.io", GHCR_PRIVATE))
|
||||
|
||||
|
||||
class SignInFromTheImporter(unittest.TestCase):
|
||||
def sign_in(self, ui, login=None):
|
||||
auth = MagicMock()
|
||||
if login:
|
||||
auth.login.side_effect = login
|
||||
with patch.object(registry_accounts, "require_root"), \
|
||||
patch.object(registry_accounts, "RegistryAuth", return_value=auth):
|
||||
result = registry_accounts.offer_sign_in(ui, "ghcr.io/macrimi/app:latest", "Title")
|
||||
return result, auth
|
||||
|
||||
def test_an_accepted_account_is_saved(self):
|
||||
ui = FakeUI(["macrimi", "ghp_secret"])
|
||||
result, auth = self.sign_in(ui)
|
||||
self.assertTrue(result)
|
||||
auth.login.assert_called_once_with("ghcr.io", "macrimi", "ghp_secret")
|
||||
|
||||
def test_a_declined_offer_asks_nothing(self):
|
||||
ui = FakeUI([], confirms=[False])
|
||||
result, auth = self.sign_in(ui)
|
||||
self.assertFalse(result)
|
||||
auth.login.assert_not_called()
|
||||
|
||||
def test_a_cancelled_question_returns_without_signing_in(self):
|
||||
ui = FakeUI([UserCancelled])
|
||||
result, auth = self.sign_in(ui)
|
||||
self.assertFalse(result)
|
||||
auth.login.assert_not_called()
|
||||
|
||||
def test_a_refused_account_is_explained(self):
|
||||
ui = FakeUI(["macrimi", "wrong"])
|
||||
refused = registry_auth.RegistryError("Authentication failed for ghcr.io.")
|
||||
result, _ = self.sign_in(ui, login=refused)
|
||||
self.assertFalse(result)
|
||||
self.assertEqual(ui.messages, ["Authentication failed for ghcr.io."])
|
||||
|
||||
def test_a_refused_image_is_checked_again_after_signing_in(self):
|
||||
compose = "services:\n app:\n image: ghcr.io/macrimi/app:latest\n"
|
||||
reports = iter([(False, "Could not inspect the image in its registry"), (True, "The image is in its registry")])
|
||||
ui = SimpleNamespace(message=lambda *a, **k: None, review=lambda *a, **k: False)
|
||||
with patch.object(custom, "read_definition", return_value=(compose, "pasted Compose file")), \
|
||||
patch.object(custom, "registry_report", side_effect=lambda _: next(reports)) as report, \
|
||||
patch.object(custom, "_registry_refused", return_value=True), \
|
||||
patch.object(registry_accounts, "offer_sign_in", return_value=True) as offer:
|
||||
custom.explore(ui)
|
||||
offer.assert_called_once()
|
||||
self.assertEqual(report.call_count, 2)
|
||||
|
||||
|
||||
class EveryImageReaderUsesTheAccounts(unittest.TestCase):
|
||||
def test_every_program_that_runs_skopeo_reads_the_cluster_file(self):
|
||||
readers = [path for path in sorted((ROOT / "remote").iterdir())
|
||||
if path.suffix in {".sh", ".py"}
|
||||
and re.search(r"skopeo['\",]*\s+(inspect|copy)|'skopeo',\s*'(inspect|copy)'", path.read_text())]
|
||||
self.assertGreaterEqual(len(readers), 7)
|
||||
for path in readers:
|
||||
with self.subTest(path=path.name):
|
||||
self.assertIn(CLUSTER_FILE, path.read_text())
|
||||
self.assertIn("_use_cluster_auth_file()", (ROOT / "src/proxmenux_oci/__init__.py").read_text())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,160 @@
|
||||
from contextlib import nullcontext
|
||||
import errno
|
||||
import io
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from types import SimpleNamespace
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT / "remote"))
|
||||
from proxmenux_oci import registry_auth as auth
|
||||
from proxmenux_oci import registry_accounts as accounts
|
||||
|
||||
|
||||
class FailureHandlingTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.platform = patch.object(accounts, 'host_architecture', return_value='amd64')
|
||||
self.platform.start()
|
||||
self.addCleanup(self.platform.stop)
|
||||
|
||||
def test_transport_errors_are_specific_and_never_echo_server_text(self):
|
||||
cases = [
|
||||
('unauthorized', 'Access denied'), ('denied', 'Access denied'),
|
||||
('manifest unknown', 'image or tag was not found'),
|
||||
('received unexpected HTTP status: 404 Not Found', 'image or tag was not found'),
|
||||
('toomanyrequests', 'rate limiting'), ('StatusCode: 429', 'rate limiting'),
|
||||
('500 Internal Server Error', 'server error'), ('503 Service Unavailable', 'server error'),
|
||||
('x509: certificate has expired', 'TLS verification failed'),
|
||||
('x509: certificate signed by unknown authority', 'TLS verification failed'),
|
||||
('http: server gave HTTP response to HTTPS client', 'plain HTTP'),
|
||||
('tls: first record does not look like a TLS handshake', 'plain HTTP'),
|
||||
('dial: no such host', 'Could not reach'), ('connection refused', 'Could not reach'),
|
||||
('i/o timeout', 'Could not reach'), ('connection reset', 'Could not reach'),
|
||||
('invalid character in manifest', 'invalid or unsupported'),
|
||||
('docker-credential-missing: executable file not found', 'credential helper'),
|
||||
]
|
||||
for error, expected in cases:
|
||||
with self.subTest(error=error):
|
||||
message = auth.registry_error('registry.test', error + ' SECRET_TOKEN\x1b[31m')
|
||||
self.assertIn(expected, message)
|
||||
self.assertNotIn('SECRET_TOKEN', message)
|
||||
self.assertNotIn('\x1b', message)
|
||||
|
||||
def test_bad_login_credentials_have_a_specific_safe_error(self):
|
||||
for error in ('invalid username/password', 'invalid username', 'invalid password',
|
||||
'invalid credentials', 'unauthorized',
|
||||
'Requesting bearer token: invalid status code from registry 403 (Forbidden)'):
|
||||
with self.subTest(error=error):
|
||||
message = auth.registry_error('registry.test', error + ' SECRET_TOKEN', login=True)
|
||||
self.assertIn('Authentication failed', message)
|
||||
self.assertNotIn('SECRET_TOKEN', message)
|
||||
|
||||
def test_corrupt_authfile_does_not_trap_the_user_in_a_message_loop(self):
|
||||
class Cancelled(RuntimeError):
|
||||
pass
|
||||
ui = SimpleNamespace(message=MagicMock(), choose=MagicMock())
|
||||
saved = SimpleNamespace(accounts=MagicMock(side_effect=auth.RegistryError('Invalid auth file')))
|
||||
with patch.object(accounts, 'require_root'), \
|
||||
patch.object(accounts.importlib, 'import_module', return_value=SimpleNamespace(UserCancelled=Cancelled)):
|
||||
accounts.registry_accounts_menu(ui, auth=saved)
|
||||
ui.message.assert_called_once()
|
||||
ui.choose.assert_not_called()
|
||||
|
||||
def images(self):
|
||||
image = SimpleNamespace(command=MagicMock())
|
||||
def resolve(ref, architecture):
|
||||
image.command('skopeo', 'inspect', '--raw', 'docker://' + ref)
|
||||
return {'manifest_digest': 'sha256:' + 'a' * 64, 'size': 10, 'version': '1.0'}
|
||||
image.resolve_candidate = resolve
|
||||
return image
|
||||
|
||||
def test_native_resolver_transport_hook_is_scoped_and_restored(self):
|
||||
image = self.images()
|
||||
original = image.command
|
||||
with patch.object(accounts.importlib, 'import_module', return_value=image), \
|
||||
patch.object(accounts, 'registry_environment', nullcontext), \
|
||||
patch.object(accounts.subprocess, 'run', return_value=SimpleNamespace(returncode=0, stdout=b'{}')):
|
||||
self.assertEqual(accounts.inspect_registry_image('registry.test/team/app:latest')['version'], '1.0')
|
||||
self.assertIs(image.command, original)
|
||||
|
||||
def test_native_resolver_restores_transport_hook_after_access_denied(self):
|
||||
image = self.images()
|
||||
original = image.command
|
||||
response = SimpleNamespace(returncode=1, stderr=b'unauthorized SECRET_TOKEN')
|
||||
with patch.object(accounts.importlib, 'import_module', return_value=image), \
|
||||
patch.object(accounts, 'registry_environment', nullcontext), \
|
||||
patch.object(accounts.subprocess, 'run', return_value=response), \
|
||||
self.assertRaises(auth.RegistryError) as error:
|
||||
accounts.inspect_registry_image('registry.test/team/app:latest')
|
||||
self.assertIn('Access denied', str(error.exception))
|
||||
self.assertNotIn('SECRET_TOKEN', str(error.exception))
|
||||
self.assertIs(image.command, original)
|
||||
|
||||
def test_image_query_timeout_does_not_fall_back_to_a_long_native_timeout(self):
|
||||
image = self.images()
|
||||
with patch.object(accounts.importlib, 'import_module', return_value=image), \
|
||||
patch.object(accounts, 'registry_environment', nullcontext), \
|
||||
patch.object(accounts.subprocess, 'run', side_effect=subprocess.TimeoutExpired('skopeo', 30)), \
|
||||
self.assertRaises(auth.RegistryError) as error:
|
||||
accounts.inspect_registry_image('registry.test/team/app:latest')
|
||||
self.assertIn('within 30 seconds', str(error.exception))
|
||||
|
||||
def test_wrong_architecture_and_malformed_metadata_do_not_recommend_relogin(self):
|
||||
for native_error, expected in [(ValueError('A single matching image platform cannot be resolved'), 'compatible Linux'),
|
||||
(ValueError('Invalid JSON'), 'invalid or unsupported'),
|
||||
(KeyError('config'), 'incomplete or unsupported'),
|
||||
(AttributeError('bad config'), 'incomplete or unsupported')]:
|
||||
image = self.images()
|
||||
image.resolve_candidate = MagicMock(side_effect=native_error)
|
||||
with self.subTest(error=type(native_error).__name__), \
|
||||
patch.object(accounts.importlib, 'import_module', return_value=image), \
|
||||
patch.object(accounts, 'registry_environment', nullcontext), \
|
||||
self.assertRaises(auth.RegistryError) as error:
|
||||
accounts.inspect_registry_image('registry.test/team/app:latest')
|
||||
self.assertIn(expected, str(error.exception))
|
||||
|
||||
def test_storage_failures_have_storage_messages_and_keep_native_lock_scope(self):
|
||||
for failure, expected in [(ValueError('The new image does not fit on the storage'), 'Not enough free space'),
|
||||
(OSError(errno.ENOSPC, 'No space left on device'), 'Not enough free space'),
|
||||
(PermissionError('denied'), 'Cannot write'),
|
||||
(OSError(errno.EROFS, 'Read-only file system'), 'Cannot write'),
|
||||
(ValueError('Unsafe OCI archive path'), 'unsafe'),
|
||||
(RuntimeError('Could not obtain an intact image'), 'integrity verification')]:
|
||||
native = SimpleNamespace(instances=SimpleNamespace(ROOT='/fixture', locked=lambda root: nullcontext()),
|
||||
resolve_archive=MagicMock(side_effect=failure))
|
||||
with self.subTest(error=str(failure)), patch.object(accounts, 'inspect_registry_image'), \
|
||||
patch.object(accounts.importlib, 'import_module', return_value=native), \
|
||||
patch.object(accounts, 'registry_environment', nullcontext), \
|
||||
self.assertRaises(auth.RegistryError) as error:
|
||||
accounts.download_registry_image('registry.test/team/app:latest', 'local')
|
||||
self.assertIn(expected, str(error.exception))
|
||||
|
||||
def test_missing_skopeo_does_not_create_a_saved_account(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
path = Path(temp).resolve() / 'containers/auth.json'
|
||||
manager = auth.RegistryAuth(path)
|
||||
with patch.object(auth.subprocess, 'run', side_effect=FileNotFoundError()), \
|
||||
self.assertRaises(auth.RegistryError) as error:
|
||||
manager.login('registry.test', 'example', 'example-token')
|
||||
self.assertIn('Skopeo is not available', str(error.exception))
|
||||
self.assertFalse(path.exists())
|
||||
|
||||
def test_invalid_usernames_and_multiline_or_empty_tokens_never_reach_skopeo(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
manager = auth.RegistryAuth(Path(temp).resolve() / 'containers/auth.json')
|
||||
for username, token in [('', 'token'), (' ', 'token'), ('user:colon', 'token'),
|
||||
('user\x7f', 'token'), ('name', ''), ('name', 'x\ny'),
|
||||
('name', 'x\0y'), ('name', 'x' * 65537)]:
|
||||
with self.subTest(username=username, token_length=len(token)), \
|
||||
patch.object(auth.subprocess, 'run') as run, self.assertRaises(auth.RegistryError):
|
||||
manager.login('registry.test', username, token)
|
||||
run.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,45 @@
|
||||
from pathlib import Path
|
||||
import json
|
||||
import sys
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
sys.path.insert(0, str(ROOT / "remote"))
|
||||
from proxmenux_oci.registry_auth import RegistryError, validate_registry, validate_image
|
||||
|
||||
|
||||
class ReferenceTests(unittest.TestCase):
|
||||
def test_native_image_importer_preserves_registry_port_and_digest(self):
|
||||
from proxmenux_oci import custom
|
||||
import yaml
|
||||
for reference in ('registry.test:5443/team/app:stable',
|
||||
'[::1]:5443/team/app@sha256:' + 'a' * 64):
|
||||
with self.subTest(reference=reference), \
|
||||
patch.object(custom.subprocess, 'run', return_value=SimpleNamespace(
|
||||
returncode=0, stdout=json.dumps({'config': {}}))) as run:
|
||||
compose = yaml.safe_load(custom.compose_from_image(reference))
|
||||
self.assertEqual(next(iter(compose['services'].values()))['image'], reference)
|
||||
self.assertEqual(run.call_args.args[0][-1], 'docker://' + reference)
|
||||
|
||||
def test_private_registries_with_ports_and_digest_references_are_valid(self):
|
||||
for reference in ('ghcr.io/team/app:latest', 'registry.local:5000/team/app:stable',
|
||||
'[::1]:5000/team/app:latest', 'ghcr.io/team/app@sha256:' + 'a' * 64):
|
||||
self.assertEqual(validate_image(reference), reference)
|
||||
|
||||
def test_credentials_and_urls_cannot_be_used_as_image_references(self):
|
||||
for reference in ('https://ghcr.io/team/app', 'user:token@ghcr.io/app', 'ghcr.io/app;id',
|
||||
'ghcr.io/../app', 'ghcr.io/app@sha256:short'):
|
||||
with self.assertRaises(RegistryError):
|
||||
validate_image(reference)
|
||||
|
||||
def test_registry_authorities_do_not_accept_image_paths_or_credentials(self):
|
||||
for registry in ('https://ghcr.io', 'ghcr.io/team', 'user:token@ghcr.io', 'host:99999'):
|
||||
with self.assertRaises(RegistryError):
|
||||
validate_registry(registry)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -607,6 +607,22 @@ hb_prepare_staging() {
|
||||
(( jobs_covered )) || paths+=("$HB_BACKUP_JOBS_DIR")
|
||||
fi
|
||||
|
||||
# The logins to private image registries are needed to update the
|
||||
# applications installed from them, whatever the profile selects.
|
||||
local registry_logins=/etc/pve/priv/proxmenux/registry-auth.json
|
||||
if [[ -e "$registry_logins" ]]; then
|
||||
local logins_covered=0 candidate normalized
|
||||
for candidate in "${paths[@]}"; do
|
||||
normalized="${candidate%/}"
|
||||
[[ -z "$normalized" ]] && normalized="/"
|
||||
if [[ "$registry_logins" == "$normalized" || "$registry_logins" == "$normalized"/* ]]; then
|
||||
logins_covered=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
(( logins_covered )) || paths+=("$registry_logins")
|
||||
fi
|
||||
|
||||
rm -rf "$staging_root"
|
||||
mkdir -p "$staging_root/rootfs" "$staging_root/metadata"
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
# 6 post-update restart failed
|
||||
# 7 another ProxMenux update is already running for this CT
|
||||
# 8 started CT could not record its verification handoff identity
|
||||
# 9 scheduled run skipped because the CT was intentionally stopped
|
||||
#
|
||||
# The frontend surfaces exit code + duration in a follow-up POST to
|
||||
# /api/lxc-updates/<vmid>/applied so the notification event fires with
|
||||
@@ -163,6 +164,11 @@ fi
|
||||
# 2) CT must be running for pct exec. Auto-start stopped CTs, then
|
||||
# restore their original stopped state on every exit path.
|
||||
STATE=$(pct status "$VMID" | awk '{print $2}')
|
||||
if [[ "$STATE" != "running" && "${EXECUTION_MODE:-}" == "scheduled" ]]; then
|
||||
[[ -n "${SCHEDULED_STOPPED_MARKER:-}" ]] && printf '%s\n' "$SCHEDULED_STOPPED_MARKER"
|
||||
echo "SKIPPED: CT $VMID is stopped; a scheduled update will not start it."
|
||||
exit 9
|
||||
fi
|
||||
STARTED_BY_PROXMENUX=0
|
||||
OBSERVATION_ATTEMPTED=0
|
||||
capture_before_stop() {
|
||||
|
||||
@@ -82,6 +82,16 @@ remove_monitor_notification_target() {
|
||||
echo " - Notification target removed from Proxmox"
|
||||
}
|
||||
|
||||
# The logins to private image registries go with ProxMenux. /etc/pve is shared
|
||||
# by the cluster, so the other nodes lose them too.
|
||||
remove_registry_logins() {
|
||||
mountpoint -q /etc/pve || return 0
|
||||
[[ -f /etc/pve/priv/proxmenux/registry-auth.json ]] || return 0
|
||||
pmx_record_execution "Remove private registry logins" "rm -f /etc/pve/priv/proxmenux/registry-auth.json"
|
||||
rm -f /etc/pve/priv/proxmenux/registry-auth.json /etc/pve/priv/proxmenux/.registry-auth.json.proxmenux.lock
|
||||
rmdir /etc/pve/priv/proxmenux 2>/dev/null || true
|
||||
}
|
||||
|
||||
uninstall_proxmenux_monitor() {
|
||||
|
||||
# 1. Stop service if it is running
|
||||
@@ -809,6 +819,7 @@ uninstall_proxmenu() {
|
||||
pmx_remove_file "$INSTALL_DIR/$MENU_SCRIPT"
|
||||
pmx_record_execution "Remove ProxMenux application directory" "rm -rf $BASE_DIR"
|
||||
rm -rf "$BASE_DIR"
|
||||
remove_registry_logins
|
||||
|
||||
# Remove selected dependencies
|
||||
if [ -n "$deps_to_remove" ]; then
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
"title": "Create VM System NAS",
|
||||
"menu": "Create VM from template or script",
|
||||
"script": "menus/create_vm_menu.sh",
|
||||
"keywords": "vm virtual nas",
|
||||
"keywords": "vm virtual nas truenas openmediavault omv xigmanas rockstor fygoos fygonas fnos",
|
||||
"argument": "1"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3034,15 +3034,27 @@ register_tool "fastfetch" true "$FUNC_VERSION"
|
||||
|
||||
|
||||
configure_figurine() {
|
||||
local FUNC_VERSION="1.1"
|
||||
local FUNC_VERSION="1.2"
|
||||
pmx_journal_context "configure_figurine" "$FUNC_VERSION"
|
||||
# description: Install Figurine (ASCII-art hostname banner) and wire it into the SSH login flow.
|
||||
msg_info2 "$(translate "Installing and configuring Figurine...")"
|
||||
# `FIGURINE_VERSION` env var allows pinning to a specific release;
|
||||
# default tracks the last tested upstream tag. Audit Tier 6 —
|
||||
# recursos remotos sin pinning de versión.
|
||||
local version="${FIGURINE_VERSION:-2.0.0}"
|
||||
local file="figurine_linux_amd64_v${version}.tar.gz"
|
||||
local version="${FIGURINE_VERSION:-2.1.1}"
|
||||
# Prefer the Debian userspace ABI; the upstream 32-bit ARM build requires ARMv7.
|
||||
local arch
|
||||
arch="$(dpkg --print-architecture 2>/dev/null || uname -m)"
|
||||
case "$arch" in
|
||||
amd64|x86_64) arch="amd64" ;;
|
||||
arm64|aarch64) arch="arm64" ;;
|
||||
armhf|armv7l|armv8l) arch="arm" ;;
|
||||
*)
|
||||
msg_error "$(translate "Unsupported architecture for Figurine:") $arch"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
local file="figurine_linux_${arch}_v${version}.tar.gz"
|
||||
local url="https://github.com/arsham/figurine/releases/download/v${version}/${file}"
|
||||
local temp_dir; temp_dir=$(mktemp -d)
|
||||
local install_dir="/usr/local/bin"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#
|
||||
# Features:
|
||||
# - Auto-detects latest versions for TrueNAS SCALE/CORE, OMV,
|
||||
# XigmaNAS and Rockstor, with safe fallbacks.
|
||||
# XigmaNAS, Rockstor and FygoOS, with safe fallbacks.
|
||||
# - Dispatches Synology DSM to the dedicated loader-based flow.
|
||||
# - Dispatches ZimaOS to its own installer script.
|
||||
# - Runs the Umbrel OS community installer (external script).
|
||||
@@ -179,6 +179,30 @@ function resolve_rockstor_iso() {
|
||||
HN="Rockstor"
|
||||
}
|
||||
|
||||
function resolve_fygoos_iso() {
|
||||
local default_file="fygoos_PE_x86_1.2.0701_2731.iso"
|
||||
local base_url="https://download.liveupdate.fygonas.com/x86_64/trim"
|
||||
local detected_file="" detected_ver=""
|
||||
|
||||
if _has_curl; then
|
||||
detected_file=$(
|
||||
curl -fsSL "https://fygonas.com/download" 2>/dev/null \
|
||||
| grep -Eo 'download\.liveupdate\.fygonas\.com/x86_64/trim/fygoos_PE_x86_[0-9.]+_[0-9]+\.iso' \
|
||||
| sed 's|.*/||' \
|
||||
| _latest_version_from_lines
|
||||
)
|
||||
fi
|
||||
|
||||
[[ -z "$detected_file" ]] && detected_file="$default_file"
|
||||
detected_ver=$(sed -E 's/^fygoos_PE_x86_([0-9.]+)_.*/\1/' <<<"$detected_file")
|
||||
|
||||
ISO_NAME="FygoOS ${detected_ver}"
|
||||
ISO_FILE="$detected_file"
|
||||
ISO_URL="${base_url}/${ISO_FILE}"
|
||||
ISO_PATH="$ISO_DIR/$ISO_FILE"
|
||||
HN="FygoOS"
|
||||
}
|
||||
|
||||
function select_nas_iso() {
|
||||
|
||||
local NAS_OPTIONS=(
|
||||
@@ -189,17 +213,18 @@ function select_nas_iso() {
|
||||
"5" "XigmaNAS VM (FreeBSD based)"
|
||||
"6" "Rockstor VM (openSUSE based)"
|
||||
"7" "ZimaOS VM (Proxmox-zimaos)"
|
||||
"8" "FygoOS VM (Debian based)"
|
||||
"" ""
|
||||
"" "\Z4───────────────── $(translate "Community Scripts") ─────────────────\Zn"
|
||||
"" ""
|
||||
"8" "Umbrel OS VM (Helper-Scripts)"
|
||||
"9" "$(translate "Return to Main Menu")"
|
||||
"9" "Umbrel OS VM (Helper-Scripts)"
|
||||
"10" "$(translate "Return to Main Menu")"
|
||||
)
|
||||
|
||||
local NAS_TYPE
|
||||
NAS_TYPE=$(dialog --colors --backtitle "ProxMenux" \
|
||||
--title "$(translate "NAS Systems")" \
|
||||
--menu "\n$(translate "Select the NAS system to install:")" 20 70 10 \
|
||||
--menu "\n$(translate "Select the NAS system to install:")" 22 70 13 \
|
||||
"${NAS_OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
|
||||
|
||||
@@ -234,6 +259,9 @@ function select_nas_iso() {
|
||||
return 1
|
||||
;;
|
||||
8)
|
||||
resolve_fygoos_iso
|
||||
;;
|
||||
9)
|
||||
HN="Umbrel OS"
|
||||
bash -c "$(wget -qLO - https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/umbrel-os-vm.sh)"
|
||||
echo -e
|
||||
@@ -251,7 +279,7 @@ function select_nas_iso() {
|
||||
return 1
|
||||
;;
|
||||
|
||||
9)
|
||||
10)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -162,6 +162,15 @@ run_case stopped_restore RUN_HELPER=0 UPDATE_COMMAND='update-custom' MOCK_INITIA
|
||||
[[ $(count 'pct start 101') -eq 1 ]] || fail "stopped CT was not started exactly once"
|
||||
[[ $(count 'pct shutdown 101 --timeout 60') -eq 1 ]] || fail "stopped CT state was not restored"
|
||||
|
||||
run_case scheduled_stopped RUN_HELPER=0 UPDATE_COMMAND='update-custom' \
|
||||
EXECUTION_MODE=scheduled SCHEDULED_STOPPED_MARKER='fixture-stopped-marker' MOCK_INITIAL_STATE=stopped
|
||||
[[ $CASE_RC -eq 9 ]] || fail "scheduled_stopped returned $CASE_RC"
|
||||
[[ $(count 'pct start 101') -eq 0 ]] || fail "scheduled update started a stopped CT"
|
||||
[[ $(count 'pct exec') -eq 0 ]] || fail "scheduled update executed inside a stopped CT"
|
||||
[[ $(count CUSTOM_EXEC) -eq 0 ]] || fail "scheduled update ran a custom updater"
|
||||
grep -qF 'fixture-stopped-marker' "$TEST_ROOT/scheduled_stopped.out" \
|
||||
|| fail "scheduled stopped result did not include its marker"
|
||||
|
||||
run_case locked RUN_HELPER=0 UPDATE_COMMAND='update-custom' MOCK_FLOCK_FAIL=1
|
||||
[[ $CASE_RC -eq 7 ]] || fail "locked expected 7, got $CASE_RC"
|
||||
[[ $(count CUSTOM_EXEC) -eq 0 ]] || fail "locked run executed an updater"
|
||||
|
||||
@@ -78,7 +78,7 @@ function walk(node) {
|
||||
if (ts.isVariableDeclaration(node)) {
|
||||
const name = node.name.getText(tree)
|
||||
if (wanted.has(name)) definitions.push(`const ${node.getText(tree)};`)
|
||||
if (["applySchedulePayload", "loadSchedule", "loadBulkUpdate"].includes(name))
|
||||
if (["LEGACY_STOPPED_SCHEDULE_REASONS", "scheduleReasonCodeFromPersisted", "applySchedulePayload", "loadSchedule", "loadBulkUpdate"].includes(name))
|
||||
preferenceDefinitions.push(`const ${node.getText(tree)};`)
|
||||
if (["osUpdateStale", "osUpdateStatusKnown", "hasOsUpdates"].includes(name))
|
||||
status.push(`const ${node.getText(tree)};`)
|
||||
@@ -325,11 +325,11 @@ context.selectedVMRef.current = { vmid: 100 }
|
||||
}
|
||||
for (const name of ["ScheduleEnabled", "ScheduleConfigured", "ScheduleCron", "SchedulePreset",
|
||||
"ScheduleTarget", "ScheduleTargets", "ScheduleReleaseDelayDays", "ApplyBackup", "ApplyBackupStorage",
|
||||
"ApplyRestart", "ScheduleLastRunAt", "ScheduleLastRunStatus", "ScheduleLastRunReason", "ScheduleLastRunLog",
|
||||
"ApplyRestart", "ScheduleLastRunAt", "ScheduleLastRunStatus", "ScheduleLastRunReason", "ScheduleLastRunReasonCode", "ScheduleLastRunLog",
|
||||
"ScheduleLastRunRebootRequired", "ScheduleLastRunRebootPackages", "ExternalCron", "ScheduleError",
|
||||
"ScheduleLoaded", "BulkError", "BulkLoaded", "BulkEditMode", "BulkConfigured", "BulkTargets", "BulkPersistedTargets"])
|
||||
preferenceContext[`set${name}`] = value => { preferenceState[name] = value }
|
||||
assert.equal(preferenceDefinitions.length, 3)
|
||||
assert.equal(preferenceDefinitions.length, 5)
|
||||
const preferences = compile(preferenceDefinitions.join("\n") + `
|
||||
exports.apply = applySchedulePayload; exports.schedule = loadSchedule; exports.bulk = loadBulkUpdate;
|
||||
`, preferenceContext)
|
||||
@@ -340,6 +340,12 @@ context.selectedVMRef.current = { vmid: 100 }
|
||||
assert.equal(preferenceState.ApplyRestart, false, "missing restart cannot inherit a reboot")
|
||||
preferences.apply({ backup: false, backup_storage: "", restart: false })
|
||||
assert.equal(preferenceState.ApplyBackupStorage, "")
|
||||
preferences.apply({ last_run_reason_code: "stopped_container", last_run_reason: "raw stopped reason" })
|
||||
assert.equal(preferenceState.ScheduleLastRunReasonCode, "stopped_container",
|
||||
"schedule payload publishes its structured stopped reason")
|
||||
preferences.apply({})
|
||||
assert.equal(preferenceState.ScheduleLastRunReasonCode, null,
|
||||
"a missing reason code cannot leak from the previously selected guest")
|
||||
preferenceContext.vmModalCacheRef.current.schedule.set(213, { backup: true, backup_storage: "local", restart: true })
|
||||
const previousSchedule = preferences.schedule(213)
|
||||
assert.equal(preferenceState.ApplyBackup, true, "use only the selected guest's own cache")
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// Execute the real scheduled-run detail JSX: a known backend reason code is
|
||||
// localized, while an unknown/missing code keeps its raw diagnostic text.
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const vm = require('node:vm')
|
||||
const root = path.resolve(__dirname, '../../AppImage')
|
||||
const ts = require(path.join(root, 'node_modules/typescript'))
|
||||
const source = fs.readFileSync(path.join(root, 'components/virtual-machines.tsx'), 'utf8')
|
||||
const tree = ts.createSourceFile('vm.tsx', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX)
|
||||
let declaration
|
||||
let legacyReasons
|
||||
let reasonCodeHelper
|
||||
function walk(node) {
|
||||
if (ts.isVariableDeclaration(node) && node.name.getText(tree) === 'renderScheduleRunDetails') declaration = node.getText(tree)
|
||||
if (ts.isVariableDeclaration(node) && node.name.getText(tree) === 'LEGACY_STOPPED_SCHEDULE_REASONS') legacyReasons = node.getText(tree)
|
||||
if (ts.isVariableDeclaration(node) && node.name.getText(tree) === 'scheduleReasonCodeFromPersisted') reasonCodeHelper = node.getText(tree)
|
||||
ts.forEachChild(node, walk)
|
||||
}
|
||||
walk(tree)
|
||||
assert(declaration, 'scheduled run detail renderer must exist')
|
||||
assert(legacyReasons, 'legacy stopped-reason list must exist')
|
||||
assert(reasonCodeHelper, 'persisted schedule reason-code helper must exist')
|
||||
|
||||
function compile(context) {
|
||||
const result = ts.transpileModule(`const ${declaration}; exports.render = renderScheduleRunDetails;`, {
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX },
|
||||
reportDiagnostics: true,
|
||||
})
|
||||
assert.equal(result.diagnostics.length, 0)
|
||||
vm.runInNewContext(result.outputText, context)
|
||||
return context.exports.render
|
||||
}
|
||||
|
||||
function compileReasonCodeHelper() {
|
||||
const result = ts.transpileModule(`const ${legacyReasons}; const ${reasonCodeHelper}; exports.reasonCode = scheduleReasonCodeFromPersisted;`, {
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS },
|
||||
reportDiagnostics: true,
|
||||
})
|
||||
assert.equal(result.diagnostics.length, 0)
|
||||
const context = { exports: {}, Set }
|
||||
vm.runInNewContext(result.outputText, context)
|
||||
return context.exports.reasonCode
|
||||
}
|
||||
|
||||
function flattenText(node) {
|
||||
if (Array.isArray(node)) return node.map(flattenText).join(' ')
|
||||
if (!node || typeof node !== 'object') return typeof node === 'string' ? node : ''
|
||||
return flattenText(node.props?.children)
|
||||
}
|
||||
|
||||
const persistedReasonCode = compileReasonCodeHelper()
|
||||
assert.equal(persistedReasonCode('stopped_container', 'anything'), 'stopped_container')
|
||||
assert.equal(persistedReasonCode(null, 'Container is stopped; scheduled update was skipped'), 'stopped_container')
|
||||
assert.equal(persistedReasonCode(null, 'container was stopped before scheduled update could begin'), 'stopped_container')
|
||||
assert.equal(persistedReasonCode('future_reason', 'raw diagnostic'), 'future_reason')
|
||||
assert.equal(persistedReasonCode(null, 'raw diagnostic'), null)
|
||||
|
||||
for (const locale of ['en', 'sk']) {
|
||||
const messages = JSON.parse(fs.readFileSync(path.join(root, `messages/${locale}/common.json`), 'utf8'))
|
||||
const t = (key, variables = {}) => {
|
||||
const message = key.split('.').reduce((value, part) => value?.[part], messages)
|
||||
return String(message ?? key).replace(/\{([^}]+)\}/g, (_, name) => String(variables[name] ?? `{${name}}`))
|
||||
}
|
||||
const context = {
|
||||
exports: {}, t, selectedVM: { vmid: 100, status: 'stopped' }, scheduleLastRunAt: '2026-10-16T05:10:02Z',
|
||||
scheduleLastRunStatus: 'skipped', scheduleLastRunReasonCode: 'stopped_container',
|
||||
scheduleLastRunReason: 'container is stopped; scheduled update was skipped',
|
||||
scheduleLastRunRebootRequired: false, scheduleLastRunRebootPackages: [], scheduleLastRunLog: null,
|
||||
openScheduleLog() {}, AlertTriangle: 'AlertTriangle', FileText: 'FileText',
|
||||
require: () => ({ jsx: (type, props) => ({ type, props }), jsxs: (type, props) => ({ type, props }), Fragment: 'Fragment' }),
|
||||
}
|
||||
const render = compile(context)
|
||||
const translated = flattenText(render(true))
|
||||
const expectedCurrentReason = t('vmLxc.scheduled.reasonStoppedContainer')
|
||||
const expectedHistoricalReason = t('vmLxc.scheduled.reasonStoppedContainerHistorical')
|
||||
const skippedLabel = t('vmLxc.scheduled.runSkippedStatus')
|
||||
const expectedCurrentText = locale === 'sk'
|
||||
? 'Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.'
|
||||
: 'Container is stopped; scheduled update was skipped.'
|
||||
const expectedHistoricalText = locale === 'sk'
|
||||
? 'Kontajner bol v čase plánovanej aktualizácie vypnutý.'
|
||||
: 'Container was stopped at the scheduled update time.'
|
||||
assert.equal(expectedCurrentReason, expectedCurrentText,
|
||||
`${locale}: stopped CT must describe its current stopped state`)
|
||||
assert.equal(expectedHistoricalReason, expectedHistoricalText,
|
||||
`${locale}: running CT must describe the stopped state at the prior scheduled run`)
|
||||
assert(translated.includes(expectedCurrentReason), `${locale}: currently stopped CT must use the present-state catalog`)
|
||||
assert(!translated.includes(expectedHistoricalReason), `${locale}: currently stopped CT must not use historical wording`)
|
||||
assert(translated.includes(skippedLabel), `${locale}: skipped run must not claim that no updates are pending`)
|
||||
assert(!translated.includes(context.scheduleLastRunReason), `${locale}: raw stopped reason must not leak into UI`)
|
||||
|
||||
context.selectedVM.status = 'running'
|
||||
const historical = flattenText(render(true))
|
||||
assert(historical.includes(expectedHistoricalReason), `${locale}: running CT must use historical wording for a past skipped run`)
|
||||
assert(!historical.includes(expectedCurrentReason), `${locale}: running CT must not claim it is currently stopped`)
|
||||
|
||||
context.scheduleLastRunReasonCode = 'unknown_reason'
|
||||
const fallback = flattenText(render(true))
|
||||
assert(fallback.includes(context.scheduleLastRunReason), `${locale}: unknown code must retain the raw diagnostic`)
|
||||
}
|
||||
console.log('PASS scheduled reason i18n: EN/SK structured stopped reason and raw fallback')
|
||||
@@ -119,7 +119,8 @@ raise SystemExit(h.main())
|
||||
self.write("sleep", "#!/bin/sh\nexit 0\n")
|
||||
self.write("flock", "#!/bin/sh\nexit 0\n")
|
||||
names = {"_finalize_lxc_update", "_terminal_lxc_update_completed",
|
||||
"api_lxc_updates_applied", "_run_scheduled_update"}
|
||||
"api_lxc_updates_applied", "_run_scheduled_update",
|
||||
"_scheduled_runner_reported_stopped"}
|
||||
nodes = [n for n in ast.parse(observed.SERVER.read_text()).body
|
||||
if isinstance(n, ast.FunctionDef) and n.name in names]
|
||||
self.scope = self.fixture.scope
|
||||
@@ -134,6 +135,7 @@ raise SystemExit(h.main())
|
||||
"_json_list": lambda value: json.loads(value or '[]'),
|
||||
"_lxc_update_finalizations": {}, "_lxc_update_finalization_lock": threading.RLock(),
|
||||
"_LXC_UPDATE_FINALIZATION_TTL": 3600,
|
||||
"_SCHEDULED_STOPPED_EXIT": 9,
|
||||
"_fast_guest_status": lambda *_: self.state.read_text(),
|
||||
"_lxc_update_snapshot": lambda *_: {"ct_name": "fixture"},
|
||||
"_lxc_update_target_labels": lambda *_: ["OS"],
|
||||
@@ -315,6 +317,7 @@ raise SystemExit(h.main())
|
||||
self.scope['notification_manager'].emit_event.assert_called_once()
|
||||
|
||||
def test_scheduled_path_executes_real_runner_and_real_finalization(self):
|
||||
self.state.write_text("running")
|
||||
def run(command, **kwargs):
|
||||
kwargs['env'].update({key: value for key, value in self.env.items()
|
||||
if key != 'RUN_ID'})
|
||||
@@ -322,7 +325,7 @@ raise SystemExit(h.main())
|
||||
self.scope['subprocess'] = SimpleNamespace(run=run, TimeoutExpired=subprocess.TimeoutExpired)
|
||||
result = self.scope['_run_scheduled_update'](100, {'targets': ['os'], 'target': 'os'})
|
||||
self.assertEqual(result['status'], 'success', result)
|
||||
self.assertEqual(self.state.read_text(), 'stopped')
|
||||
self.assertEqual(self.state.read_text(), 'running')
|
||||
self.assertEqual(self.fixture.row()['update_check']['count'], 0)
|
||||
|
||||
def test_legacy_cli_without_run_id_preserves_update_and_original_state(self):
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -312,6 +315,159 @@ class AppCacheWriteThroughContractTests(unittest.TestCase):
|
||||
self.assertIn("before_snapshot=before", scheduler_block)
|
||||
|
||||
|
||||
class ScheduledStoppedContainerTests(unittest.TestCase):
|
||||
@staticmethod
|
||||
def _worker(scope):
|
||||
source = ast.parse((REPO_ROOT / "AppImage" / "scripts" / "flask_server.py").read_text())
|
||||
node = next(item for item in source.body
|
||||
if isinstance(item, ast.FunctionDef) and item.name == "_run_scheduled_update")
|
||||
exec(compile(ast.Module(body=[node], type_ignores=[]), "scheduled-update", "exec"), scope)
|
||||
return scope["_run_scheduled_update"]
|
||||
|
||||
@staticmethod
|
||||
def _stopped_marker_reader(scope):
|
||||
source = ast.parse((REPO_ROOT / "AppImage" / "scripts" / "flask_server.py").read_text())
|
||||
node = next(item for item in source.body
|
||||
if isinstance(item, ast.FunctionDef) and item.name == "_scheduled_runner_reported_stopped")
|
||||
exec(compile(ast.Module(body=[node], type_ignores=[]), "scheduled-marker", "exec"), scope)
|
||||
return scope["_scheduled_runner_reported_stopped"]
|
||||
|
||||
def test_stopped_container_skips_before_runner_or_any_guest_effect(self):
|
||||
runner = MagicMock()
|
||||
finalizer = MagicMock(return_value={"recorded": True})
|
||||
append_log = MagicMock()
|
||||
scope = {
|
||||
"time": SimpleNamespace(monotonic=MagicMock(return_value=10.0)),
|
||||
"uuid": SimpleNamespace(uuid4=lambda: SimpleNamespace(hex="a" * 32)),
|
||||
"datetime": __import__("datetime").datetime,
|
||||
"subprocess": SimpleNamespace(run=runner, STDOUT=object(), TimeoutExpired=subprocess.TimeoutExpired),
|
||||
"_create_lxc_update_log": lambda _vmid, _run_id: ("fixture.log", "/tmp/fixture.log"),
|
||||
"_fast_guest_status": MagicMock(return_value="stopped"),
|
||||
"_normalise_schedule_targets": lambda _sched: ["os"],
|
||||
"_lxc_update_snapshot": lambda _vmid: {"ct_name": "fixture"},
|
||||
"_lxc_update_target_labels": lambda *_: ["OS"],
|
||||
"_append_lxc_update_log": append_log,
|
||||
"_prune_lxc_update_logs": MagicMock(),
|
||||
"_finalize_lxc_update": finalizer,
|
||||
}
|
||||
|
||||
outcome = self._worker(scope)(101, {"target": "os"})
|
||||
|
||||
self.assertEqual(outcome["status"], "skipped")
|
||||
self.assertEqual(outcome["executed_targets"], [])
|
||||
self.assertIn("container is stopped", outcome["reason"])
|
||||
self.assertEqual(outcome["reason_code"], "stopped_container")
|
||||
runner.assert_not_called()
|
||||
self.assertEqual(finalizer.call_args.kwargs["status"], "skipped")
|
||||
self.assertEqual(finalizer.call_args.kwargs["source"], "scheduled")
|
||||
|
||||
def test_stopped_marker_requires_the_scheduler_token_not_only_exit_code(self):
|
||||
marker = "PROXMENUX_SCHEDULED_STOPPED:fixture"
|
||||
reader = self._stopped_marker_reader({"_SCHEDULED_STOPPED_EXIT": 9, "os": os})
|
||||
self.assertTrue(reader(SimpleNamespace(returncode=9, stdout=marker, stderr=""), None, marker))
|
||||
self.assertFalse(reader(SimpleNamespace(returncode=9, stdout="", stderr=""), None, marker))
|
||||
self.assertFalse(reader(SimpleNamespace(returncode=8, stdout=marker, stderr=""), None, marker))
|
||||
self.assertFalse(reader(SimpleNamespace(returncode=4, stdout=marker, stderr=""), None, marker))
|
||||
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as log:
|
||||
log.write("prefix\\n" + marker + "\\n")
|
||||
log.flush()
|
||||
self.assertTrue(reader(SimpleNamespace(returncode=9, stdout="", stderr=""), log.name, marker))
|
||||
|
||||
def test_runner_race_to_stopped_is_reported_as_skipped_without_reboot_probe(self):
|
||||
runner = MagicMock(return_value=SimpleNamespace(returncode=9, stdout="", stderr=""))
|
||||
finalizer = MagicMock(return_value={"recorded": True})
|
||||
reboot_probe = MagicMock()
|
||||
stopped_marker = MagicMock(return_value=True)
|
||||
lxc = SimpleNamespace(
|
||||
_read_sidecar=lambda _vmid: {"apps": []},
|
||||
partition_scheduled_release_targets=lambda targets, _apps: (set(), targets),
|
||||
)
|
||||
scope = {
|
||||
"time": SimpleNamespace(monotonic=MagicMock(return_value=10.0)),
|
||||
"uuid": SimpleNamespace(uuid4=lambda: SimpleNamespace(hex="b" * 32)),
|
||||
"datetime": __import__("datetime").datetime,
|
||||
"subprocess": SimpleNamespace(run=runner, STDOUT=object(), TimeoutExpired=subprocess.TimeoutExpired),
|
||||
"os": os,
|
||||
"json": json,
|
||||
"_APPLY_UPDATES_SCRIPT": "/bin/true",
|
||||
"_SCHEDULED_STOPPED_EXIT": 9,
|
||||
"_DOCKER_ENGINE_INTEGRATED_COMMAND": "integrated-docker",
|
||||
"_create_lxc_update_log": lambda _vmid, _run_id: (None, None),
|
||||
"_fast_guest_status": MagicMock(return_value="running"),
|
||||
"_normalise_schedule_targets": lambda _sched: ["os"],
|
||||
"_lxc_update_snapshot": lambda _vmid: {"ct_name": "fixture"},
|
||||
"_lxc_update_target_labels": lambda *_: ["OS"],
|
||||
"_append_lxc_update_log": MagicMock(),
|
||||
"_prune_lxc_update_logs": MagicMock(),
|
||||
"_finalize_lxc_update": finalizer,
|
||||
"_scheduled_helper_enabled": lambda *_: False,
|
||||
"_compose_scheduled_update_command": lambda *_: "",
|
||||
"_inspect_lxc_reboot_requirement": reboot_probe,
|
||||
"_scheduled_runner_reported_stopped": stopped_marker,
|
||||
}
|
||||
|
||||
with patch.dict(sys.modules, {"lxc_apps": lxc}):
|
||||
outcome = self._worker(scope)(101, {"target": "os"})
|
||||
|
||||
self.assertEqual(outcome["status"], "skipped")
|
||||
self.assertEqual(outcome["executed_targets"], [])
|
||||
self.assertIn("before scheduled update could begin", outcome["reason"])
|
||||
self.assertEqual(outcome["reason_code"], "stopped_container")
|
||||
self.assertEqual(runner.call_args.args[0], ["bash", "/bin/true"])
|
||||
self.assertEqual(runner.call_args.kwargs["env"]["EXECUTION_MODE"], "scheduled")
|
||||
self.assertTrue(runner.call_args.kwargs["env"]["SCHEDULED_STOPPED_MARKER"].startswith(
|
||||
"PROXMENUX_SCHEDULED_STOPPED:scheduled-"))
|
||||
stopped_marker.assert_called_once()
|
||||
reboot_probe.assert_not_called()
|
||||
|
||||
stopped_marker.reset_mock()
|
||||
stopped_marker.return_value = False
|
||||
runner.return_value = SimpleNamespace(returncode=8, stdout="", stderr="")
|
||||
reboot_probe.return_value = (None, [], None)
|
||||
outcome = self._worker(scope)(101, {"target": "os"})
|
||||
self.assertEqual(outcome["status"], "failure")
|
||||
self.assertIn("exited with code 8", outcome["reason"])
|
||||
stopped_marker.assert_called_once()
|
||||
reboot_probe.assert_called_once()
|
||||
|
||||
def test_oci_race_to_stopped_skips_before_the_oci_engine_runs(self):
|
||||
runner = MagicMock(return_value=SimpleNamespace(returncode=0, stdout="", stderr=""))
|
||||
finalizer = MagicMock(return_value={"recorded": True})
|
||||
status = MagicMock(side_effect=["running", "stopped"])
|
||||
scope = {
|
||||
"time": SimpleNamespace(monotonic=MagicMock(return_value=10.0)),
|
||||
"uuid": SimpleNamespace(uuid4=lambda: SimpleNamespace(hex="c" * 32)),
|
||||
"datetime": __import__("datetime").datetime,
|
||||
"subprocess": SimpleNamespace(
|
||||
run=runner,
|
||||
STDOUT=object(),
|
||||
DEVNULL=object(),
|
||||
TimeoutExpired=subprocess.TimeoutExpired,
|
||||
),
|
||||
"os": os,
|
||||
"re": re,
|
||||
"_create_lxc_update_log": lambda _vmid, _run_id: (None, None),
|
||||
"_fast_guest_status": status,
|
||||
"_normalise_schedule_targets": lambda _sched: ["oci_image"],
|
||||
"_lxc_update_snapshot": lambda _vmid: {"ct_name": "fixture"},
|
||||
"_lxc_update_target_labels": lambda *_: ["OCI image"],
|
||||
"_append_lxc_update_log": MagicMock(),
|
||||
"_prune_lxc_update_logs": MagicMock(),
|
||||
"_finalize_lxc_update": finalizer,
|
||||
}
|
||||
|
||||
outcome = self._worker(scope)(101, {"targets": ["oci_image"]})
|
||||
|
||||
self.assertEqual(outcome["status"], "skipped")
|
||||
self.assertEqual(outcome["target"], "oci_image")
|
||||
self.assertEqual(outcome["executed_targets"], [])
|
||||
self.assertEqual(outcome["reason_code"], "stopped_container")
|
||||
self.assertIn("before scheduled update could begin", outcome["reason"])
|
||||
self.assertEqual(status.call_count, 2)
|
||||
runner.assert_not_called()
|
||||
self.assertEqual(finalizer.call_args.kwargs["status"], "skipped")
|
||||
|
||||
|
||||
class DockerStackNotificationTests(unittest.TestCase):
|
||||
def _docker_app(self):
|
||||
return {
|
||||
|
||||
@@ -37,6 +37,7 @@ def routes():
|
||||
_lxc_update_target_labels=lambda *_: [],
|
||||
_append_lxc_update_log=lambda *_: None,
|
||||
_prune_lxc_update_logs=lambda *_: None,
|
||||
_scheduled_runner_reported_stopped=lambda *_: False,
|
||||
_finalize_lxc_update=Mock(return_value={}),
|
||||
_inspect_lxc_reboot_requirement=lambda *_, **__: (False, [], None))
|
||||
exec(compile(ast.Module(body=nodes, type_ignores=[]), 'update-routes', 'exec'), ns)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Render the real help component; only its translation provider is replaced.
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const vm = require('node:vm');
|
||||
const ts = require('typescript');
|
||||
const React = require('react');
|
||||
const { renderToStaticMarkup } = require('react-dom/server');
|
||||
const source = fs.readFileSync('AppImage/components/apprise-service-help.tsx', 'utf8');
|
||||
const js = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX } }).outputText;
|
||||
const english = JSON.parse(fs.readFileSync('AppImage/messages/en/common.json'));
|
||||
function resolve(catalog, key) { return key.split('.').reduce((value, part) => value?.[part], catalog); }
|
||||
for (const locale of ['en', 'es', 'de', 'fr', 'it', 'pt', 'sk', 'sv', 'missing']) {
|
||||
const catalog = locale === 'missing' ? {} : JSON.parse(fs.readFileSync(`AppImage/messages/${locale}/common.json`));
|
||||
const context = { exports: {}, require: name => name === '../lib/i18n/provider' ? {
|
||||
useT: () => key => resolve(catalog, key) ?? resolve(english, key),
|
||||
} : require(name) };
|
||||
vm.runInNewContext(js, context);
|
||||
const html = renderToStaticMarkup(React.createElement(context.exports.AppriseServiceHelp));
|
||||
assert.ok(html.includes('https://hooks.slack.com/services/TOKEN_A/TOKEN_B/TOKEN_C'));
|
||||
assert.ok(html.includes('matrixs://USER:PASSWORD@matrix.example.com/!ROOM_ID:matrix.example.com'));
|
||||
assert.ok(html.includes('https://appriseit.com/services/slack/'));
|
||||
assert.ok(html.includes('https://appriseit.com/services/matrix/'));
|
||||
assert.ok(!html.includes('settings.notifications.'), `${locale}: no unresolved labels`);
|
||||
}
|
||||
for (const [, key] of source.matchAll(/t\("([^"]+)"\)/g)) assert.ok(resolve(english, key), key);
|
||||
assert.ok(!source.includes('onChange') && !source.includes('fetch(') && !source.includes('updateChannel'));
|
||||
const settings = fs.readFileSync('AppImage/components/notification-settings.tsx', 'utf8');
|
||||
const section = settings.slice(settings.indexOf('<TabsContent value="apprise"'), settings.indexOf('</TabsContent>', settings.indexOf('<TabsContent value="apprise"')));
|
||||
for (const part of ['<AppriseServiceHelp />', 'renderChannelCategories("apprise")', 'handleTest("apprise")']) assert.ok(section.includes(part));
|
||||
console.log('PASS: real provider-help JSX, shipped locales and English fallback, no secret mutation, native category/test controls retained');
|
||||
@@ -0,0 +1,137 @@
|
||||
"""Real Apprise Slack/Matrix plugins with the HTTP boundary replaced.
|
||||
|
||||
No provider account or network is used. These contracts run against both
|
||||
the minimum bundled Apprise version and the current tested version.
|
||||
"""
|
||||
import gc
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import apprise
|
||||
import requests
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "AppImage/scripts"))
|
||||
from notification_channels import create_channel
|
||||
|
||||
SLACK = "https://hooks.slack.com/services/T00000000/B00000000/fixturesecret1234567890"
|
||||
MATRIX = "matrixs://notify:fixture-password@matrix.example.test/!room:matrix.example.test"
|
||||
|
||||
|
||||
class AppriseServiceTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.calls = []
|
||||
self.status = 200
|
||||
self.transport = patch.object(requests.Session, "request", side_effect=self.http)
|
||||
self.transport.start()
|
||||
self.addCleanup(self.transport.stop)
|
||||
self.sleep = patch("notification_channels.time.sleep")
|
||||
self.sleep.start()
|
||||
self.addCleanup(self.sleep.stop)
|
||||
self.addCleanup(gc.collect)
|
||||
|
||||
def http(self, method, url, **kwargs):
|
||||
self.calls.append((method, url, kwargs))
|
||||
response = requests.Response()
|
||||
response.status_code = self.status
|
||||
response.url = url
|
||||
response.reason = "OK" if self.status == 200 else "Rejected"
|
||||
response._content_consumed = True
|
||||
host, path = urlparse(url).hostname, urlparse(url).path
|
||||
if host == "hooks.slack.com":
|
||||
self.assertTrue(path.startswith("/services/"))
|
||||
response._content = b"ok" if self.status == 200 else b"invalid_auth"
|
||||
else:
|
||||
self.assertEqual(host, "matrix.example.test", "no unexpected destinations")
|
||||
if self.status != 200:
|
||||
payload = {"errcode": "M_FORBIDDEN", "error": "Invalid credentials"}
|
||||
elif path == "/.well-known/matrix/client":
|
||||
payload = {"m.homeserver": {"base_url": "https://" + host}}
|
||||
elif path.endswith("/login"):
|
||||
payload = {"access_token": "fixture-token", "home_server": host, "user_id": "@notify:" + host}
|
||||
elif path.endswith("/joined_rooms"):
|
||||
payload = {"joined_rooms": ["!room:" + host]}
|
||||
elif "/join/" in path:
|
||||
payload = {"room_id": "!room:" + host}
|
||||
elif "/send/" in path:
|
||||
payload = {"event_id": "$fixture"}
|
||||
elif path.endswith("/logout"):
|
||||
payload = {}
|
||||
elif path.endswith("/versions"):
|
||||
payload = {"versions": ["v1.1"]}
|
||||
else:
|
||||
raise AssertionError("Unhandled Matrix request: " + path)
|
||||
response._content = json.dumps(payload).encode()
|
||||
return response
|
||||
|
||||
def send(self, url):
|
||||
channel = create_channel("apprise", {"url": url})
|
||||
self.assertIsNotNone(channel)
|
||||
return channel.send("ProxMenux probe", "Controlled message", "WARNING")
|
||||
|
||||
def test_slack_accepts_the_native_webhook_without_conversion(self):
|
||||
result = self.send(SLACK)
|
||||
self.assertTrue(result["success"], result)
|
||||
self.assertTrue(any(url == SLACK for _, url, _ in self.calls))
|
||||
self.assertIn("Controlled message", str(self.calls))
|
||||
|
||||
def test_slack_apprise_scheme_uses_the_same_transport(self):
|
||||
result = self.send(SLACK.replace("https://hooks.slack.com/services/", "slack://"))
|
||||
self.assertTrue(result["success"], result)
|
||||
self.assertTrue(any(url == SLACK for _, url, _ in self.calls))
|
||||
|
||||
def test_matrix_authenticates_and_delivers_to_the_full_room_id_over_https(self):
|
||||
result = self.send(MATRIX)
|
||||
self.assertTrue(result["success"], result)
|
||||
sends = [(url, kwargs) for _, url, kwargs in self.calls if "/send/" in url]
|
||||
self.assertTrue(sends, self.calls)
|
||||
self.assertTrue(all(url.startswith("https://matrix.example.test/") for url, _ in sends))
|
||||
self.assertTrue(all(kwargs.get("verify", True) for _, kwargs in sends))
|
||||
self.assertIn("Controlled message", str(sends))
|
||||
self.assertTrue(any(url.endswith("/login") for _, url, _ in self.calls))
|
||||
|
||||
def test_test_button_contract_uses_the_same_provider(self):
|
||||
ok, error = create_channel("apprise", {"url": SLACK}).test()
|
||||
self.assertTrue(ok, error)
|
||||
self.assertTrue(self.calls)
|
||||
|
||||
def test_rejected_slack_webhook_is_not_reported_as_delivered(self):
|
||||
self.status = 403
|
||||
result = self.send(SLACK)
|
||||
self.assertFalse(result["success"])
|
||||
self.assertTrue(result["error"])
|
||||
|
||||
def test_invalid_matrix_credentials_are_not_reported_as_delivered(self):
|
||||
self.status = 403
|
||||
result = self.send(MATRIX)
|
||||
self.assertFalse(result["success"])
|
||||
self.assertFalse(any("/send/" in url for _, url, _ in self.calls))
|
||||
|
||||
def test_invalid_urls_and_missing_library_fail_before_any_request(self):
|
||||
channel = create_channel("apprise", {"url": "not-a-url"})
|
||||
self.assertFalse(channel.send("Probe", "Body")["success"])
|
||||
channel = create_channel("apprise", {"url": SLACK})
|
||||
with patch.object(channel, "_load_apprise", return_value=None):
|
||||
self.assertFalse(channel.send("Probe", "Body")["success"])
|
||||
self.assertEqual(self.calls, [])
|
||||
|
||||
def test_connection_failure_never_claims_delivery(self):
|
||||
for url in (SLACK, MATRIX):
|
||||
with patch.object(requests.Session, "request", side_effect=requests.ConnectionError("fixture connection failure")):
|
||||
result = self.send(url)
|
||||
self.assertFalse(result["success"])
|
||||
self.assertTrue(result["error"])
|
||||
|
||||
def test_severity_mapping_keeps_native_notification_semantics(self):
|
||||
channel = create_channel("apprise", {"url": SLACK})
|
||||
for severity, expected in (("CRITICAL", apprise.NotifyType.FAILURE), ("WARNING", apprise.NotifyType.WARNING),
|
||||
("INFO", apprise.NotifyType.INFO), ("OK", apprise.NotifyType.SUCCESS),
|
||||
("SUCCESS", apprise.NotifyType.SUCCESS)):
|
||||
self.assertEqual(channel._severity_to_notify_type(apprise, severity), expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,204 @@
|
||||
"""Exercise the real Figurine installer with isolated files and no network/root access."""
|
||||
|
||||
import ast
|
||||
import importlib.util
|
||||
import io
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = ROOT / "scripts/post_install/customizable_post_install.sh"
|
||||
FUNCTION = re.search(
|
||||
r"^configure_figurine\(\) \{\n.*?^\}", SCRIPT.read_text(), re.M | re.S
|
||||
).group(0)
|
||||
VERSION = re.search(r'FIGURINE_VERSION:-([^}]+)', FUNCTION).group(1)
|
||||
FUNCTION_VERSION = re.search(r'local FUNC_VERSION="([^"]+)"', FUNCTION).group(1)
|
||||
|
||||
|
||||
class FigurineInstallation(unittest.TestCase):
|
||||
def run_installer(self, arch="amd64", *, kernel="x86_64", dpkg_exit=0,
|
||||
release=None, download_exit=0, package="valid", existing=True):
|
||||
with tempfile.TemporaryDirectory(prefix="figurine-test-") as directory:
|
||||
root = Path(directory)
|
||||
binary_dir = root / "bin"
|
||||
profile_dir = root / "profile.d"
|
||||
binary_dir.mkdir()
|
||||
profile_dir.mkdir()
|
||||
(root / "tmp").mkdir()
|
||||
binary = binary_dir / "figurine"
|
||||
profile = profile_dir / "figurine.sh"
|
||||
bashrc = root / "bashrc"
|
||||
if existing:
|
||||
binary.write_text("previous binary\n")
|
||||
binary.chmod(0o755)
|
||||
profile.write_text("previous profile\n")
|
||||
bashrc.write_text("# previous bashrc\n")
|
||||
archive = root / "fixture.tar.gz"
|
||||
payload = b"#!/bin/sh\nprintf 'fixture Figurine\\n'\n"
|
||||
if package == "corrupt":
|
||||
archive.write_bytes(b"invalid tarball")
|
||||
else:
|
||||
with tarfile.open(archive, "w:gz") as tar:
|
||||
name = "deploy/figurine" if package == "valid" else "README"
|
||||
member = tarfile.TarInfo(name)
|
||||
member.size = len(payload)
|
||||
tar.addfile(member, io.BytesIO(payload))
|
||||
|
||||
# Relocate every installer filesystem boundary, including its login script.
|
||||
function = (FUNCTION.replace("/usr/local/bin", str(binary_dir))
|
||||
.replace("/etc/profile.d", str(profile_dir))
|
||||
.replace("/root/.bashrc", str(bashrc)))
|
||||
harness = r'''
|
||||
translate() { printf '%s' "$1"; }
|
||||
msg_info2() { :; }
|
||||
msg_info() { :; }
|
||||
msg_ok() { :; }
|
||||
msg_success() { :; }
|
||||
msg_error() { printf '%s\n' "$*" >&2; }
|
||||
pmx_journal_context() { :; }
|
||||
pmx_write_file() { cat > "$1"; }
|
||||
pmx_append_file() { cat >> "$1"; }
|
||||
pmx_edit_file() { :; }
|
||||
chown() { :; }
|
||||
dpkg() {
|
||||
[[ "$TEST_DPKG_EXIT" == 0 ]] || return "$TEST_DPKG_EXIT"
|
||||
printf '%s\n' "$TEST_ARCH"
|
||||
}
|
||||
uname() { printf '%s\n' "$TEST_KERNEL"; }
|
||||
wget() {
|
||||
[[ "$1" == -qO ]] || return 90
|
||||
printf '%s\n' "$3" >> "$TEST_ROOT/downloads"
|
||||
[[ "$TEST_DOWNLOAD_EXIT" == 0 ]] || return "$TEST_DOWNLOAD_EXIT"
|
||||
cp "$TEST_ROOT/fixture.tar.gz" "$2"
|
||||
}
|
||||
register_tool() { printf '%s\n' "$*" > "$TEST_ROOT/registered"; }
|
||||
'''
|
||||
harness += function + "\nconfigure_figurine\nexit \"$?\"\n"
|
||||
environment = {
|
||||
"PATH": f"{binary_dir}:/usr/bin:/bin",
|
||||
"HOME": str(root),
|
||||
"TMPDIR": str(root / "tmp"),
|
||||
"LC_ALL": "C",
|
||||
"TEST_ROOT": str(root),
|
||||
"TEST_ARCH": arch,
|
||||
"TEST_DPKG_EXIT": str(dpkg_exit),
|
||||
"TEST_KERNEL": kernel,
|
||||
"TEST_DOWNLOAD_EXIT": str(download_exit),
|
||||
}
|
||||
if release is not None:
|
||||
environment["FIGURINE_VERSION"] = release
|
||||
result = subprocess.run(
|
||||
["/bin/bash", "--noprofile", "--norc"], input=harness,
|
||||
text=True, capture_output=True, env=environment, timeout=10,
|
||||
)
|
||||
return {
|
||||
"result": result,
|
||||
"binary": binary.read_bytes(),
|
||||
"mode": binary.stat().st_mode & 0o777,
|
||||
"profile": profile.read_text(),
|
||||
"bashrc": bashrc.read_text(),
|
||||
"downloads": (root / "downloads").read_text() if (root / "downloads").exists() else "",
|
||||
"registered": (root / "registered").read_text() if (root / "registered").exists() else "",
|
||||
"payload": payload,
|
||||
"binary_path": str(binary),
|
||||
}
|
||||
|
||||
def test_installs_release_matching_debian_userspace(self):
|
||||
for arch, asset in (("amd64", "amd64"), ("arm64", "arm64"), ("armhf", "arm")):
|
||||
with self.subTest(arch=arch):
|
||||
state = self.run_installer(arch)
|
||||
self.assertEqual(state["result"].returncode, 0, state["result"].stderr)
|
||||
self.assertEqual(state["downloads"],
|
||||
f"https://github.com/arsham/figurine/releases/download/v{VERSION}/"
|
||||
f"figurine_linux_{asset}_v{VERSION}.tar.gz\n")
|
||||
self.assertEqual(state["binary"], state["payload"])
|
||||
self.assertEqual(state["mode"], 0o755)
|
||||
self.assertIn(f'{state["binary_path"]} -f "3d.flf" $(hostname)', state["profile"])
|
||||
self.assertEqual(state["registered"], f"figurine true {FUNCTION_VERSION}\n")
|
||||
|
||||
def test_falls_back_to_kernel_when_dpkg_is_unavailable(self):
|
||||
for kernel, asset in (("x86_64", "amd64"), ("aarch64", "arm64"),
|
||||
("armv7l", "arm"), ("armv8l", "arm")):
|
||||
with self.subTest(kernel=kernel):
|
||||
state = self.run_installer("", kernel=kernel, dpkg_exit=127)
|
||||
self.assertEqual(state["result"].returncode, 0, state["result"].stderr)
|
||||
self.assertIn(f"figurine_linux_{asset}_v{VERSION}.tar.gz", state["downloads"])
|
||||
|
||||
def test_userspace_takes_precedence_over_kernel(self):
|
||||
state = self.run_installer("armhf", kernel="aarch64")
|
||||
self.assertEqual(state["result"].returncode, 0, state["result"].stderr)
|
||||
self.assertIn(f"figurine_linux_arm_v{VERSION}.tar.gz", state["downloads"])
|
||||
|
||||
def test_fresh_install_creates_binary_banner_and_aliases(self):
|
||||
state = self.run_installer(existing=False)
|
||||
self.assertEqual(state["result"].returncode, 0, state["result"].stderr)
|
||||
self.assertEqual(state["binary"], state["payload"])
|
||||
self.assertIn(' -f "3d.flf" $(hostname)', state["profile"])
|
||||
self.assertIn("shopt -s expand_aliases", state["bashrc"])
|
||||
self.assertIn("alias aptup='apt update && apt dist-upgrade'", state["bashrc"])
|
||||
self.assertEqual(state["registered"], f"figurine true {FUNCTION_VERSION}\n")
|
||||
|
||||
def test_unsupported_architecture_fails_before_changes_or_download(self):
|
||||
for arch in ("i386", "riscv64", "armel", "armv6l", "ppc64el", ""):
|
||||
with self.subTest(arch=arch):
|
||||
state = self.run_installer(arch)
|
||||
self.assertNotEqual(state["result"].returncode, 0)
|
||||
self.assertIn("Unsupported architecture for Figurine:", state["result"].stderr)
|
||||
self.assertEqual(state["downloads"], "")
|
||||
self.assert_preserved(state)
|
||||
self.assertEqual(state["bashrc"], "# previous bashrc\n")
|
||||
|
||||
def assert_preserved(self, state):
|
||||
self.assertEqual(state["binary"], b"previous binary\n")
|
||||
self.assertEqual(state["profile"], "previous profile\n")
|
||||
self.assertEqual(state["registered"], "")
|
||||
|
||||
def test_download_failure_preserves_previous_installation(self):
|
||||
state = self.run_installer(download_exit=8)
|
||||
self.assertNotEqual(state["result"].returncode, 0)
|
||||
self.assertIn("Failed to download Figurine", state["result"].stderr)
|
||||
self.assert_preserved(state)
|
||||
|
||||
def test_invalid_packages_preserve_previous_installation(self):
|
||||
for package, error in (("corrupt", "Failed to extract package"),
|
||||
("missing", "Binary not found in extracted content.")):
|
||||
with self.subTest(package=package):
|
||||
state = self.run_installer(package=package)
|
||||
self.assertNotEqual(state["result"].returncode, 0)
|
||||
self.assertIn(error, state["result"].stderr)
|
||||
self.assert_preserved(state)
|
||||
|
||||
def test_release_override_is_preserved(self):
|
||||
state = self.run_installer("arm64", release="2.1.0")
|
||||
self.assertEqual(state["result"].returncode, 0, state["result"].stderr)
|
||||
self.assertIn("/v2.1.0/figurine_linux_arm64_v2.1.0.tar.gz", state["downloads"])
|
||||
|
||||
def test_existing_installation_is_offered_the_update_once(self):
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"post_install_versions", ROOT / "AppImage/scripts/post_install_versions.py")
|
||||
versions = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(versions)
|
||||
metadata = versions.parse_post_install_script(SCRIPT)
|
||||
installed = {"figurine": {"installed": True, "version": "1.1", "source": "custom"}}
|
||||
updates = versions._detect_updates({}, metadata, installed)
|
||||
self.assertEqual(len(updates), 1)
|
||||
self.assertEqual(updates[0]["available_version"], FUNCTION_VERSION)
|
||||
self.assertEqual(updates[0]["function"], "configure_figurine")
|
||||
installed["figurine"]["version"] = FUNCTION_VERSION
|
||||
self.assertEqual(versions._detect_updates({}, metadata, installed), [])
|
||||
|
||||
tree = ast.parse((ROOT / "AppImage/scripts/flask_proxmenux_routes.py").read_text())
|
||||
fallback = next(ast.literal_eval(node.value) for node in tree.body
|
||||
if isinstance(node, ast.Assign)
|
||||
and any(isinstance(t, ast.Name) and t.id == "TOOL_METADATA"
|
||||
for t in node.targets))
|
||||
self.assertEqual(fallback["figurine"]["version"], FUNCTION_VERSION)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -87,7 +87,7 @@ export default async function OtherNASSystemsPage({
|
||||
const importItems = o.storagePlan.importItemsRich
|
||||
const pciItems = o.storagePlan.pciItemsRich
|
||||
const endToEndItems = o.endToEnd.itemsRich
|
||||
const systemOrder = ["truenasScale", "truenasCore", "openmediavault", "xigmanas", "rockstor", "zimaos"]
|
||||
const systemOrder = ["truenasScale", "truenasCore", "openmediavault", "xigmanas", "rockstor", "zimaos", "fygoos"]
|
||||
const relatedItems = o.related.itemsRich
|
||||
|
||||
const code = (chunks: React.ReactNode) => <code>{chunks}</code>
|
||||
|
||||
@@ -312,25 +312,31 @@ EOF
|
||||
<p className="text-lg mb-2">{t("figurine.automates")}</p>
|
||||
<CopyableCode
|
||||
code={`
|
||||
# Check for previous installation and remove if found
|
||||
if command -v figurine &> /dev/null; then
|
||||
rm -f "/usr/local/bin/figurine"
|
||||
fi
|
||||
|
||||
# Download and install Figurine
|
||||
version="2.0.0"
|
||||
file="figurine_linux_amd64_v\${version}.tar.gz"
|
||||
(
|
||||
set -e
|
||||
version="\${FIGURINE_VERSION:-2.1.1}"
|
||||
arch="$(dpkg --print-architecture 2>/dev/null || uname -m)"
|
||||
case "$arch" in
|
||||
amd64|x86_64) arch="amd64" ;;
|
||||
arm64|aarch64) arch="arm64" ;;
|
||||
armhf|armv7l|armv8l) arch="arm" ;;
|
||||
*) echo "Unsupported architecture for Figurine: $arch" >&2; exit 1 ;;
|
||||
esac
|
||||
file="figurine_linux_\${arch}_v\${version}.tar.gz"
|
||||
url="https://github.com/arsham/figurine/releases/download/v\${version}/\${file}"
|
||||
wget -qO "/tmp/\${file}" "\${url}"
|
||||
tar -xf "/tmp/\${file}" -C "/tmp"
|
||||
mv "/tmp/deploy/figurine" "/usr/local/bin/figurine"
|
||||
chmod +x "/usr/local/bin/figurine"
|
||||
temp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$temp_dir"' EXIT
|
||||
wget -qO "\${temp_dir}/\${file}" "\${url}"
|
||||
tar -xf "\${temp_dir}/\${file}" -C "$temp_dir"
|
||||
install -m 0755 "\${temp_dir}/deploy/figurine" "/usr/local/bin/figurine"
|
||||
|
||||
# Create welcome message script
|
||||
cat << 'EOF' > "/etc/profile.d/figurine.sh"
|
||||
/usr/local/bin/figurine -f "3d.flf" $(hostname)
|
||||
EOF
|
||||
chmod +x "/etc/profile.d/figurine.sh"
|
||||
)
|
||||
`}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Create VM: System NAS | ProxMenux Documentation",
|
||||
"description": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS. Umbrel OS is available via community script.",
|
||||
"description": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS and FygoOS. Umbrel OS is available via community script.",
|
||||
"ogTitle": "Create VM: System NAS | ProxMenux Documentation",
|
||||
"ogDescription": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS.",
|
||||
"ogDescription": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS and FygoOS.",
|
||||
"ogImageAlt": "ProxMenux System NAS Menu"
|
||||
},
|
||||
"header": {
|
||||
"title": "Create VM: System NAS",
|
||||
"description": "ProxMenux supports seven NAS operating systems as dedicated VMs, plus an optional Umbrel OS path via a community script. Most systems share the same auto-ISO flow; Synology DSM uses a specialised loader wizard.",
|
||||
"description": "ProxMenux supports eight NAS operating systems as dedicated VMs, plus an optional Umbrel OS path via a community script. Most systems share the same auto-ISO flow; Synology DSM uses a specialised loader wizard.",
|
||||
"section": "Virtual Machines"
|
||||
},
|
||||
"intro": {
|
||||
@@ -94,12 +94,21 @@
|
||||
"fileSystem": "ext4",
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others#zimaos",
|
||||
"flow": "dedicated"
|
||||
},
|
||||
{
|
||||
"name": "FygoOS",
|
||||
"tagline": "International edition of fnOS: a Debian-based NAS with storage volumes, apps and media streaming, managed from its web interface and the Fygo apps.",
|
||||
"icon": "Server",
|
||||
"base": "Debian Linux",
|
||||
"fileSystem": "Btrfs, ext4",
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others#fygoos",
|
||||
"flow": "auto-iso"
|
||||
}
|
||||
]
|
||||
},
|
||||
"umbrel": {
|
||||
"title": "Community option: Umbrel OS",
|
||||
"bodyRich": "The 8th entry in the NAS menu is <strong>Umbrel OS</strong>. It runs a <umbrelLink>community-scripts installer</umbrelLink> maintained outside ProxMenux, so it is not documented here. The installer handles the entire lifecycle and prints its default credentials at the end."
|
||||
"bodyRich": "The 9th entry in the NAS menu is <strong>Umbrel OS</strong>. It runs a <umbrelLink>community-scripts installer</umbrelLink> maintained outside ProxMenux, so it is not documented here. The installer handles the entire lifecycle and prints its default credentials at the end."
|
||||
},
|
||||
"zfsMem": {
|
||||
"title": "ZFS memory rule of thumb",
|
||||
@@ -116,7 +125,7 @@
|
||||
{
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others",
|
||||
"label": "Other System NAS",
|
||||
"tail": " — TrueNAS, OpenMediaVault, Rockstor, XigmaNAS and similar."
|
||||
"tail": " — TrueNAS, OpenMediaVault, Rockstor, XigmaNAS, FygoOS and similar."
|
||||
},
|
||||
{
|
||||
"href": "/docs/disk-manager/import-disk-vm",
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Create VM: Other NAS Systems | ProxMenux Documentation",
|
||||
"description": "Create TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS virtual machines on Proxmox VE with ProxMenux. Covers default / advanced configuration, the new storage plan, optional GPU passthrough and per-system recommended specs.",
|
||||
"description": "Create TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS and FygoOS virtual machines on Proxmox VE with ProxMenux. Covers default / advanced configuration, the new storage plan, optional GPU passthrough and per-system recommended specs.",
|
||||
"ogTitle": "Create VM: Other NAS Systems | ProxMenux Documentation",
|
||||
"ogDescription": "Create TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS VMs on Proxmox VE with ProxMenux.",
|
||||
"ogDescription": "Create TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS and FygoOS VMs on Proxmox VE with ProxMenux.",
|
||||
"ogImageAlt": "ProxMenux NAS selector"
|
||||
},
|
||||
"header": {
|
||||
"title": "Create VM: Other NAS Systems",
|
||||
"description": "ProxMenux can create a ready-to-install VM for TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS. This page covers the shared creation flow (default / advanced configuration, the new storage plan, optional GPU passthrough) plus per-system notes and recommended specs.",
|
||||
"description": "ProxMenux can create a ready-to-install VM for TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS and FygoOS. This page covers the shared creation flow (default / advanced configuration, the new storage plan, optional GPU passthrough) plus per-system notes and recommended specs.",
|
||||
"section": "Virtual Machines · NAS"
|
||||
},
|
||||
"intro": {
|
||||
"title": "How these systems are created",
|
||||
"bodyRich": "All six systems share the same ProxMenux wizard. The NAS selector picks the matching installer (auto-detecting the latest stable version for TrueNAS, OMV, XigmaNAS and Rockstor) and then hands over to the generic VM configurator and the storage plan. ZimaOS uses its own installer script (<code>vm/zimaos.sh</code>) but follows the same CPU / RAM / storage / optional-GPU sequence."
|
||||
"bodyRich": "All seven systems share the same ProxMenux wizard. The NAS selector picks the matching installer (auto-detecting the latest stable version for TrueNAS, OMV, XigmaNAS, Rockstor and FygoOS) and then hands over to the generic VM configurator and the storage plan. ZimaOS uses its own installer script (<code>vm/zimaos.sh</code>) but follows the same CPU / RAM / storage / optional-GPU sequence."
|
||||
},
|
||||
"config": {
|
||||
"heading": "Default vs Advanced configuration",
|
||||
@@ -262,6 +262,21 @@
|
||||
"UEFI (OVMF) boot",
|
||||
"VirtIO network adapter for best throughput"
|
||||
]
|
||||
},
|
||||
"fygoos": {
|
||||
"id": "fygoos",
|
||||
"title": "FygoOS",
|
||||
"icon": "Server",
|
||||
"officialName": "fygonas.com",
|
||||
"officialUrl": "https://fygonas.com",
|
||||
"description": "International edition of fnOS, a Debian-based NAS. ProxMenux downloads the latest installer ISO published on fygonas.com and mounts it in the VM. The installer puts the system on one disk; the space left on that disk can hold volumes for apps and files. After the installation, the console shows the address of the web interface, on port 5666 (port 80 redirects to it): open it in a browser to name the device and create the administrator account.",
|
||||
"specs": [
|
||||
"System disk: FygoOS proposes a 64 GB system partition, which can be smaller in a VM",
|
||||
"Installation: Graphical Install, or Rescuing Install if the graphical one fails",
|
||||
"UEFI (OVMF) boot without Secure Boot keys, as the installer requires",
|
||||
"Network: Ethernet with DHCP by default",
|
||||
"VirtIO network adapter for best throughput"
|
||||
]
|
||||
}
|
||||
},
|
||||
"related": {
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
"table": {
|
||||
"headers": ["Option", "What it reads"],
|
||||
"rows": [
|
||||
["Paste its Compose file in the terminal", "The YAML is pasted in the terminal and ends with Ctrl+D on an empty line."],
|
||||
["Paste its Compose file in the terminal", "The YAML is pasted in the terminal and ends with Ctrl+D."],
|
||||
["Read its Compose file from a file of this host", "A path on the node, <code>/root/docker-compose.yml</code> by default. The file must exist and be at most 256 KiB."],
|
||||
["Download its Compose file from an address", "An <code>http://</code> or <code>https://</code> address that serves the raw YAML. At most 256 KiB are downloaded."],
|
||||
["Paste its docker run command in the terminal", "The command published by the project. Ports, environment, volumes, devices, capabilities, user, shared memory and the other supported options are translated."],
|
||||
["Only the image reference, with no Compose file", "A reference such as <code>ghcr.io/user/application:latest</code>. The registry is queried and the OCI metadata of the image is kept."],
|
||||
["Paste an oci-compose in the terminal", "The JSON is pasted in the terminal and ends with Ctrl+D on an empty line. It is not translated: it is checked and installed as it is written."],
|
||||
["Paste an oci-compose in the terminal", "The JSON is pasted in the terminal and ends with Ctrl+D. It is not translated: it is checked and installed as it is written."],
|
||||
["Read an oci-compose from a file of this host", "A JSON file on the node, <code>/root/oci-compose.json</code> by default, of at most 2 MiB."],
|
||||
["Download an oci-compose from an address", "An <code>http://</code> or <code>https://</code> address that serves the JSON file. At most 2 MiB are downloaded."]
|
||||
]
|
||||
@@ -76,7 +76,7 @@
|
||||
"steps": {
|
||||
"items": [
|
||||
{ "title": "Analyse", "body": "Services, image, ports, paths, environment, devices, security and healthcheck are read." },
|
||||
{ "title": "Query the registry", "body": "The image must exist in a public registry, and its published architectures are listed." },
|
||||
{ "title": "Query the registry", "body": "The image must exist in its registry, and its published architectures are listed. A private registry is read with the account saved for it." },
|
||||
{ "title": "List what is not applied", "body": "Labels, Docker networks, Swarm settings and other keys that have no effect on an LXC are listed." },
|
||||
{ "title": "Block what cannot be translated", "body": "A key with no safe equivalent is shown under <strong>What cannot be translated</strong> and the installation does not continue. Nothing is dropped silently." },
|
||||
{ "title": "Ask for secrets", "body": "Variables whose names read as a password, token or key become sensitive questions of the installation." }
|
||||
@@ -152,6 +152,38 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "private-registries",
|
||||
"title": "Images in private registries",
|
||||
"intro": "An image in a private registry, such as a private package on GitHub or a private repository on Docker Hub, is read with an account saved in ProxMenux.",
|
||||
"blocks": [
|
||||
{
|
||||
"steps": {
|
||||
"items": [
|
||||
{ "title": "The registry refuses the image", "body": "When the registry answers that the image needs an account, the review offers to sign in to that registry and reads the image again." },
|
||||
{ "title": "Sign in", "body": "A user and a password or access token that can pull the image. The registry checks them, and they are saved only if it accepts them." },
|
||||
{ "title": "Install and keep up to date", "body": "The installation downloads the image with that account, and so do updates, Modify, Recreate, the watchdog and the update check of the Monitor, on any node of the cluster." }
|
||||
]
|
||||
}
|
||||
},
|
||||
{ "p": "<strong>Registry accounts</strong>, in the main menu of OCI manager Apps, lists the saved accounts by registry and user, never their secret. From each account an image can be checked, downloaded or installed, and the account updated or removed." },
|
||||
{
|
||||
"list": {
|
||||
"items": [
|
||||
"GitHub (<code>ghcr.io</code>): the user is the GitHub account, and the password a personal access token with the <code>read:packages</code> permission.",
|
||||
"Docker Hub (<code>docker.io</code>): the user is the Docker Hub account, and the password an access token with read permission.",
|
||||
"Other registries, including one with its own port such as <code>registry.example.com:5000</code>: the user and password or token that registry gives."
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"calloutInfo": {
|
||||
"title": "Where the accounts are kept",
|
||||
"body": "In <code>/etc/pve/priv/proxmenux/registry-auth.json</code>, readable only by root, in the same folder where Proxmox keeps its storage passwords. <code>/etc/pve</code> is shared by every node of the cluster, so an account added on one node is used on all of them. The host backup includes it, and uninstalling ProxMenux removes it from every node."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "limits",
|
||||
"title": "Definitions that are not installed",
|
||||
@@ -159,7 +191,6 @@
|
||||
{
|
||||
"list": {
|
||||
"items": [
|
||||
"Images in private registries: registry credentials are not requested.",
|
||||
"A Dockerfile without a published image: the image has to be built and published in an OCI registry first.",
|
||||
"A Compose file with several services: it is blocked because it describes more than one image. This option installs a single container.",
|
||||
"<code>configs</code>, external secrets or device formats that cannot be translated unambiguously.",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"<strong>Search applications</strong> — search by name across the catalog.",
|
||||
"<strong>All applications</strong> — the complete catalog, with the number of applications.",
|
||||
"<strong>Manage installed OCI applications</strong> — update, modify, remove or recover what was installed.",
|
||||
"<strong>Registry accounts</strong> — the accounts used to install and update images from private registries.",
|
||||
"<strong>Install an image that is not in the catalog</strong> — translate a Compose file, a <code>docker run</code> command or an image reference.",
|
||||
"The catalog categories, each with its number of applications."
|
||||
]
|
||||
|
||||
@@ -119,9 +119,9 @@
|
||||
"intro": "This option installs and configures Figurine, a tool that creates stylish ASCII text banners for your terminal, displaying your hostname in a visually appealing 3D format.",
|
||||
"doesLabel": "What it does:",
|
||||
"doesItems": [
|
||||
"Downloads and installs Figurine v2.0.0 from GitHub",
|
||||
"Downloads and installs Figurine v2.1.1 from GitHub for the host architecture (AMD64, ARM64 or ARMv7)",
|
||||
"Creates a welcome message that displays your hostname in 3D ASCII art when you log in",
|
||||
"Automatically removes any previous Figurine installation if present",
|
||||
"Updates an existing Figurine binary after download and extraction succeed",
|
||||
"Sets up the welcome message to run automatically at login"
|
||||
],
|
||||
"practicalLabel": "Practical Use:",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Crear VM: System NAS | ProxMenux Documentation",
|
||||
"description": "Crea máquinas virtuales NAS en Proxmox VE con ProxMenux. Soporta Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor y ZimaOS. Umbrel OS está disponible vía community script.",
|
||||
"description": "Crea máquinas virtuales NAS en Proxmox VE con ProxMenux. Soporta Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS y FygoOS. Umbrel OS está disponible vía community script.",
|
||||
"ogTitle": "Crear VM: System NAS | ProxMenux Documentation",
|
||||
"ogDescription": "Crea máquinas virtuales NAS en Proxmox VE con ProxMenux. Soporta Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor y ZimaOS.",
|
||||
"ogDescription": "Crea máquinas virtuales NAS en Proxmox VE con ProxMenux. Soporta Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS y FygoOS.",
|
||||
"ogImageAlt": "Menú System NAS de ProxMenux"
|
||||
},
|
||||
"header": {
|
||||
"title": "Crear VM: System NAS",
|
||||
"description": "ProxMenux soporta siete sistemas operativos NAS como VMs específicas, más una ruta opcional para Umbrel OS vía community script. La mayoría de sistemas comparten el mismo flujo auto-ISO; Synology DSM usa un asistente de loader especializado.",
|
||||
"description": "ProxMenux soporta ocho sistemas operativos NAS como VMs específicas, más una ruta opcional para Umbrel OS vía community script. La mayoría de sistemas comparten el mismo flujo auto-ISO; Synology DSM usa un asistente de loader especializado.",
|
||||
"section": "Máquinas virtuales"
|
||||
},
|
||||
"intro": {
|
||||
@@ -94,12 +94,21 @@
|
||||
"fileSystem": "ext4",
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others#zimaos",
|
||||
"flow": "dedicated"
|
||||
},
|
||||
{
|
||||
"name": "FygoOS",
|
||||
"tagline": "Edición internacional de fnOS: un NAS basado en Debian con volúmenes de almacenamiento, apps y streaming multimedia, gestionado desde su interfaz web y las apps de Fygo.",
|
||||
"icon": "Server",
|
||||
"base": "Debian Linux",
|
||||
"fileSystem": "Btrfs, ext4",
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others#fygoos",
|
||||
"flow": "auto-iso"
|
||||
}
|
||||
]
|
||||
},
|
||||
"umbrel": {
|
||||
"title": "Opción de la comunidad: Umbrel OS",
|
||||
"bodyRich": "La 8ª entrada del menú NAS es <strong>Umbrel OS</strong>. Ejecuta un <umbrelLink>instalador de community-scripts</umbrelLink> mantenido fuera de ProxMenux, así que no se documenta aquí. El instalador gestiona el ciclo de vida completo y muestra sus credenciales por defecto al final."
|
||||
"bodyRich": "La 9ª entrada del menú NAS es <strong>Umbrel OS</strong>. Ejecuta un <umbrelLink>instalador de community-scripts</umbrelLink> mantenido fuera de ProxMenux, así que no se documenta aquí. El instalador gestiona el ciclo de vida completo y muestra sus credenciales por defecto al final."
|
||||
},
|
||||
"zfsMem": {
|
||||
"title": "Regla rápida de memoria para ZFS",
|
||||
@@ -116,7 +125,7 @@
|
||||
{
|
||||
"href": "/docs/create-vm/system-nas/system-nas-others",
|
||||
"label": "Otros System NAS",
|
||||
"tail": " — TrueNAS, OpenMediaVault, Rockstor, XigmaNAS y similares."
|
||||
"tail": " — TrueNAS, OpenMediaVault, Rockstor, XigmaNAS, FygoOS y similares."
|
||||
},
|
||||
{
|
||||
"href": "/docs/disk-manager/import-disk-vm",
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"title": "Crear VM: Otros sistemas NAS | ProxMenux Documentation",
|
||||
"description": "Crea máquinas virtuales de TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor y ZimaOS en Proxmox VE con ProxMenux. Cubre la configuración por defecto / avanzada, el nuevo plan de almacenamiento, el passthrough de GPU opcional y las specs recomendadas por sistema.",
|
||||
"description": "Crea máquinas virtuales de TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS y FygoOS en Proxmox VE con ProxMenux. Cubre la configuración por defecto / avanzada, el nuevo plan de almacenamiento, el passthrough de GPU opcional y las specs recomendadas por sistema.",
|
||||
"ogTitle": "Crear VM: Otros sistemas NAS | ProxMenux Documentation",
|
||||
"ogDescription": "Crea VMs de TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor y ZimaOS en Proxmox VE con ProxMenux.",
|
||||
"ogDescription": "Crea VMs de TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS y FygoOS en Proxmox VE con ProxMenux.",
|
||||
"ogImageAlt": "Selector NAS de ProxMenux"
|
||||
},
|
||||
"header": {
|
||||
"title": "Crear VM: Otros sistemas NAS",
|
||||
"description": "ProxMenux puede crear una VM lista para instalar TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor y ZimaOS. Esta página cubre el flujo de creación compartido (configuración por defecto / avanzada, el nuevo plan de almacenamiento, passthrough de GPU opcional) más notas por sistema y specs recomendadas.",
|
||||
"description": "ProxMenux puede crear una VM lista para instalar TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor, ZimaOS y FygoOS. Esta página cubre el flujo de creación compartido (configuración por defecto / avanzada, el nuevo plan de almacenamiento, passthrough de GPU opcional) más notas por sistema y specs recomendadas.",
|
||||
"section": "Máquinas virtuales · NAS"
|
||||
},
|
||||
"intro": {
|
||||
"title": "Cómo se crean estos sistemas",
|
||||
"bodyRich": "Los seis sistemas comparten el mismo asistente de ProxMenux. El selector de NAS elige el instalador correspondiente (autodetectando la última versión estable para TrueNAS, OMV, XigmaNAS y Rockstor) y luego cede el control al configurador genérico de VM y al plan de almacenamiento. ZimaOS usa su propio script de instalador (<code>vm/zimaos.sh</code>) pero sigue la misma secuencia de CPU / RAM / almacenamiento / GPU opcional."
|
||||
"bodyRich": "Los siete sistemas comparten el mismo asistente de ProxMenux. El selector de NAS elige el instalador correspondiente (autodetectando la última versión estable para TrueNAS, OMV, XigmaNAS, Rockstor y FygoOS) y luego cede el control al configurador genérico de VM y al plan de almacenamiento. ZimaOS usa su propio script de instalador (<code>vm/zimaos.sh</code>) pero sigue la misma secuencia de CPU / RAM / almacenamiento / GPU opcional."
|
||||
},
|
||||
"config": {
|
||||
"heading": "Configuración por defecto vs Avanzada",
|
||||
@@ -262,6 +262,21 @@
|
||||
"Arranque UEFI (OVMF)",
|
||||
"Adaptador de red VirtIO para mejor throughput"
|
||||
]
|
||||
},
|
||||
"fygoos": {
|
||||
"id": "fygoos",
|
||||
"title": "FygoOS",
|
||||
"icon": "Server",
|
||||
"officialName": "fygonas.com",
|
||||
"officialUrl": "https://fygonas.com",
|
||||
"description": "Edición internacional de fnOS, un NAS basado en Debian. ProxMenux descarga la última ISO de instalación publicada en fygonas.com y la monta en la VM. El instalador coloca el sistema en un disco; el espacio que queda en ese disco puede alojar volúmenes para apps y archivos. Al terminar la instalación, la consola muestra la dirección de la interfaz web, en el puerto 5666 (el puerto 80 redirige a él): al abrirla en el navegador se da nombre al equipo y se crea la cuenta de administrador.",
|
||||
"specs": [
|
||||
"Disco del sistema: FygoOS propone una partición de sistema de 64 GB, que puede ser menor en una VM",
|
||||
"Instalación: Graphical Install, o Rescuing Install si la gráfica falla",
|
||||
"Arranque UEFI (OVMF) sin claves de Secure Boot, como pide el instalador",
|
||||
"Red: Ethernet con DHCP por defecto",
|
||||
"Adaptador de red VirtIO para mejor throughput"
|
||||
]
|
||||
}
|
||||
},
|
||||
"related": {
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
"table": {
|
||||
"headers": ["Opción", "Qué lee"],
|
||||
"rows": [
|
||||
["Pegar su archivo Compose en la terminal", "El YAML se pega en la terminal y termina con Ctrl+D en una línea vacía."],
|
||||
["Pegar su archivo Compose en la terminal", "El YAML se pega en la terminal y termina con Ctrl+D."],
|
||||
["Leer su archivo Compose desde un archivo de este host", "Una ruta del nodo, <code>/root/docker-compose.yml</code> por defecto. El archivo debe existir y ocupar como máximo 256 KiB."],
|
||||
["Descargar su archivo Compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el YAML sin procesar. Se descargan como máximo 256 KiB."],
|
||||
["Pegar su comando docker run en la terminal", "El comando que publica el proyecto. Se traducen puertos, entorno, volúmenes, dispositivos, capacidades, usuario, memoria compartida y el resto de opciones admitidas."],
|
||||
["Solo la referencia de la imagen, sin archivo Compose", "Una referencia como <code>ghcr.io/user/application:latest</code>. Se consulta el registro y se conservan los metadatos OCI de la imagen."],
|
||||
["Pegar un oci-compose en la terminal", "El JSON se pega en la terminal y termina con Ctrl+D en una línea vacía. No se traduce: se comprueba y se instala tal como está escrito."],
|
||||
["Pegar un oci-compose en la terminal", "El JSON se pega en la terminal y termina con Ctrl+D. No se traduce: se comprueba y se instala tal como está escrito."],
|
||||
["Leer un oci-compose desde un archivo de este host", "Un archivo JSON del nodo, <code>/root/oci-compose.json</code> por defecto, de 2 MiB como máximo."],
|
||||
["Descargar un oci-compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el archivo JSON. Se descargan como máximo 2 MiB."]
|
||||
]
|
||||
@@ -76,7 +76,7 @@
|
||||
"steps": {
|
||||
"items": [
|
||||
{ "title": "Analizar", "body": "Se leen servicios, imagen, puertos, rutas, entorno, dispositivos, seguridad y healthcheck." },
|
||||
{ "title": "Consultar el registro", "body": "La imagen debe existir en un registro público, y se enumeran las arquitecturas que publica." },
|
||||
{ "title": "Consultar el registro", "body": "La imagen debe existir en su registro, y se enumeran las arquitecturas que publica. Un registro privado se lee con la cuenta guardada para él." },
|
||||
{ "title": "Enumerar lo que no se aplica", "body": "Se enumeran las etiquetas, las redes Docker, los ajustes de Swarm y el resto de claves que no tienen efecto en un LXC." },
|
||||
{ "title": "Bloquear lo que no puede traducirse", "body": "Una clave sin equivalencia segura aparece en <strong>Lo que no puede traducirse</strong> y la instalación no continúa. Nada se descarta en silencio." },
|
||||
{ "title": "Pedir los secretos", "body": "Las variables cuyo nombre corresponde a una contraseña, un token o una clave se convierten en preguntas sensibles de la instalación." }
|
||||
@@ -152,6 +152,38 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "private-registries",
|
||||
"title": "Imágenes en registros privados",
|
||||
"intro": "Una imagen en un registro privado, como un paquete privado de GitHub o un repositorio privado de Docker Hub, se lee con una cuenta guardada en ProxMenux.",
|
||||
"blocks": [
|
||||
{
|
||||
"steps": {
|
||||
"items": [
|
||||
{ "title": "El registro rechaza la imagen", "body": "Cuando el registro responde que la imagen necesita una cuenta, la revisión ofrece iniciar sesión en ese registro y vuelve a leer la imagen." },
|
||||
{ "title": "Iniciar sesión", "body": "Un usuario y una contraseña o un token de acceso que puedan descargar la imagen. El registro los comprueba y solo se guardan si los acepta." },
|
||||
{ "title": "Instalar y mantener al día", "body": "La instalación descarga la imagen con esa cuenta, y también las actualizaciones, Modificar, Recrear, la vigilancia y la comprobación de actualizaciones del Monitor, en cualquier nodo del clúster." }
|
||||
]
|
||||
}
|
||||
},
|
||||
{ "p": "<strong>Cuentas de registro</strong>, en el menú principal de OCI manager Apps, lista las cuentas guardadas por registro y usuario, nunca su secreto. Desde cada cuenta se puede comprobar, descargar o instalar una imagen, y actualizar o eliminar la cuenta." },
|
||||
{
|
||||
"list": {
|
||||
"items": [
|
||||
"GitHub (<code>ghcr.io</code>): el usuario es la cuenta de GitHub, y la contraseña un token de acceso personal con el permiso <code>read:packages</code>.",
|
||||
"Docker Hub (<code>docker.io</code>): el usuario es la cuenta de Docker Hub, y la contraseña un token de acceso con permiso de lectura.",
|
||||
"Otros registros, también uno con su propio puerto como <code>registry.example.com:5000</code>: el usuario y la contraseña o token que da ese registro."
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"calloutInfo": {
|
||||
"title": "Dónde se guardan",
|
||||
"body": "En <code>/etc/pve/priv/proxmenux/registry-auth.json</code>, legible solo por root, en la misma carpeta donde Proxmox guarda las contraseñas de sus almacenamientos. <code>/etc/pve</code> lo comparten todos los nodos del clúster, así que una cuenta añadida en un nodo se usa en todos. El backup del host lo incluye, y al desinstalar ProxMenux se elimina de todos los nodos."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "limits",
|
||||
"title": "Definiciones que no se instalan",
|
||||
@@ -159,7 +191,6 @@
|
||||
{
|
||||
"list": {
|
||||
"items": [
|
||||
"Imágenes en registros privados: no se piden credenciales del registro.",
|
||||
"Un Dockerfile sin imagen publicada: la imagen debe construirse y publicarse antes en un registro OCI.",
|
||||
"Un archivo Compose con varios servicios: queda bloqueado porque describe más de una imagen. Esta opción instala un único contenedor.",
|
||||
"<code>configs</code>, secretos externos o formatos de dispositivo que no pueden traducirse sin ambigüedad.",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"<strong>Buscar aplicaciones</strong>: búsqueda por nombre en todo el catálogo.",
|
||||
"<strong>Todas las aplicaciones</strong>: el catálogo completo, con el número de aplicaciones.",
|
||||
"<strong>Gestionar aplicaciones OCI instaladas</strong>: actualizar, modificar, eliminar o recuperar lo instalado.",
|
||||
"<strong>Cuentas de registro</strong>: las cuentas con las que se instalan y actualizan imágenes de registros privados.",
|
||||
"<strong>Instalar una imagen que no está en el catálogo</strong>: traducción de un archivo Compose, un comando <code>docker run</code> o una referencia de imagen.",
|
||||
"Las categorías del catálogo, cada una con su número de aplicaciones."
|
||||
]
|
||||
|
||||
@@ -119,9 +119,9 @@
|
||||
"intro": "Esta opción instala y configura Figurine, una herramienta que crea banners de texto ASCII con estilo para tu terminal, mostrando tu hostname en un formato 3D atractivo visualmente.",
|
||||
"doesLabel": "Qué hace:",
|
||||
"doesItems": [
|
||||
"Descarga e instala Figurine v2.0.0 desde GitHub",
|
||||
"Descarga e instala Figurine v2.1.1 desde GitHub para la arquitectura del host (AMD64, ARM64 o ARMv7)",
|
||||
"Crea un mensaje de bienvenida que muestra tu hostname en ASCII art 3D al hacer login",
|
||||
"Elimina automáticamente cualquier instalación previa de Figurine si la hay",
|
||||
"Actualiza el binario existente de Figurine tras descargar y extraer el paquete correctamente",
|
||||
"Configura el mensaje de bienvenida para que se ejecute automáticamente al hacer login"
|
||||
],
|
||||
"practicalLabel": "Uso práctico:",
|
||||
|
||||
Reference in New Issue
Block a user