mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-29 10:06:41 +00:00
Merge remote-tracking branch 'origin/develop' into beta/1.2.6.2
This commit is contained in:
@@ -0,0 +1,145 @@
|
|||||||
|
"""Offline, bounded real Bash consumers: no administrative entrypoints are sourced."""
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[3]
|
||||||
|
SCRIPTS = ROOT / 'scripts'
|
||||||
|
NETWORK = {
|
||||||
|
'share/iscsi_host.sh': 1,
|
||||||
|
'share/nfs_client.sh': 1,
|
||||||
|
'share/nfs_host.sh': 2,
|
||||||
|
'share/samba_client.sh': 1,
|
||||||
|
'share/samba_host.sh': 2,
|
||||||
|
}
|
||||||
|
MOUNT = 'Mounting existing filesystem ({filesystem})...'
|
||||||
|
RAID = 'If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.'
|
||||||
|
|
||||||
|
|
||||||
|
def function(text, name):
|
||||||
|
start = text.index(name + '() {')
|
||||||
|
return text[start:text.index('\n}', start) + 2] + '\n'
|
||||||
|
|
||||||
|
|
||||||
|
def network_blocks(path):
|
||||||
|
lines = path.read_text().splitlines()
|
||||||
|
blocks = []
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if re.search(r'^\s*if (?:pct exec .* -- )?nc -z -w 2 ', line):
|
||||||
|
depth = len(line) - len(line.lstrip())
|
||||||
|
end = next(j for j in range(i + 1, len(lines))
|
||||||
|
if lines[j].strip() == 'fi' and len(lines[j]) - len(lines[j].lstrip()) == depth)
|
||||||
|
block = '\n'.join(lines[i:end + 1])
|
||||||
|
assert '$(translate "Open")' in block and '$(translate "Closed")' in block or '$(translate "Probe failed")' in block
|
||||||
|
blocks.append(block)
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
|
||||||
|
def run(code, translations=None, statuses='1', variables='', dialog=False):
|
||||||
|
translations = translations or {}
|
||||||
|
with tempfile.TemporaryDirectory(prefix='tui-wording-') as directory:
|
||||||
|
root = Path(directory)
|
||||||
|
(root / 'xx.json').write_text(json.dumps(translations))
|
||||||
|
body = f'''LANGUAGE=xx LANG_DIR={root!s}
|
||||||
|
{function((SCRIPTS / 'utils.sh').read_text(), 'translate')}
|
||||||
|
GN='\\033[32m' RD='\\033[31m' CL='\\033[0m'
|
||||||
|
{variables}
|
||||||
|
statuses=({statuses})
|
||||||
|
nc() {{ local code=${{statuses[0]}}; statuses=("${{statuses[@]:1}}"); return "$code"; }}
|
||||||
|
pct() {{ [[ "$1" == exec && "$3" == -- && "$4" == nc ]] || return 98; shift 3; nc "$@"; }}
|
||||||
|
msg_info() {{ printf 'INFO:%s\\n' "$1"; }}
|
||||||
|
msg_error() {{ printf 'ERROR:%s\\n' "$1"; }}
|
||||||
|
msg_ok() {{ printf 'OK:%s\\n' "$1"; }}
|
||||||
|
msg_title() {{ :; }}
|
||||||
|
show_proxmenux_logo() {{ :; }}
|
||||||
|
pmx_journal_context() {{ :; }}
|
||||||
|
blkid() {{ [[ "$2" == TYPE ]] && printf 'ext4\\n' || printf 'UUID123\\n'; }}
|
||||||
|
mkdir() {{ :; }}
|
||||||
|
mount() {{ return 1; }}
|
||||||
|
dialog() {{ printf 'DIALOG:%s\\n' "$*"; }}
|
||||||
|
{code}
|
||||||
|
'''
|
||||||
|
result = subprocess.run(['/bin/bash', '--noprofile', '--norc', '-c', body],
|
||||||
|
env={'PATH': '/usr/bin:/bin', 'LC_ALL': 'C.UTF-8'},
|
||||||
|
capture_output=True, text=True, timeout=10)
|
||||||
|
if result.returncode or result.stderr:
|
||||||
|
raise AssertionError((result.returncode, result.stderr, result.stdout))
|
||||||
|
return result.stdout
|
||||||
|
|
||||||
|
|
||||||
|
class TuiNetworkStorageWording(unittest.TestCase):
|
||||||
|
def test_failed_tcp_probe_is_not_declared_closed_at_every_caller(self):
|
||||||
|
for path, count in NETWORK.items():
|
||||||
|
blocks = network_blocks(SCRIPTS / path)
|
||||||
|
self.assertEqual(len(blocks), count, path)
|
||||||
|
for index, block in enumerate(blocks):
|
||||||
|
cases = [('0 1', 'Open'), ('1 1', 'Probe failed'), ('124 124', 'Probe failed')]
|
||||||
|
if 'samba_' in path:
|
||||||
|
cases.append(('1 0', 'Open'))
|
||||||
|
for codes, expected in cases:
|
||||||
|
with self.subTest(path=path, index=index, codes=codes):
|
||||||
|
output = run(block, statuses=codes, translations={'Probe failed': 'SONDAGGIO FALLITO'})
|
||||||
|
self.assertIn('SONDAGGIO FALLITO' if expected == 'Probe failed' else 'Open', output)
|
||||||
|
self.assertNotIn('Closed', output)
|
||||||
|
if expected == 'Open':
|
||||||
|
self.assertNotIn('SONDAGGIO FALLITO', output)
|
||||||
|
else:
|
||||||
|
fallback = run(block, statuses=codes)
|
||||||
|
self.assertIn('Probe failed', fallback)
|
||||||
|
self.assertNotIn('Closed', fallback)
|
||||||
|
|
||||||
|
def test_mount_progress_is_whole_and_uses_real_lookup_with_fallback(self):
|
||||||
|
source = (SCRIPTS / 'share/disk_host.sh').read_text()
|
||||||
|
start = source.index('mount_existing_disk() {')
|
||||||
|
portion = source[start:source.index(' if ! mount "$disk"', start)] + ' return 0\n}\n'
|
||||||
|
for translation, expected in [({}, MOUNT.replace('{filesystem}', 'ext4')),
|
||||||
|
({MOUNT: 'SYNTHETIC {filesystem} in corso'}, 'SYNTHETIC ext4 in corso'),
|
||||||
|
({MOUNT: 'SYNTHETIC malformed'}, MOUNT.replace('{filesystem}', 'ext4'))]:
|
||||||
|
with self.subTest(translation=translation):
|
||||||
|
output = run(portion + '\nmount_existing_disk /dev/fixture /mnt/fixture', translations=translation)
|
||||||
|
self.assertIn('INFO:' + expected, output)
|
||||||
|
self.assertNotIn('{filesystem}', output)
|
||||||
|
|
||||||
|
def test_raid_warning_is_complete_message_with_disk_identifier_and_fallback(self):
|
||||||
|
source = (SCRIPTS / 'storage/disk-passthrough_ct.sh').read_text().splitlines()
|
||||||
|
invocation = '\n'.join(source[457:460]) # original dialog invocation, not the raid detection command
|
||||||
|
for translation, expected in [({}, RAID), ({RAID: 'SYNTHETIC RAID metadata remains'}, 'SYNTHETIC RAID metadata remains')]:
|
||||||
|
with self.subTest(translation=translation):
|
||||||
|
output = run(invocation, translations=translation,
|
||||||
|
variables="BACKTITLE=fixture DISK_INFO='/dev/fixture 2TiB' UI_RESULT_H=16 UI_RESULT_W=80")
|
||||||
|
self.assertIn(expected, output)
|
||||||
|
self.assertIn('/dev/fixture 2TiB', output)
|
||||||
|
self.assertNotIn('remove the RAID metadata or format it manually using external tools. RAID metadata', output)
|
||||||
|
|
||||||
|
def test_shipped_catalogs_use_english_fallback_for_new_keys(self):
|
||||||
|
catalogs = sorted((ROOT / 'lang').glob('*.json'))
|
||||||
|
self.assertTrue(catalogs)
|
||||||
|
block = network_blocks(SCRIPTS / 'share/iscsi_host.sh')[0]
|
||||||
|
source = (SCRIPTS / 'share/disk_host.sh').read_text()
|
||||||
|
start = source.index('mount_existing_disk() {')
|
||||||
|
mount = source[start:source.index(' if ! mount "$disk"', start)] + ' return 0\n}\nmount_existing_disk /dev/fixture /mnt/fixture'
|
||||||
|
raid = '\n'.join((SCRIPTS / 'storage/disk-passthrough_ct.sh').read_text().splitlines()[457:460])
|
||||||
|
for path in catalogs:
|
||||||
|
with self.subTest(locale=path.name):
|
||||||
|
catalog = json.loads(path.read_text())
|
||||||
|
self.assertIn(catalog.get('Probe failed') or 'Probe failed', run(block, statuses='1', translations=catalog))
|
||||||
|
self.assertIn((catalog.get(MOUNT) or MOUNT).replace('{filesystem}', 'ext4'), run(mount, translations=catalog))
|
||||||
|
self.assertIn(catalog.get(RAID) or RAID, run(raid, translations=catalog,
|
||||||
|
variables="BACKTITLE=fixture DISK_INFO='/dev/fixture' UI_RESULT_H=16 UI_RESULT_W=80"))
|
||||||
|
|
||||||
|
def test_extractor_discovers_whole_keys(self):
|
||||||
|
spec = importlib.util.spec_from_file_location('cache_builder', ROOT / '.github/scripts/build_translation_cache.py')
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
keys = module.extract_translate_texts(SCRIPTS)
|
||||||
|
for key in (MOUNT, RAID, 'Probe failed'):
|
||||||
|
self.assertTrue(key in keys, key)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
"""Run the inert Node TUI consumer fixture in the existing offline i18n lane."""
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[3]
|
||||||
|
|
||||||
|
|
||||||
|
class TuiUpgradeGpuWording(unittest.TestCase):
|
||||||
|
def test_source_extracted_node_consumer(self):
|
||||||
|
fixture = ROOT / 'tests/test_tui_upgrade_gpu_wording.cjs'
|
||||||
|
self.assertTrue(fixture.is_file(), 'Node fixture must be packaged with the candidate')
|
||||||
|
node = os.environ.get('NODE_BINARY') or 'node'
|
||||||
|
result = subprocess.run([node, str(fixture)], cwd=ROOT, capture_output=True,
|
||||||
|
text=True, timeout=60, env={**os.environ, 'PYTHONDONTWRITEBYTECODE': '1'})
|
||||||
|
self.assertEqual(result.returncode, 0, result.stdout + '\n' + result.stderr)
|
||||||
|
self.assertIn('PASS: extracted upgrade/GPU consumers', result.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -27,6 +27,7 @@ import { AppUpdaterEditor, type AppUpdateMethod } from "./app-updater-editor"
|
|||||||
import { formatStorage } from "../lib/utils"
|
import { formatStorage } from "../lib/utils"
|
||||||
import { formatNetworkTraffic, getNetworkUnit } from "../lib/format-network"
|
import { formatNetworkTraffic, getNetworkUnit } from "../lib/format-network"
|
||||||
import { fetchApi } from "../lib/api-config"
|
import { fetchApi } from "../lib/api-config"
|
||||||
|
import { matchesVmSearch, normalizeVmSearchValue } from "../lib/vm-search"
|
||||||
import DOMPurify from "dompurify"
|
import DOMPurify from "dompurify"
|
||||||
import { marked } from "marked"
|
import { marked } from "marked"
|
||||||
import { getCountFormKey, useI18n, useT } from "@/lib/i18n/provider"
|
import { getCountFormKey, useI18n, useT } from "@/lib/i18n/provider"
|
||||||
@@ -234,6 +235,9 @@ interface VMData {
|
|||||||
diskread?: number
|
diskread?: number
|
||||||
diskwrite?: number
|
diskwrite?: number
|
||||||
ip?: string
|
ip?: string
|
||||||
|
// All LXC addresses reported by lxc-info. `ip` remains the primary
|
||||||
|
// address for backwards compatibility and compact card rendering.
|
||||||
|
ips?: string[]
|
||||||
update_check?: LxcUpdateCheck
|
update_check?: LxcUpdateCheck
|
||||||
// Proxmox tags as a raw string ("prod;web;monitoring" — PVE
|
// Proxmox tags as a raw string ("prod;web;monitoring" — PVE
|
||||||
// separator is ';' but ',' is also accepted). Rendered as
|
// separator is ';' but ',' is also accepted). Rendered as
|
||||||
@@ -251,36 +255,6 @@ interface VMData {
|
|||||||
modal_cache_revision?: number
|
modal_cache_revision?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeVmSearchValue(value: unknown): string {
|
|
||||||
return String(value ?? "")
|
|
||||||
.normalize("NFD")
|
|
||||||
.replace(/[\u0300-\u036f]/g, "")
|
|
||||||
.toLocaleLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type synonyms come from the active locale so a user can search by the
|
|
||||||
// word they'd naturally use ("contenedor", "machine virtuelle", …) rather
|
|
||||||
// than only the internal type token. "lxc" / "qemu" already match through
|
|
||||||
// vm.type, so the catalog entries only carry the natural-language terms.
|
|
||||||
function matchesVmSearch(
|
|
||||||
vm: VMData,
|
|
||||||
terms: string[],
|
|
||||||
typeSynonyms: { lxc: string; qemu: string },
|
|
||||||
): boolean {
|
|
||||||
if (terms.length === 0) return true
|
|
||||||
const searchable = normalizeVmSearchValue([
|
|
||||||
vm.name,
|
|
||||||
vm.vmid,
|
|
||||||
vm.type,
|
|
||||||
vm.type === "lxc" ? typeSynonyms.lxc : typeSynonyms.qemu,
|
|
||||||
vm.tags,
|
|
||||||
vm.description,
|
|
||||||
vm.ip,
|
|
||||||
...(vm.app_watches || []).map((app) => app.name || ""),
|
|
||||||
].join(" "))
|
|
||||||
return terms.every((term) => searchable.includes(term))
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasLxcPendingUpdates(vm: VMData): boolean {
|
function hasLxcPendingUpdates(vm: VMData): boolean {
|
||||||
if (vm.type !== "lxc") return false
|
if (vm.type !== "lxc") return false
|
||||||
const osUpdates = vm.update_check?.count ?? 0
|
const osUpdates = vm.update_check?.count ?? 0
|
||||||
@@ -3295,13 +3269,16 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
|||||||
// immediately without waiting for the batch.
|
// immediately without waiting for the batch.
|
||||||
let lxcIP: string | null | undefined = null
|
let lxcIP: string | null | undefined = null
|
||||||
if (vm.type === "lxc") {
|
if (vm.type === "lxc") {
|
||||||
lxcIP = vmConfigs[vm.vmid]
|
lxcIP = vm.ip || vmConfigs[vm.vmid]
|
||||||
if (!lxcIP) {
|
if (!lxcIP) {
|
||||||
const cached = vmModalCacheRef.current.details.get(vm.vmid) as any
|
const cached = vmModalCacheRef.current.details.get(vm.vmid) as any
|
||||||
lxcIP = cached?.lxc_ip_info?.primary_ip
|
lxcIP = cached?.lxc_ip_info?.primary_ip
|
||||||
|| (cached?.config ? extractIPFromConfig(cached.config, cached.lxc_ip_info) : null)
|
|| (cached?.config ? extractIPFromConfig(cached.config, cached.lxc_ip_info) : null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const additionalIpCount = lxcIP
|
||||||
|
? (vm.ips || []).filter((ip) => ip !== lxcIP).length
|
||||||
|
: 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={vm.vmid}>
|
<div key={vm.vmid}>
|
||||||
@@ -3380,6 +3357,14 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
|||||||
<span className="text-sm text-foreground flex items-center gap-1">
|
<span className="text-sm text-foreground flex items-center gap-1">
|
||||||
<Network className="h-3 w-3 text-green-500" />
|
<Network className="h-3 w-3 text-green-500" />
|
||||||
{lxcIP}
|
{lxcIP}
|
||||||
|
{additionalIpCount > 0 && (
|
||||||
|
<span
|
||||||
|
className="text-xs text-muted-foreground"
|
||||||
|
title={(vm.ips || []).join(", ")}
|
||||||
|
>
|
||||||
|
+{additionalIpCount}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
export interface VMSearchable {
|
||||||
|
vmid: number
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
tags?: string
|
||||||
|
description?: string
|
||||||
|
ip?: string
|
||||||
|
ips?: string[]
|
||||||
|
app_watches?: Array<{ name?: string | null }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VMTypeSynonyms {
|
||||||
|
lxc: string
|
||||||
|
qemu: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeVmSearchValue(value: unknown): string {
|
||||||
|
return String(value ?? "")
|
||||||
|
.normalize("NFD")
|
||||||
|
.replace(/[\u0300-\u036f]/g, "")
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchesVmSearch(
|
||||||
|
vm: VMSearchable,
|
||||||
|
terms: string[],
|
||||||
|
typeSynonyms: VMTypeSynonyms,
|
||||||
|
): boolean {
|
||||||
|
if (terms.length === 0) return true
|
||||||
|
const searchable = normalizeVmSearchValue([
|
||||||
|
vm.name,
|
||||||
|
vm.vmid,
|
||||||
|
vm.type,
|
||||||
|
vm.type === "lxc" ? typeSynonyms.lxc : typeSynonyms.qemu,
|
||||||
|
vm.tags,
|
||||||
|
vm.description,
|
||||||
|
vm.ip,
|
||||||
|
...(vm.ips || []),
|
||||||
|
...(vm.app_watches || []).map((app) => app.name || ""),
|
||||||
|
].join(" "))
|
||||||
|
return terms.every((term) => searchable.includes(term))
|
||||||
|
}
|
||||||
@@ -611,13 +611,14 @@ def parse_lxc_hardware_config(vmid, node):
|
|||||||
return hardware_info
|
return hardware_info
|
||||||
|
|
||||||
|
|
||||||
def _get_lxc_primary_ip_cached(vmid):
|
def _get_lxc_ip_info_cached(vmid):
|
||||||
"""Return the LXC's primary non-Docker IP with an indefinite
|
"""Return an LXC's complete IP classification from the lifecycle cache.
|
||||||
cache. First read per CT spawns one `lxc-info` subprocess;
|
|
||||||
subsequent reads are free until the CT's lifecycle event drops
|
First read per CT spawns one `lxc-info` subprocess; subsequent reads are
|
||||||
the entry via `_invalidate_lxc_ip`. A running CT's IP doesn't
|
free until the CT's lifecycle event drops the entry via
|
||||||
change on its own — the invalidation on start/stop/reboot is the
|
`_invalidate_lxc_ip`. Keeping the complete result (rather than only the
|
||||||
only path that requires re-probing.
|
primary address) lets `/api/vms` expose every address without changing
|
||||||
|
the cache's lifecycle semantics.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
vmid_int = int(vmid)
|
vmid_int = int(vmid)
|
||||||
@@ -626,11 +627,39 @@ def _get_lxc_primary_ip_cached(vmid):
|
|||||||
if vmid_int in _lxc_ip_cache:
|
if vmid_int in _lxc_ip_cache:
|
||||||
return _lxc_ip_cache[vmid_int]
|
return _lxc_ip_cache[vmid_int]
|
||||||
info = get_lxc_ip_from_lxc_info(vmid_int)
|
info = get_lxc_ip_from_lxc_info(vmid_int)
|
||||||
ip = None
|
_lxc_ip_cache[vmid_int] = info
|
||||||
if info:
|
return info
|
||||||
ip = info.get('primary_ip') or (info.get('real_ips') or [None])[0]
|
|
||||||
_lxc_ip_cache[vmid_int] = ip
|
|
||||||
return ip
|
def _get_lxc_primary_ip_cached(vmid):
|
||||||
|
"""Return the primary IP for legacy callers of the LXC IP cache."""
|
||||||
|
info = _get_lxc_ip_info_cached(vmid)
|
||||||
|
if not info:
|
||||||
|
return None
|
||||||
|
return info.get('primary_ip') or (info.get('real_ips') or [None])[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _normalise_lxc_ips(ip_info):
|
||||||
|
"""Return a stable, JSON-safe ordered list of LXC addresses.
|
||||||
|
|
||||||
|
`lxc-info` already decides which addresses are real or Docker addresses;
|
||||||
|
this helper deliberately does not reclassify or filter them. It merely
|
||||||
|
protects the list endpoint from malformed cache data and removes exact
|
||||||
|
duplicates while retaining the original order.
|
||||||
|
"""
|
||||||
|
if not isinstance(ip_info, dict):
|
||||||
|
return []
|
||||||
|
raw_ips = ip_info.get('all_ips')
|
||||||
|
if not isinstance(raw_ips, (list, tuple)):
|
||||||
|
return []
|
||||||
|
ips = []
|
||||||
|
seen = set()
|
||||||
|
for raw_ip in raw_ips:
|
||||||
|
ip = str(raw_ip).strip() if raw_ip is not None else ''
|
||||||
|
if ip and ip not in seen:
|
||||||
|
seen.add(ip)
|
||||||
|
ips.append(ip)
|
||||||
|
return ips
|
||||||
|
|
||||||
|
|
||||||
def _invalidate_lxc_ip(vmid):
|
def _invalidate_lxc_ip(vmid):
|
||||||
@@ -669,11 +698,7 @@ def _warmup_lxc_ip_cache() -> int:
|
|||||||
continue
|
continue
|
||||||
if parts[1].lower() != 'running':
|
if parts[1].lower() != 'running':
|
||||||
continue
|
continue
|
||||||
info = get_lxc_ip_from_lxc_info(vmid_int)
|
_lxc_ip_cache[vmid_int] = get_lxc_ip_from_lxc_info(vmid_int)
|
||||||
ip = None
|
|
||||||
if info:
|
|
||||||
ip = info.get('primary_ip') or (info.get('real_ips') or [None])[0]
|
|
||||||
_lxc_ip_cache[vmid_int] = ip
|
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -1752,7 +1777,7 @@ _vm_mounts_cache: dict = {} # vmid -> (ts, payload) — LXC only
|
|||||||
_VM_LIST_SEARCH_NOTES_TTL = 30
|
_VM_LIST_SEARCH_NOTES_TTL = 30
|
||||||
_vm_list_search_notes_cache: dict = {"ts": 0.0, "signature": (), "notes": {}}
|
_vm_list_search_notes_cache: dict = {"ts": 0.0, "signature": (), "notes": {}}
|
||||||
_vm_list_search_notes_lock = threading.Lock()
|
_vm_list_search_notes_lock = threading.Lock()
|
||||||
# LXC primary IP cache — populated on first read, held indefinitely.
|
# LXC IP classification cache — populated on first read, held indefinitely.
|
||||||
# A running CT's IP doesn't change; the cache is invalidated only when
|
# A running CT's IP doesn't change; the cache is invalidated only when
|
||||||
# the CT's lifecycle event fires (start/stop/reboot), so no periodic
|
# the CT's lifecycle event fires (start/stop/reboot), so no periodic
|
||||||
# polling is needed. See `_handle_guest_lifecycle`.
|
# polling is needed. See `_handle_guest_lifecycle`.
|
||||||
@@ -6749,6 +6774,20 @@ def get_proxmox_vms():
|
|||||||
upd = lxc_updates_map.get(str(resource.get('vmid')))
|
upd = lxc_updates_map.get(str(resource.get('vmid')))
|
||||||
if upd is not None:
|
if upd is not None:
|
||||||
vm_data['update_check'] = upd
|
vm_data['update_check'] = upd
|
||||||
|
# IP addresses are core LXC inventory, not an App
|
||||||
|
# Watch feature. Keep `ip` for callers that expect
|
||||||
|
# a primary address and add `ips` for search and
|
||||||
|
# detail-aware clients. The cache is still warmed
|
||||||
|
# at startup and invalidated by LXC lifecycle events.
|
||||||
|
vm_data['ips'] = []
|
||||||
|
if resource.get('status') == 'running':
|
||||||
|
lxc_ip_info = _get_lxc_ip_info_cached(resource.get('vmid'))
|
||||||
|
lxc_ips = _normalise_lxc_ips(lxc_ip_info)
|
||||||
|
vm_data['ips'] = lxc_ips
|
||||||
|
if lxc_ip_info:
|
||||||
|
primary_ip = lxc_ip_info.get('primary_ip')
|
||||||
|
if isinstance(primary_ip, str) and primary_ip.strip():
|
||||||
|
vm_data['ip'] = primary_ip.strip()
|
||||||
# App Watch (Phase 2c) — list of registered
|
# App Watch (Phase 2c) — list of registered
|
||||||
# apps per CT (0..N). Populates header badge,
|
# apps per CT (0..N). Populates header badge,
|
||||||
# Updates modal connected row, and the App
|
# Updates modal connected row, and the App
|
||||||
@@ -6771,15 +6810,6 @@ def get_proxmox_vms():
|
|||||||
app_list = lxc_app_map.get(str(resource.get('vmid'))) or []
|
app_list = lxc_app_map.get(str(resource.get('vmid'))) or []
|
||||||
if app_list:
|
if app_list:
|
||||||
vm_data['app_watches'] = app_list
|
vm_data['app_watches'] = app_list
|
||||||
# Apps dashboard reads this to build
|
|
||||||
# weblinks. Only paid on CTs that have
|
|
||||||
# registered apps; the IP is cached
|
|
||||||
# indefinitely and invalidated by the
|
|
||||||
# guest lifecycle hook on start/stop/reboot.
|
|
||||||
if vm_type == 'lxc' and resource.get('status') == 'running':
|
|
||||||
_ip = _get_lxc_primary_ip_cached(resource.get('vmid'))
|
|
||||||
if _ip:
|
|
||||||
vm_data['ip'] = _ip
|
|
||||||
docker_inventory = lxc_docker_map.get(str(resource.get('vmid')))
|
docker_inventory = lxc_docker_map.get(str(resource.get('vmid')))
|
||||||
# Docker image drift is an Updates-tab feature,
|
# Docker image drift is an Updates-tab feature,
|
||||||
# not an automatic app detection. Do not attach
|
# not an automatic app detection. Do not attach
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
"""Contracts for LXC IP inventory returned by the compact `/api/vms` list."""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import threading
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
SERVER_SOURCE = Path(__file__).resolve().parents[1] / "flask_server.py"
|
||||||
|
|
||||||
|
|
||||||
|
def load_server_functions(*names):
|
||||||
|
"""Compile selected production functions without importing host-bound Flask state."""
|
||||||
|
tree = ast.parse(SERVER_SOURCE.read_text())
|
||||||
|
functions = {
|
||||||
|
node.name: node
|
||||||
|
for node in tree.body
|
||||||
|
if isinstance(node, ast.FunctionDef) and node.name in names
|
||||||
|
}
|
||||||
|
missing = set(names) - functions.keys()
|
||||||
|
if missing:
|
||||||
|
raise AssertionError(f"Missing production functions: {sorted(missing)}")
|
||||||
|
module = ast.Module(body=[functions[name] for name in names], type_ignores=[])
|
||||||
|
ast.fix_missing_locations(module)
|
||||||
|
namespace = {}
|
||||||
|
exec(compile(module, str(SERVER_SOURCE), "exec"), namespace)
|
||||||
|
return namespace
|
||||||
|
|
||||||
|
|
||||||
|
class LxcVmIpInventoryTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.server = load_server_functions("_normalise_lxc_ips", "get_proxmox_vms")
|
||||||
|
self.server.update({
|
||||||
|
"_get_lxc_update_status_map": lambda: {},
|
||||||
|
"_get_lxc_app_watch_map": lambda: {},
|
||||||
|
"_get_lxc_docker_inventory_map": lambda: {},
|
||||||
|
"get_proxmox_node_name": lambda: "pve",
|
||||||
|
"_get_cached_vm_list_search_notes": lambda _resources, _node: {},
|
||||||
|
"get_cached_vm_disk": lambda _vmid: None,
|
||||||
|
"_guest_lifecycle_lock": threading.RLock(),
|
||||||
|
"_guest_modal_cache_revision": {},
|
||||||
|
"_guest_modal_cache_epoch": 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_rows(self, resources, ip_info_by_vmid):
|
||||||
|
self.server["get_cached_pvesh_cluster_resources_vm"] = lambda: resources
|
||||||
|
self.server["_get_lxc_ip_info_cached"] = lambda vmid: ip_info_by_vmid.get(vmid)
|
||||||
|
return self.server["get_proxmox_vms"]()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def running_lxc(vmid):
|
||||||
|
return {
|
||||||
|
"type": "lxc", "node": "pve", "status": "running", "vmid": vmid,
|
||||||
|
"name": f"ct-{vmid}", "cpu": 0, "mem": 0, "maxmem": 0,
|
||||||
|
"disk": 0, "maxdisk": 0, "uptime": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_unregistered_lxc_keeps_its_primary_ip_in_the_list(self):
|
||||||
|
rows = self.list_rows([self.running_lxc(300)], {
|
||||||
|
300: {
|
||||||
|
"all_ips": ["10.100.100.218"],
|
||||||
|
"real_ips": ["10.100.100.218"],
|
||||||
|
"docker_ips": [],
|
||||||
|
"primary_ip": "10.100.100.218",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertEqual(rows[0]["ip"], "10.100.100.218")
|
||||||
|
self.assertEqual(rows[0]["ips"], ["10.100.100.218"])
|
||||||
|
self.assertNotIn("app_watches", rows[0])
|
||||||
|
|
||||||
|
def test_lxc_with_multiple_ips_preserves_order_and_docker_classification_output(self):
|
||||||
|
rows = self.list_rows([self.running_lxc(301)], {
|
||||||
|
301: {
|
||||||
|
"all_ips": ["10.100.100.219", "10.100.100.220", "172.17.0.1"],
|
||||||
|
"real_ips": ["10.100.100.219", "10.100.100.220"],
|
||||||
|
"docker_ips": ["172.17.0.1"],
|
||||||
|
"primary_ip": "10.100.100.219",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertEqual(rows[0]["ip"], "10.100.100.219")
|
||||||
|
self.assertEqual(rows[0]["ips"], ["10.100.100.219", "10.100.100.220", "172.17.0.1"])
|
||||||
|
|
||||||
|
def test_lxc_without_an_ip_returns_an_empty_ips_list(self):
|
||||||
|
rows = self.list_rows([self.running_lxc(302)], {302: None})
|
||||||
|
|
||||||
|
self.assertEqual(rows[0]["ips"], [])
|
||||||
|
self.assertNotIn("ip", rows[0])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
const assert = require("assert")
|
||||||
|
const fs = require("fs")
|
||||||
|
const path = require("path")
|
||||||
|
const ts = require("../../node_modules/typescript")
|
||||||
|
|
||||||
|
const sourcePath = path.join(__dirname, "../../lib/vm-search.ts")
|
||||||
|
const source = fs.readFileSync(sourcePath, "utf8")
|
||||||
|
const compiled = ts.transpileModule(source, {
|
||||||
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017 },
|
||||||
|
}).outputText
|
||||||
|
const moduleShim = { exports: {} }
|
||||||
|
new Function("exports", "require", "module", "__filename", "__dirname", compiled)(
|
||||||
|
moduleShim.exports,
|
||||||
|
require,
|
||||||
|
moduleShim,
|
||||||
|
sourcePath,
|
||||||
|
path.dirname(sourcePath),
|
||||||
|
)
|
||||||
|
|
||||||
|
const { matchesVmSearch, normalizeVmSearchValue } = moduleShim.exports
|
||||||
|
const synonyms = { lxc: "container", qemu: "virtual machine" }
|
||||||
|
|
||||||
|
const multiIpLxc = {
|
||||||
|
vmid: 301,
|
||||||
|
name: "database",
|
||||||
|
type: "lxc",
|
||||||
|
ip: "10.100.100.219",
|
||||||
|
ips: ["10.100.100.219", "10.100.100.220"],
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
matchesVmSearch(multiIpLxc, [normalizeVmSearchValue("10.100.100.220")], synonyms),
|
||||||
|
true,
|
||||||
|
"A secondary LXC IP must be searchable",
|
||||||
|
)
|
||||||
|
assert.equal(
|
||||||
|
matchesVmSearch(multiIpLxc, [normalizeVmSearchValue("10.100.100.218")], synonyms),
|
||||||
|
false,
|
||||||
|
"Unrelated IPs must not match",
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log("VM IP search tests passed")
|
||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU wird in der Quell-VM-Konfiguration beibehalten",
|
"GPU kept in source VM config": "GPU wird in der Quell-VM-Konfiguration beibehalten",
|
||||||
"GPU not driven by this version": "GPU wird von dieser Version nicht angetrieben",
|
"GPU not driven by this version": "GPU wird von dieser Version nicht angetrieben",
|
||||||
"GPU not found with slot": "GPU mit Steckplatz nicht gefunden",
|
"GPU not found with slot": "GPU mit Steckplatz nicht gefunden",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "GPU-Passthrough-Assistent nicht gefunden. Öffnen Sie später {menu} → {action} im Hauptmenü, um es erneut zu versuchen.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "GPU-Passthrough-Assistent nicht gefunden. Sie können es später über Hardware Graphics ausführen.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "GPU-Passthrough-Assistent nicht gefunden. Sie können es später über Hardware Graphics ausführen.",
|
||||||
"GPU passthrough changes require a host reboot.": "GPU-Passthrough-Änderungen erfordern einen Neustart des Hosts.",
|
"GPU passthrough changes require a host reboot.": "GPU-Passthrough-Änderungen erfordern einen Neustart des Hosts.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "Die GPU-Passthrough-Konfiguration wird jetzt fortgesetzt und nach dem Neustart des Hosts wirksam.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "Die GPU-Passthrough-Konfiguration wird jetzt fortgesetzt und nach dem Neustart des Hosts wirksam.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Wenn das Upgrade fehlschlägt:",
|
"If upgrade fails:": "Wenn das Upgrade fehlschlägt:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Wenn Sie Nein antworten, wird Glances ohne Privilegien installiert und überwacht NUR seinen eigenen LXC, nicht Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Wenn Sie Nein antworten, wird Glances ohne Privilegien installiert und überwacht NUR seinen eigenen LXC, nicht Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Wenn Sie sicher sind, dass Sie es verwenden möchten, entfernen Sie bitte das",
|
"If you are sure you want to use it, please remove the": "Wenn Sie sicher sind, dass Sie es verwenden möchten, entfernen Sie bitte das",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Wenn Sie sure verwenden möchten, entfernen Sie die RAID-Metadaten oder formatieren Sie sie manuell mit externen Tools.",
|
||||||
"If you choose No, install": "Wenn Sie „Nein“ wählen, installieren Sie es",
|
"If you choose No, install": "Wenn Sie „Nein“ wählen, installieren Sie es",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Wenn Sie fortfahren, werden möglicherweise einige Anpassungen dupliziert oder stehen in Konflikt mit den bereits von xshok vorgenommenen.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Wenn Sie fortfahren, werden möglicherweise einige Anpassungen dupliziert oder stehen in Konflikt mit den bereits von xshok vorgenommenen.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Wenn Sie ein Coral M.2/PCIe-Gerät haben, das physisch installiert ist, aber von lspci nicht erkannt wird, brechen Sie hier ab und überprüfen Sie zunächst Ihre Hardware, bevor Sie fortfahren.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Wenn Sie ein Coral M.2/PCIe-Gerät haben, das physisch installiert ist, aber von lspci nicht erkannt wird, brechen Sie hier ab und überprüfen Sie zunächst Ihre Hardware, bevor Sie fortfahren.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Container-Dateisystem mounten",
|
"Mounting container filesystem": "Container-Dateisystem mounten",
|
||||||
"Mounting disk...": "Montagescheibe...",
|
"Mounting disk...": "Montagescheibe...",
|
||||||
"Mounting existing": "Montage vorhanden",
|
"Mounting existing": "Montage vorhanden",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Vorhandenes Dateisystem ({filesystem}) mounten...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Beim Mounten hier werden vorhandene Dateien ausgeblendet, bis die Bereitstellung aufgehoben wird.",
|
"Mounting here will hide existing files until unmounted.": "Beim Mounten hier werden vorhandene Dateien ausgeblendet, bis die Bereitstellung aufgehoben wird.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Verschieben Sie diese Kopie an einen anderen Standort (USB, Passwort-Manager, ein anderer Host).Löschen Sie es aus diesem Pfad, wenn Sie fertig sind.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Verschieben Sie diese Kopie an einen anderen Standort (USB, Passwort-Manager, ein anderer Host).Löschen Sie es aus diesem Pfad, wenn Sie fertig sind.",
|
||||||
"Move to target VM (remove from source VM config)": "Zur Ziel-VM verschieben (aus der Quell-VM-Konfiguration entfernen)",
|
"Move to target VM (remove from source VM config)": "Zur Ziel-VM verschieben (aus der Quell-VM-Konfiguration entfernen)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Wenn Sie fertig sind, führen Sie die „PVE 8 bis 9-Überprüfung“ erneut aus, um sicherzustellen, dass alle Probleme behoben sind \n bevor Sie das PVE 8 → PVE 9-Upgrade durchführen.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Wenn Sie fertig sind, führen Sie die „PVE 8 bis 9-Überprüfung“ erneut aus, um sicherzustellen, dass alle Probleme behoben sind \n bevor Sie das PVE 8 → PVE 9-Upgrade durchführen.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Wenn Sie fertig sind, führen Sie das Skript „PVE 8 to 9 check“ erneut aus, um zu überprüfen, ob alle Probleme behoben sind \n vor dem Neustart.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Wenn Sie fertig sind, führen Sie das Skript „PVE 8 to 9 check“ erneut aus, um zu überprüfen, ob alle Probleme behoben sind \n vor dem Neustart.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Wenn Sie fertig sind, führen Sie das Skript „PVE 8 to 9 check“ erneut aus, um zu überprüfen, ob alle Probleme vorliegen.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Wenn Sie fertig sind, führen Sie das Skript „PVE 8 to 9 check“ erneut aus, um zu überprüfen, ob alle Probleme vorliegen.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "Wenn Sie fertig sind, wiederholen Sie die Prüfung ({check}), um alle verbleibenden Probleme zu überprüfen, bevor Sie neu starten.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "Sobald Sie fertig sind, wiederholen Sie die Prüfung ({check}), um alle verbleibenden Probleme zu überprüfen, bevor Sie mit dem Upgrade von PVE 8 → PVE 9 beginnen.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "Wenn Sie fertig sind, wiederholen Sie die Prüfung ({check}), um alle verbleibenden Probleme zu überprüfen.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Öffnen Sie nach der Installation die VirtIO-ISO und führen Sie das Installationsprogramm aus, um die Treibereinrichtung abzuschließen.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Öffnen Sie nach der Installation die VirtIO-ISO und führen Sie das Installationsprogramm aus, um die Treibereinrichtung abzuschließen.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Eine oder mehrere NVIDIA-GPUs sind derzeit für VM-Passthrough (vfio-pci) konfiguriert:",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Eine oder mehrere NVIDIA-GPUs sind derzeit für VM-Passthrough (vfio-pci) konfiguriert:",
|
||||||
"Online retro games emulator": "Online Retro Spiele Emulator",
|
"Online retro games emulator": "Online Retro Spiele Emulator",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "Privilegierte Container haben vollen Root-Zugriff auf das Hostsystem!",
|
"Privileged containers have full root access to the host system!": "Privilegierte Container haben vollen Root-Zugriff auf das Hostsystem!",
|
||||||
"Privileged installation declined": "Privilegierte Installation abgelehnt",
|
"Privileged installation declined": "Privilegierte Installation abgelehnt",
|
||||||
"Privileged: Full host access (less secure)": "Privilegiert: Vollständiger Hostzugriff (weniger sicher)",
|
"Privileged: Full host access (less secure)": "Privilegiert: Vollständiger Hostzugriff (weniger sicher)",
|
||||||
|
"Probe failed": "Probe fehlgeschlagen",
|
||||||
"Proceed": "Fortfahren",
|
"Proceed": "Fortfahren",
|
||||||
"Proceed with removal": "Fahren Sie mit der Entfernung fort",
|
"Proceed with removal": "Fahren Sie mit der Entfernung fort",
|
||||||
"Proceed?": "Fortfahren?",
|
"Proceed?": "Fortfahren?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Schritte, die ausgeführt werden:",
|
"Steps that will run:": "Schritte, die ausgeführt werden:",
|
||||||
"Still has issues": "Es gibt immer noch Probleme",
|
"Still has issues": "Es gibt immer noch Probleme",
|
||||||
"Stop it first and run this option again.": "Stoppen Sie es zuerst und führen Sie diese Option erneut aus.",
|
"Stop it first and run this option again.": "Stoppen Sie es zuerst und führen Sie diese Option erneut aus.",
|
||||||
|
"Stop that VM, then choose:": "Stoppen Sie VM und wählen Sie dann:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Stoppen Sie den CT, unmounten Sie die Festplatte auf dem HOST und mounten Sie sie erneut mit:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Stoppen Sie den CT, unmounten Sie die Festplatte auf dem HOST und mounten Sie sie erneut mit:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Stoppen Sie die VM/CT, bevor Sie diese Festplatte formatieren.",
|
"Stop the VM/CT before formatting this disk.": "Stoppen Sie die VM/CT, bevor Sie diese Festplatte formatieren.",
|
||||||
"Stop the container before the NVIDIA refresh": "Stoppen Sie den Container, bevor Sie die NVIDIA aktualisieren",
|
"Stop the container before the NVIDIA refresh": "Stoppen Sie den Container, bevor Sie die NVIDIA aktualisieren",
|
||||||
|
|||||||
@@ -2363,6 +2363,7 @@
|
|||||||
"GPU kept in source VM config": "GPU mantenida en la configuración de la VM de origen",
|
"GPU kept in source VM config": "GPU mantenida en la configuración de la VM de origen",
|
||||||
"GPU not driven by this version": "GPU no impulsada por esta versión",
|
"GPU not driven by this version": "GPU no impulsada por esta versión",
|
||||||
"GPU not found with slot": "GPU no encontrada con ranura",
|
"GPU not found with slot": "GPU no encontrada con ranura",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "No se encontró el asistente de paso GPU.Luego, abra {menu} → {action} desde el menú principal para volver a intentarlo.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "No se encontró el asistente de transferencia de GPU. Puede ejecutarlo más tarde desde Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "No se encontró el asistente de transferencia de GPU. Puede ejecutarlo más tarde desde Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "Los cambios de transferencia de GPU requieren reiniciar el host.",
|
"GPU passthrough changes require a host reboot.": "Los cambios de transferencia de GPU requieren reiniciar el host.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configuración de transferencia de GPU continuará ahora y entrará en vigor después de reiniciar el host.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configuración de transferencia de GPU continuará ahora y entrará en vigor después de reiniciar el host.",
|
||||||
@@ -2680,6 +2681,7 @@
|
|||||||
"If upgrade fails:": "Si la actualización falla:",
|
"If upgrade fails:": "Si la actualización falla:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Si responde No, Glances se instala sin privilegios y monitoriza SOLO su propio LXC, no Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Si responde No, Glances se instala sin privilegios y monitoriza SOLO su propio LXC, no Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Si está seguro de que desea utilizarlo, elimine el",
|
"If you are sure you want to use it, please remove the": "Si está seguro de que desea utilizarlo, elimine el",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "si es sure y desea usarlo, elimine los metadatos RAID o formatéelo manualmente usando herramientas externas.",
|
||||||
"If you choose No, install": "Si elige No, instale",
|
"If you choose No, install": "Si elige No, instale",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Si continúa, es posible que algunos ajustes se dupliquen o entren en conflicto con los que ya realizó xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Si continúa, es posible que algunos ajustes se dupliquen o entren en conflicto con los que ya realizó xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Si tiene un dispositivo Coral M.2/PCIe instalado físicamente que lspci no detecta, cancele esta operación y revise primero el hardware.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Si tiene un dispositivo Coral M.2/PCIe instalado físicamente que lspci no detecta, cancele esta operación y revise primero el hardware.",
|
||||||
@@ -3511,6 +3513,7 @@
|
|||||||
"Mounting container filesystem": "Montaje del sistema de archivos del contenedor",
|
"Mounting container filesystem": "Montaje del sistema de archivos del contenedor",
|
||||||
"Mounting disk...": "Disco de montaje...",
|
"Mounting disk...": "Disco de montaje...",
|
||||||
"Mounting existing": "Montaje existente",
|
"Mounting existing": "Montaje existente",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Montando el sistema de archivos existente ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Montar aquí ocultará los archivos existentes hasta que se desmonten.",
|
"Mounting here will hide existing files until unmounted.": "Montar aquí ocultará los archivos existentes hasta que se desmonten.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "mueva esa copia fuera del sitio (USB, administrador de contraseñas, otro host).Elimínelo de esta ruta cuando haya terminado.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "mueva esa copia fuera del sitio (USB, administrador de contraseñas, otro host).Elimínelo de esta ruta cuando haya terminado.",
|
||||||
"Move to target VM (remove from source VM config)": "Mover a la VM de destino (eliminar de la configuración de la VM de origen)",
|
"Move to target VM (remove from source VM config)": "Mover a la VM de destino (eliminar de la configuración de la VM de origen)",
|
||||||
@@ -4085,6 +4088,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Una vez terminado, vuelva a ejecutar la 'verificación PVE 8 a 9' para verificar que todos los problemas estén resueltos. \n antes de ejecutar la actualización PVE 8 → PVE 9.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Una vez terminado, vuelva a ejecutar la 'verificación PVE 8 a 9' para verificar que todos los problemas estén resueltos. \n antes de ejecutar la actualización PVE 8 → PVE 9.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Una vez terminado, vuelva a ejecutar el script 'PVE 8 to 9 check' para verificar que todos los problemas estén resueltos. \n antes de reiniciar.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Una vez terminado, vuelva a ejecutar el script 'PVE 8 to 9 check' para verificar que todos los problemas estén resueltos. \n antes de reiniciar.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Una vez terminado, vuelva a ejecutar el script 'PVE 8 to 9 check' para verificar que todos los problemas.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Una vez terminado, vuelva a ejecutar el script 'PVE 8 to 9 check' para verificar que todos los problemas.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "una vez terminado, repita la verificación ({check}) para revisar cualquier problema restante antes de reiniciar.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "una vez terminado, repita la verificación ({check}) para revisar cualquier problema restante antes de iniciar la actualización PVE 8 → PVE 9.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "una vez terminado, repita la verificación ({check}) para revisar los problemas restantes.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Una vez instalado, abra VirtIO ISO y ejecute el instalador para completar la configuración del controlador.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Una vez instalado, abra VirtIO ISO y ejecute el instalador para completar la configuración del controlador.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Actualmente, una o más GPU NVIDIA están configuradas para el paso a través de VM (vfio-pci):",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Actualmente, una o más GPU NVIDIA están configuradas para el paso a través de VM (vfio-pci):",
|
||||||
"Online retro games emulator": "emulador de juegos retro en línea",
|
"Online retro games emulator": "emulador de juegos retro en línea",
|
||||||
@@ -4449,6 +4455,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "¡Los contenedores privilegiados tienen acceso raíz completo al sistema host!",
|
"Privileged containers have full root access to the host system!": "¡Los contenedores privilegiados tienen acceso raíz completo al sistema host!",
|
||||||
"Privileged installation declined": "Instalación privilegiada rechazada",
|
"Privileged installation declined": "Instalación privilegiada rechazada",
|
||||||
"Privileged: Full host access (less secure)": "Privilegiado: acceso completo al host (menos seguro)",
|
"Privileged: Full host access (less secure)": "Privilegiado: acceso completo al host (menos seguro)",
|
||||||
|
"Probe failed": "Falló la sonda",
|
||||||
"Proceed": "Proceder",
|
"Proceed": "Proceder",
|
||||||
"Proceed with removal": "Proceder con la eliminación",
|
"Proceed with removal": "Proceder con la eliminación",
|
||||||
"Proceed?": "¿Proceder?",
|
"Proceed?": "¿Proceder?",
|
||||||
@@ -5552,6 +5559,7 @@
|
|||||||
"Steps that will run:": "Pasos que se ejecutarán:",
|
"Steps that will run:": "Pasos que se ejecutarán:",
|
||||||
"Still has issues": "Todavía tiene problemas",
|
"Still has issues": "Todavía tiene problemas",
|
||||||
"Stop it first and run this option again.": "Deténgalo primero y ejecute esta opción nuevamente.",
|
"Stop it first and run this option again.": "Deténgalo primero y ejecute esta opción nuevamente.",
|
||||||
|
"Stop that VM, then choose:": "Detenga ese VM, luego elija:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Detenga el CT, desmonte el disco en el HOST y vuelva a montarlo con:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Detenga el CT, desmonte el disco en el HOST y vuelva a montarlo con:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Detenga el VM/CT antes de formatear este disco.",
|
"Stop the VM/CT before formatting this disk.": "Detenga el VM/CT antes de formatear este disco.",
|
||||||
"Stop the container before the NVIDIA refresh": "Detén el contenedor antes de la actualización de NVIDIA",
|
"Stop the container before the NVIDIA refresh": "Detén el contenedor antes de la actualización de NVIDIA",
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU conservé dans la configuration de la VM source",
|
"GPU kept in source VM config": "GPU conservé dans la configuration de la VM source",
|
||||||
"GPU not driven by this version": "GPU non piloté par cette version",
|
"GPU not driven by this version": "GPU non piloté par cette version",
|
||||||
"GPU not found with slot": "GPU introuvable avec le slot",
|
"GPU not found with slot": "GPU introuvable avec le slot",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "Assistant de relais GPU introuvable. Plus tard, ouvrez {menu} → {action} depuis le menu principal pour réessayer.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistant de relais GPU introuvable. Vous pouvez l'exécuter plus tard à partir de Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistant de relais GPU introuvable. Vous pouvez l'exécuter plus tard à partir de Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "Les modifications du relais GPU nécessitent un redémarrage de l’hôte.",
|
"GPU passthrough changes require a host reboot.": "Les modifications du relais GPU nécessitent un redémarrage de l’hôte.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configuration du relais GPU continuera maintenant et deviendra effective après le redémarrage de l'hôte.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configuration du relais GPU continuera maintenant et deviendra effective après le redémarrage de l'hôte.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Si la mise à niveau échoue :",
|
"If upgrade fails:": "Si la mise à niveau échoue :",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Si vous répondez Non, Glances est installé sans privilèges et surveille SEULEMENT ses propres LXC, pas Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Si vous répondez Non, Glances est installé sans privilèges et surveille SEULEMENT ses propres LXC, pas Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Si vous êtes sûr de vouloir l'utiliser, veuillez supprimer le",
|
"If you are sure you want to use it, please remove the": "Si vous êtes sûr de vouloir l'utiliser, veuillez supprimer le",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Si vous êtes sure et que vous souhaitez l'utiliser, supprimez les métadonnées RAID ou formatez-les manuellement à l'aide d'outils externes.",
|
||||||
"If you choose No, install": "Si vous choisissez Non, installez",
|
"If you choose No, install": "Si vous choisissez Non, installez",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Si vous continuez, certains ajustements peuvent être dupliqués ou entrer en conflit avec ceux déjà effectués par xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Si vous continuez, certains ajustements peuvent être dupliqués ou entrer en conflit avec ceux déjà effectués par xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Si vous disposez d'un périphérique Coral M.2 / PCIe physiquement installé mais non détecté par lspci, annulez ici et vérifiez d'abord votre matériel avant de continuer.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Si vous disposez d'un périphérique Coral M.2 / PCIe physiquement installé mais non détecté par lspci, annulez ici et vérifiez d'abord votre matériel avant de continuer.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Montage du système de fichiers du conteneur",
|
"Mounting container filesystem": "Montage du système de fichiers du conteneur",
|
||||||
"Mounting disk...": "Disque de montage...",
|
"Mounting disk...": "Disque de montage...",
|
||||||
"Mounting existing": "Montage existant",
|
"Mounting existing": "Montage existant",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Montage du système de fichiers existant ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Le montage ici masquera les fichiers existants jusqu'à leur démontage.",
|
"Mounting here will hide existing files until unmounted.": "Le montage ici masquera les fichiers existants jusqu'à leur démontage.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "déplacez cette copie hors site (USB, gestionnaire de mots de passe, un autre hôte).Supprimez-le de ce chemin une fois terminé.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "déplacez cette copie hors site (USB, gestionnaire de mots de passe, un autre hôte).Supprimez-le de ce chemin une fois terminé.",
|
||||||
"Move to target VM (remove from source VM config)": "Déplacer vers la VM cible (supprimer de la configuration de la VM source)",
|
"Move to target VM (remove from source VM config)": "Déplacer vers la VM cible (supprimer de la configuration de la VM source)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Une fois terminé, réexécutez la « vérification PVE 8 à 9 » pour vérifier que tous les problèmes sont résolus. \n avant d'exécuter la mise à niveau PVE 8 → PVE 9.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Une fois terminé, réexécutez la « vérification PVE 8 à 9 » pour vérifier que tous les problèmes sont résolus. \n avant d'exécuter la mise à niveau PVE 8 → PVE 9.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Une fois terminé, réexécutez le script 'PVE 8 to 9 check' pour vérifier que tous les problèmes sont résolus. \n avant de redémarrer.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Une fois terminé, réexécutez le script 'PVE 8 to 9 check' pour vérifier que tous les problèmes sont résolus. \n avant de redémarrer.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Une fois terminé, réexécutez le script « PVE 8 to 9 check » pour vérifier que tous les problèmes sont résolus.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Une fois terminé, réexécutez le script « PVE 8 to 9 check » pour vérifier que tous les problèmes sont résolus.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "Une fois terminé, répétez la vérification ({check}) pour examiner les problèmes restants avant de redémarrer.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "Une fois terminé, répétez la vérification ({check}) pour examiner les problèmes restants avant de démarrer la mise à niveau PVE 8 → PVE 9.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "une fois terminé, répétez la vérification ({check}) pour examiner les problèmes restants.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Une fois installé, ouvrez l'ISO VirtIO et exécutez le programme d'installation pour terminer la configuration du pilote.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Une fois installé, ouvrez l'ISO VirtIO et exécutez le programme d'installation pour terminer la configuration du pilote.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Un ou plusieurs GPU NVIDIA sont actuellement configurés pour le relais de VM (vfio-pci) :",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Un ou plusieurs GPU NVIDIA sont actuellement configurés pour le relais de VM (vfio-pci) :",
|
||||||
"Online retro games emulator": "Jeux rétro en ligne émulateur",
|
"Online retro games emulator": "Jeux rétro en ligne émulateur",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "Les conteneurs privilégiés ont un accès root complet au système hôte !",
|
"Privileged containers have full root access to the host system!": "Les conteneurs privilégiés ont un accès root complet au système hôte !",
|
||||||
"Privileged installation declined": "Défaut d'installation privilégié",
|
"Privileged installation declined": "Défaut d'installation privilégié",
|
||||||
"Privileged: Full host access (less secure)": "Privilégié : accès complet à l'hôte (moins sécurisé)",
|
"Privileged: Full host access (less secure)": "Privilégié : accès complet à l'hôte (moins sécurisé)",
|
||||||
|
"Probe failed": "Échec de la sonde",
|
||||||
"Proceed": "Procéder",
|
"Proceed": "Procéder",
|
||||||
"Proceed with removal": "Procéder à la suppression",
|
"Proceed with removal": "Procéder à la suppression",
|
||||||
"Proceed?": "Procéder?",
|
"Proceed?": "Procéder?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Étapes qui s'exécuteront :",
|
"Steps that will run:": "Étapes qui s'exécuteront :",
|
||||||
"Still has issues": "A encore des problèmes",
|
"Still has issues": "A encore des problèmes",
|
||||||
"Stop it first and run this option again.": "Arrêtez-le d'abord et réexécutez cette option.",
|
"Stop it first and run this option again.": "Arrêtez-le d'abord et réexécutez cette option.",
|
||||||
|
"Stop that VM, then choose:": "Arrêtez ce VM, puis choisissez :",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Arrêtez le CT, démontez le disque sur le HOST et remontez avec :",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Arrêtez le CT, démontez le disque sur le HOST et remontez avec :",
|
||||||
"Stop the VM/CT before formatting this disk.": "Arrêtez la VM/CT avant de formater ce disque.",
|
"Stop the VM/CT before formatting this disk.": "Arrêtez la VM/CT avant de formater ce disque.",
|
||||||
"Stop the container before the NVIDIA refresh": "Arrêter le récipient avant le rafraîchissement NVIDIA",
|
"Stop the container before the NVIDIA refresh": "Arrêter le récipient avant le rafraîchissement NVIDIA",
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU mantenuta nella configurazione della VM di origine",
|
"GPU kept in source VM config": "GPU mantenuta nella configurazione della VM di origine",
|
||||||
"GPU not driven by this version": "GPU non supportata da questa versione",
|
"GPU not driven by this version": "GPU non supportata da questa versione",
|
||||||
"GPU not found with slot": "GPU non trovata con lo slot",
|
"GPU not found with slot": "GPU non trovata con lo slot",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "GPU assistente passthrough non trovato. Successivamente, aprire {menu} → {action} dal menu principale per riprovare.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistente passthrough GPU non trovato. Puoi eseguirlo in seguito da Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistente passthrough GPU non trovato. Puoi eseguirlo in seguito da Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "Le modifiche al passthrough della GPU richiedono il riavvio dell'host.",
|
"GPU passthrough changes require a host reboot.": "Le modifiche al passthrough della GPU richiedono il riavvio dell'host.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configurazione del passthrough GPU continuerà ora e diventerà effettiva dopo il riavvio dell'host.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "La configurazione del passthrough GPU continuerà ora e diventerà effettiva dopo il riavvio dell'host.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Se l'aggiornamento fallisce:",
|
"If upgrade fails:": "Se l'aggiornamento fallisce:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Se rispondete a No, Glances è installato senza privilegi e monitor SOLO il proprio LXC, non Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Se rispondete a No, Glances è installato senza privilegi e monitor SOLO il proprio LXC, non Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Se sei sicuro di volerlo utilizzare, rimuovi il file",
|
"If you are sure you want to use it, please remove the": "Se sei sicuro di volerlo utilizzare, rimuovi il file",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Se sei sure e desideri utilizzarlo, rimuovi i metadati RAID o formattalo manualmente utilizzando strumenti esterni.",
|
||||||
"If you choose No, install": "Se scegli No, installa",
|
"If you choose No, install": "Se scegli No, installa",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Se continui, alcune modifiche potrebbero essere duplicate o entrare in conflitto con quelle già apportate da xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Se continui, alcune modifiche potrebbero essere duplicate o entrare in conflitto con quelle già apportate da xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "se disponi di un dispositivo Coral M.2 / PCIe installato fisicamente ma non rilevato da lspci, annulla qui e controlla l'hardware prima di procedere.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "se disponi di un dispositivo Coral M.2 / PCIe installato fisicamente ma non rilevato da lspci, annulla qui e controlla l'hardware prima di procedere.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Montaggio del filesystem del contenitore",
|
"Mounting container filesystem": "Montaggio del filesystem del contenitore",
|
||||||
"Mounting disk...": "Disco di montaggio...",
|
"Mounting disk...": "Disco di montaggio...",
|
||||||
"Mounting existing": "Montaggio esistente",
|
"Mounting existing": "Montaggio esistente",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Montaggio del filesystem esistente ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Il montaggio qui nasconderà i file esistenti finché non verranno smontati.",
|
"Mounting here will hide existing files until unmounted.": "Il montaggio qui nasconderà i file esistenti finché non verranno smontati.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "sposta la copia fuori sede (USB, gestore password, un altro host).Eliminalo da questo percorso una volta terminato.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "sposta la copia fuori sede (USB, gestore password, un altro host).Eliminalo da questo percorso una volta terminato.",
|
||||||
"Move to target VM (remove from source VM config)": "Sposta nella VM di destinazione (rimuovi dalla configurazione della VM di origine)",
|
"Move to target VM (remove from source VM config)": "Sposta nella VM di destinazione (rimuovi dalla configurazione della VM di origine)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Una volta terminato, esegui nuovamente il \"controllo PVE da 8 a 9\" per verificare che tutti i problemi siano stati risolti \n prima di eseguire l'aggiornamento PVE 8 → PVE 9.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Una volta terminato, esegui nuovamente il \"controllo PVE da 8 a 9\" per verificare che tutti i problemi siano stati risolti \n prima di eseguire l'aggiornamento PVE 8 → PVE 9.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Una volta terminato, eseguire nuovamente lo script \"PVE 8 to 9 check\" per verificare che tutti i problemi siano stati risolti \n prima di riavviare.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Una volta terminato, eseguire nuovamente lo script \"PVE 8 to 9 check\" per verificare che tutti i problemi siano stati risolti \n prima di riavviare.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Una volta terminato, eseguire nuovamente lo script \"PVE 8 to 9 check\" per verificare che tutti i problemi siano corretti.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Una volta terminato, eseguire nuovamente lo script \"PVE 8 to 9 check\" per verificare che tutti i problemi siano corretti.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "una volta terminato, ripetere il controllo ({check}) per esaminare eventuali problemi rimanenti prima di riavviare.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "una volta terminato, ripetere il controllo ({check}) per esaminare eventuali problemi rimanenti prima di iniziare l'aggiornamento PVE 8 → PVE 9.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "una volta terminato, ripetere il controllo ({check}) per esaminare eventuali problemi rimanenti.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Una volta installato, apri l'ISO VirtIO ed esegui il programma di installazione per completare la configurazione del driver.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Una volta installato, apri l'ISO VirtIO ed esegui il programma di installazione per completare la configurazione del driver.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Una o più GPU NVIDIA sono attualmente configurate per il passthrough VM (vfio-pci):",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Una o più GPU NVIDIA sono attualmente configurate per il passthrough VM (vfio-pci):",
|
||||||
"Online retro games emulator": "Emulatore di giochi retrò online",
|
"Online retro games emulator": "Emulatore di giochi retrò online",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "I contenitori privilegiati hanno pieno accesso root al sistema host!",
|
"Privileged containers have full root access to the host system!": "I contenitori privilegiati hanno pieno accesso root al sistema host!",
|
||||||
"Privileged installation declined": "Installazione privilegiata declinata",
|
"Privileged installation declined": "Installazione privilegiata declinata",
|
||||||
"Privileged: Full host access (less secure)": "Privilegiato: accesso completo all'host (meno sicuro)",
|
"Privileged: Full host access (less secure)": "Privilegiato: accesso completo all'host (meno sicuro)",
|
||||||
|
"Probe failed": "Sonda fallita",
|
||||||
"Proceed": "Procedere",
|
"Proceed": "Procedere",
|
||||||
"Proceed with removal": "Procedere con la rimozione",
|
"Proceed with removal": "Procedere con la rimozione",
|
||||||
"Proceed?": "Procedere?",
|
"Proceed?": "Procedere?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Passaggi che verranno eseguiti:",
|
"Steps that will run:": "Passaggi che verranno eseguiti:",
|
||||||
"Still has issues": "Ha ancora problemi",
|
"Still has issues": "Ha ancora problemi",
|
||||||
"Stop it first and run this option again.": "Interrompilo prima ed esegui nuovamente questa opzione.",
|
"Stop it first and run this option again.": "Interrompilo prima ed esegui nuovamente questa opzione.",
|
||||||
|
"Stop that VM, then choose:": "arresta VM, quindi scegli:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Arrestare il CT, smontare il disco sull'HOST e rimontarlo con:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Arrestare il CT, smontare il disco sull'HOST e rimontarlo con:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Arrestare il VM/CT prima di formattare questo disco.",
|
"Stop the VM/CT before formatting this disk.": "Arrestare il VM/CT prima di formattare questo disco.",
|
||||||
"Stop the container before the NVIDIA refresh": "Fermare il contenitore prima del rinfresco NVIDIA",
|
"Stop the container before the NVIDIA refresh": "Fermare il contenitore prima del rinfresco NVIDIA",
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU mantida na configuração da VM de origem",
|
"GPU kept in source VM config": "GPU mantida na configuração da VM de origem",
|
||||||
"GPU not driven by this version": "GPU não controlada por esta versão",
|
"GPU not driven by this version": "GPU não controlada por esta versão",
|
||||||
"GPU not found with slot": "GPU não encontrada com slot",
|
"GPU not found with slot": "GPU não encontrada com slot",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "assistente de passagem GPU não encontrado. Mais tarde, abra {menu} → {action} no menu principal para tentar novamente.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistente de passagem de GPU não encontrado. Você pode executá-lo mais tarde em Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Assistente de passagem de GPU não encontrado. Você pode executá-lo mais tarde em Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "As alterações de passagem da GPU exigem uma reinicialização do host.",
|
"GPU passthrough changes require a host reboot.": "As alterações de passagem da GPU exigem uma reinicialização do host.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "A configuração de passagem de GPU continuará agora e entrará em vigor após a reinicialização do host.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "A configuração de passagem de GPU continuará agora e entrará em vigor após a reinicialização do host.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Se a atualização falhar:",
|
"If upgrade fails:": "Se a atualização falhar:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Se responder Não, o Glances é instalado sem privilégios e monitora SOMENTE o seu próprio LXC, não o Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Se responder Não, o Glances é instalado sem privilégios e monitora SOMENTE o seu próprio LXC, não o Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Se você tem certeza de que deseja usá-lo, remova o",
|
"If you are sure you want to use it, please remove the": "Se você tem certeza de que deseja usá-lo, remova o",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Se você é sure e deseja usá-lo, remova os metadados RAID ou formate-os manualmente usando ferramentas externas.",
|
||||||
"If you choose No, install": "Se você escolher Não, instale",
|
"If you choose No, install": "Se você escolher Não, instale",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Se você continuar, alguns ajustes poderão ser duplicados ou entrar em conflito com aqueles já feitos pelo xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Se você continuar, alguns ajustes poderão ser duplicados ou entrar em conflito com aqueles já feitos pelo xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Se você possui um dispositivo Coral M.2 / PCIe instalado fisicamente, mas não detectado pelo lspci, cancele aqui e verifique seu hardware antes de continuar.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Se você possui um dispositivo Coral M.2 / PCIe instalado fisicamente, mas não detectado pelo lspci, cancele aqui e verifique seu hardware antes de continuar.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Montando sistema de arquivos contêiner",
|
"Mounting container filesystem": "Montando sistema de arquivos contêiner",
|
||||||
"Mounting disk...": "Montando disco...",
|
"Mounting disk...": "Montando disco...",
|
||||||
"Mounting existing": "Montagem existente",
|
"Mounting existing": "Montagem existente",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Montando sistema de arquivos existente ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "A montagem aqui ocultará os arquivos existentes até serem desmontados.",
|
"Mounting here will hide existing files until unmounted.": "A montagem aqui ocultará os arquivos existentes até serem desmontados.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Mova essa cópia para fora do local (USB, gerenciador de senhas, outro host).Exclua-o deste caminho quando terminar.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Mova essa cópia para fora do local (USB, gerenciador de senhas, outro host).Exclua-o deste caminho quando terminar.",
|
||||||
"Move to target VM (remove from source VM config)": "Mover para a VM de destino (remover da configuração da VM de origem)",
|
"Move to target VM (remove from source VM config)": "Mover para a VM de destino (remover da configuração da VM de origem)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Quando terminar, execute novamente a 'verificação PVE 8 a 9' para verificar se todos os problemas foram resolvidos \n antes de executar a atualização PVE 8 → PVE 9.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Quando terminar, execute novamente a 'verificação PVE 8 a 9' para verificar se todos os problemas foram resolvidos \n antes de executar a atualização PVE 8 → PVE 9.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Quando terminar, execute novamente o script 'PVE 8 to 9 check' para verificar se todos os problemas foram resolvidos \n antes de reiniciar.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Quando terminar, execute novamente o script 'PVE 8 to 9 check' para verificar se todos os problemas foram resolvidos \n antes de reiniciar.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Quando terminar, execute novamente o script 'PVE 8 to 9 check' para verificar todos os problemas.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Quando terminar, execute novamente o script 'PVE 8 to 9 check' para verificar todos os problemas.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "Quando terminar, repita a verificação ({check}) para revisar quaisquer problemas restantes antes de reiniciar.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "Quando terminar, repita a verificação ({check}) para revisar quaisquer problemas restantes antes de iniciar a atualização PVE 8 → PVE 9.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "Ao terminar, repita a verificação ({check}) para revisar quaisquer problemas restantes.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Depois de instalado, abra o VirtIO ISO e execute o instalador para concluir a configuração do driver.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Depois de instalado, abra o VirtIO ISO e execute o instalador para concluir a configuração do driver.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Uma ou mais GPUs NVIDIA estão atualmente configuradas para passagem de VM (vfio-pci):",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Uma ou mais GPUs NVIDIA estão atualmente configuradas para passagem de VM (vfio-pci):",
|
||||||
"Online retro games emulator": "Emulador de jogos retro online",
|
"Online retro games emulator": "Emulador de jogos retro online",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "Contêineres privilegiados têm acesso root total ao sistema host!",
|
"Privileged containers have full root access to the host system!": "Contêineres privilegiados têm acesso root total ao sistema host!",
|
||||||
"Privileged installation declined": "Instalação privada declinou",
|
"Privileged installation declined": "Instalação privada declinou",
|
||||||
"Privileged: Full host access (less secure)": "Privilegiado: acesso total ao host (menos seguro)",
|
"Privileged: Full host access (less secure)": "Privilegiado: acesso total ao host (menos seguro)",
|
||||||
|
"Probe failed": "falha na sonda",
|
||||||
"Proceed": "Prosseguir",
|
"Proceed": "Prosseguir",
|
||||||
"Proceed with removal": "Prossiga com a remoção",
|
"Proceed with removal": "Prossiga com a remoção",
|
||||||
"Proceed?": "Continuar?",
|
"Proceed?": "Continuar?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Etapas que serão executadas:",
|
"Steps that will run:": "Etapas que serão executadas:",
|
||||||
"Still has issues": "Ainda tem problemas",
|
"Still has issues": "Ainda tem problemas",
|
||||||
"Stop it first and run this option again.": "Pare primeiro e execute esta opção novamente.",
|
"Stop it first and run this option again.": "Pare primeiro e execute esta opção novamente.",
|
||||||
|
"Stop that VM, then choose:": "Pare esse VM e escolha:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Pare o CT, desmonte o disco no HOST e remonte com:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Pare o CT, desmonte o disco no HOST e remonte com:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Pare a VM/CT antes de formatar este disco.",
|
"Stop the VM/CT before formatting this disk.": "Pare a VM/CT antes de formatar este disco.",
|
||||||
"Stop the container before the NVIDIA refresh": "Pare o recipiente antes da atualização do NVIDIA",
|
"Stop the container before the NVIDIA refresh": "Pare o recipiente antes da atualização do NVIDIA",
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU ponechaná v nastavení zdrojovej VM",
|
"GPU kept in source VM config": "GPU ponechaná v nastavení zdrojovej VM",
|
||||||
"GPU not driven by this version": "GPU nepoháňa táto verzia",
|
"GPU not driven by this version": "GPU nepoháňa táto verzia",
|
||||||
"GPU not found with slot": "GPU sa nenašla na slote",
|
"GPU not found with slot": "GPU sa nenašla na slote",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "Asistent prechodu GPU sa nenašiel. Neskôr otvorte {menu} → {action} z hlavnej ponuky a skúste to znova.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Sprievodca priamym priradením GPU sa nenašiel. Môžete ho spustiť neskôr z časti Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "Sprievodca priamym priradením GPU sa nenašiel. Môžete ho spustiť neskôr z časti Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "Zmeny pre priame priradenie GPU vyžadujú reštart servera.",
|
"GPU passthrough changes require a host reboot.": "Zmeny pre priame priradenie GPU vyžadujú reštart servera.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "Nastavenie GPU passthrough bude teraz pokračovať a prejaví sa po reštarte hosta.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "Nastavenie GPU passthrough bude teraz pokračovať a prejaví sa po reštarte hosta.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Ak aktualizácia zlyhá:",
|
"If upgrade fails:": "Ak aktualizácia zlyhá:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Ak odpoviete nie, Glances je nainštalovaný bez oprávnení a monitoruje IBA svoje vlastné LXC, nie Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Ak odpoviete nie, Glances je nainštalovaný bez oprávnení a monitoruje IBA svoje vlastné LXC, nie Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Ak ste si istý, že ho chcete použiť, odstráňte",
|
"If you are sure you want to use it, please remove the": "Ak ste si istý, že ho chcete použiť, odstráňte",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Ak ste sure, chcete ho použiť, odstráňte metadáta RAID alebo ich naformátujte manuálne pomocou externých nástrojov.",
|
||||||
"If you choose No, install": "Ak vyberiete Nie, nainštalujte",
|
"If you choose No, install": "Ak vyberiete Nie, nainštalujte",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Ak budete pokračovať, niektoré úpravy sa môžu zdvojiť alebo byť v konflikte s tým, čo už urobil xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Ak budete pokračovať, niektoré úpravy sa môžu zdvojiť alebo byť v konflikte s tým, čo už urobil xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Ak máte zariadenie Coral M.2 / PCIe, ktoré je fyzicky nainštalované, ale nie je detekované lspci, zrušte to tu a pred pokračovaním najskôr skontrolujte hardvér.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Ak máte zariadenie Coral M.2 / PCIe, ktoré je fyzicky nainštalované, ale nie je detekované lspci, zrušte to tu a pred pokračovaním najskôr skontrolujte hardvér.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Pripájam súborový systém kontajnera",
|
"Mounting container filesystem": "Pripájam súborový systém kontajnera",
|
||||||
"Mounting disk...": "Pripájam disk...",
|
"Mounting disk...": "Pripájam disk...",
|
||||||
"Mounting existing": "Pripájam existujúci",
|
"Mounting existing": "Pripájam existujúci",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Pripája sa existujúci súborový systém ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Pripojenie do tohto priečinka dočasne skryje existujúce súbory, kým zdieľanie neodpojíte.",
|
"Mounting here will hide existing files until unmounted.": "Pripojenie do tohto priečinka dočasne skryje existujúce súbory, kým zdieľanie neodpojíte.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Presuňte túto kópiu mimo servera (USB, správca hesiel, iný host). Po dokončení ju z tejto cesty odstráňte.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Presuňte túto kópiu mimo servera (USB, správca hesiel, iný host). Po dokončení ju z tejto cesty odstráňte.",
|
||||||
"Move to target VM (remove from source VM config)": "Presunúť do cieľovej VM (odstrániť zo zdrojovej VM)",
|
"Move to target VM (remove from source VM config)": "Presunúť do cieľovej VM (odstrániť zo zdrojovej VM)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Po dokončení znova spustite 'PVE 8 to 9 check', aby ste overili, že všetky problémy sú vyriešené \n ešte pred spustením aktualizácie z PVE 8 na PVE 9.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "Po dokončení znova spustite 'PVE 8 to 9 check', aby ste overili, že všetky problémy sú vyriešené \n ešte pred spustením aktualizácie z PVE 8 na PVE 9.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Po dokončení znova spustite skript 'PVE 8 to 9 check', aby ste overili, že všetky problémy sú vyriešené \n ešte pred reštartom.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "Po dokončení znova spustite skript 'PVE 8 to 9 check', aby ste overili, že všetky problémy sú vyriešené \n ešte pred reštartom.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Po dokončení spustite skript 'PVE 8 to 9 check' znova, aby ste overili všetky problémy.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "Po dokončení spustite skript 'PVE 8 to 9 check' znova, aby ste overili všetky problémy.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "Po dokončení zopakujte kontrolu ({check}) a skontrolujte všetky zostávajúce problémy pred reštartovaním.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "Po dokončení zopakujte kontrolu ({check}), aby ste skontrolovali všetky zostávajúce problémy pred spustením inovácie PVE 8 → PVE 9.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "Po dokončení zopakujte kontrolu ({check}), aby ste skontrolovali všetky zostávajúce problémy.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Po nainštalovaní otvorte VirtIO ISO a spustite inštalátor na dokončenie ovládačov.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "Po nainštalovaní otvorte VirtIO ISO a spustite inštalátor na dokončenie ovládačov.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Jedna alebo viac NVIDIA GPU je aktuálne nastavených na VM passthrough (vfio-pci):",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "Jedna alebo viac NVIDIA GPU je aktuálne nastavených na VM passthrough (vfio-pci):",
|
||||||
"Online retro games emulator": "Online retro hry emulátor",
|
"Online retro games emulator": "Online retro hry emulátor",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "Privilegované kontajnery majú plný root prístup k hostiteľskému systému!",
|
"Privileged containers have full root access to the host system!": "Privilegované kontajnery majú plný root prístup k hostiteľskému systému!",
|
||||||
"Privileged installation declined": "Privilegovaná inštalácia odmietla",
|
"Privileged installation declined": "Privilegovaná inštalácia odmietla",
|
||||||
"Privileged: Full host access (less secure)": "Privilegovaný: plný prístup k serveru (menej bezpečné)",
|
"Privileged: Full host access (less secure)": "Privilegovaný: plný prístup k serveru (menej bezpečné)",
|
||||||
|
"Probe failed": "Sonda zlyhala",
|
||||||
"Proceed": "Pokračovať",
|
"Proceed": "Pokračovať",
|
||||||
"Proceed with removal": "Pokračovať v odstránení",
|
"Proceed with removal": "Pokračovať v odstránení",
|
||||||
"Proceed?": "Pokračovať?",
|
"Proceed?": "Pokračovať?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Kroky, ktoré sa vykonajú:",
|
"Steps that will run:": "Kroky, ktoré sa vykonajú:",
|
||||||
"Still has issues": "Stále má problémy",
|
"Still has issues": "Stále má problémy",
|
||||||
"Stop it first and run this option again.": "Najprv ju zastavte a potom túto možnosť spustite znova.",
|
"Stop it first and run this option again.": "Najprv ju zastavte a potom túto možnosť spustite znova.",
|
||||||
|
"Stop that VM, then choose:": "Zastavte VM a potom vyberte:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Zastavte CT, odpojte disk na HOSTE a pripojte ho znova pomocou:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Zastavte CT, odpojte disk na HOSTE a pripojte ho znova pomocou:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Pred formátovaním tohto disku zastavte VM/CT.",
|
"Stop the VM/CT before formatting this disk.": "Pred formátovaním tohto disku zastavte VM/CT.",
|
||||||
"Stop the container before the NVIDIA refresh": "Zastavte nádobu pred obnovou NVIDIA",
|
"Stop the container before the NVIDIA refresh": "Zastavte nádobu pred obnovou NVIDIA",
|
||||||
|
|||||||
@@ -2360,6 +2360,7 @@
|
|||||||
"GPU kept in source VM config": "GPU hålls i käll-VM-konfiguration",
|
"GPU kept in source VM config": "GPU hålls i käll-VM-konfiguration",
|
||||||
"GPU not driven by this version": "GPU drivs inte av den här versionen",
|
"GPU not driven by this version": "GPU drivs inte av den här versionen",
|
||||||
"GPU not found with slot": "GPU hittades inte med kortplats",
|
"GPU not found with slot": "GPU hittades inte med kortplats",
|
||||||
|
"GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.": "GPU passthrough-assistent hittades inte. Senare, öppna {menu} → {action} från huvudmenyn för att försöka igen.",
|
||||||
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "GPU passthrough-assistent hittades inte. Du kan köra det senare från Hardware Graphics.",
|
"GPU passthrough assistant not found. You can run it later from Hardware Graphics.": "GPU passthrough-assistent hittades inte. Du kan köra det senare från Hardware Graphics.",
|
||||||
"GPU passthrough changes require a host reboot.": "GPU-genomföringsändringar kräver omstart av värddatorn.",
|
"GPU passthrough changes require a host reboot.": "GPU-genomföringsändringar kräver omstart av värddatorn.",
|
||||||
"GPU passthrough configuration will continue now and will become effective after host reboot.": "GPU-genomkopplingskonfigurationen fortsätter nu och träder i kraft efter omstart av värddatorn.",
|
"GPU passthrough configuration will continue now and will become effective after host reboot.": "GPU-genomkopplingskonfigurationen fortsätter nu och träder i kraft efter omstart av värddatorn.",
|
||||||
@@ -2677,6 +2678,7 @@
|
|||||||
"If upgrade fails:": "Om uppgraderingen misslyckas:",
|
"If upgrade fails:": "Om uppgraderingen misslyckas:",
|
||||||
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Om du svarar nej installeras Glances utan privilegier och övervakar ENDAST sin egen LXC, inte Proxmox.",
|
"If you answer No, Glances is installed without privileges and monitors ONLY its own LXC, not Proxmox.": "Om du svarar nej installeras Glances utan privilegier och övervakar ENDAST sin egen LXC, inte Proxmox.",
|
||||||
"If you are sure you want to use it, please remove the": "Om du är säker på att du vill använda den, vänligen ta bort",
|
"If you are sure you want to use it, please remove the": "Om du är säker på att du vill använda den, vänligen ta bort",
|
||||||
|
"If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.": "Om du är sure vill du använda den, ta bort RAID-metadata eller formatera den manuellt med hjälp av externa verktyg.",
|
||||||
"If you choose No, install": "Om du väljer Nej, installera",
|
"If you choose No, install": "Om du väljer Nej, installera",
|
||||||
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Om du fortsätter kan vissa justeringar dupliceras eller komma i konflikt med de som redan gjorts av xshok.",
|
"If you continue, some adjustments may be duplicated or conflict with those already made by xshok.": "Om du fortsätter kan vissa justeringar dupliceras eller komma i konflikt med de som redan gjorts av xshok.",
|
||||||
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Om du har en Coral M.2/PCIe-enhet som är fysiskt installerad men inte detekteras av lspci, avbryt här och kontrollera din hårdvara innan du fortsätter.",
|
"If you have a Coral M.2 / PCIe device that is physically installed but not detected by lspci, cancel here and check your hardware first before proceeding.": "Om du har en Coral M.2/PCIe-enhet som är fysiskt installerad men inte detekteras av lspci, avbryt här och kontrollera din hårdvara innan du fortsätter.",
|
||||||
@@ -3508,6 +3510,7 @@
|
|||||||
"Mounting container filesystem": "Montering av containerfilsystem",
|
"Mounting container filesystem": "Montering av containerfilsystem",
|
||||||
"Mounting disk...": "Monteringsskiva...",
|
"Mounting disk...": "Monteringsskiva...",
|
||||||
"Mounting existing": "Montering befintlig",
|
"Mounting existing": "Montering befintlig",
|
||||||
|
"Mounting existing filesystem ({filesystem})...": "Montering av befintligt filsystem ({filesystem})...",
|
||||||
"Mounting here will hide existing files until unmounted.": "Montering här kommer att dölja befintliga filer tills de avmonteras.",
|
"Mounting here will hide existing files until unmounted.": "Montering här kommer att dölja befintliga filer tills de avmonteras.",
|
||||||
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Flytta kopian från platsen (USB, lösenordshanterare, en annan värd). Ta bort den från den här sökvägen när du är klar.",
|
"Move that copy offsite (USB, password manager, another host). Delete it from this path when done.": "Flytta kopian från platsen (USB, lösenordshanterare, en annan värd). Ta bort den från den här sökvägen när du är klar.",
|
||||||
"Move to target VM (remove from source VM config)": "Flytta till mål-VM (ta bort från käll-VM-konfiguration)",
|
"Move to target VM (remove from source VM config)": "Flytta till mål-VM (ta bort från käll-VM-konfiguration)",
|
||||||
@@ -4082,6 +4085,9 @@
|
|||||||
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "När du är klar, kör \"PVE 8 till 9-kontroll\" igen för att verifiera att alla problem är lösta \n innan du kör PVE 8 → PVE 9-uppgraderingen.",
|
"Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.": "När du är klar, kör \"PVE 8 till 9-kontroll\" igen för att verifiera att alla problem är lösta \n innan du kör PVE 8 → PVE 9-uppgraderingen.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "När du är klar, kör skriptet \"PVE 8 till 9 check\" igen för att verifiera att alla problem är lösta \n innan du startar om.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.": "När du är klar, kör skriptet \"PVE 8 till 9 check\" igen för att verifiera att alla problem är lösta \n innan du startar om.",
|
||||||
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "När du är klar, kör skriptet 'PVE 8 till 9 check' igen för att verifiera att alla problem.",
|
"Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.": "När du är klar, kör skriptet 'PVE 8 till 9 check' igen för att verifiera att alla problem.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before rebooting.": "När du är klar, upprepa kontrollen ({check}) för att granska eventuella återstående problem innan du startar om.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.": "När du är klar, upprepa kontrollen ({check}) för att granska eventuella återstående problem innan du startar PVE 8 → PVE 9-uppgraderingen.",
|
||||||
|
"Once finished, repeat the check ({check}) to review any remaining issues.": "När du är klar, upprepa kontrollen ({check}) för att granska eventuella återstående problem.",
|
||||||
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "När det är installerat, öppna VirtIO ISO och kör installationsprogrammet för att slutföra drivrutinsinstallationen.",
|
"Once installed, open the VirtIO ISO and run the installer to complete driver setup.": "När det är installerat, öppna VirtIO ISO och kör installationsprogrammet för att slutföra drivrutinsinstallationen.",
|
||||||
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "En eller flera NVIDIA GPU:er är för närvarande konfigurerade för VM-passthrough (vfio-pci):",
|
"One or more NVIDIA GPUs are currently configured for VM passthrough (vfio-pci):": "En eller flera NVIDIA GPU:er är för närvarande konfigurerade för VM-passthrough (vfio-pci):",
|
||||||
"Online retro games emulator": "Online retro spel emulator",
|
"Online retro games emulator": "Online retro spel emulator",
|
||||||
@@ -4446,6 +4452,7 @@
|
|||||||
"Privileged containers have full root access to the host system!": "Privilegerade behållare har full root-åtkomst till värdsystemet!",
|
"Privileged containers have full root access to the host system!": "Privilegerade behållare har full root-åtkomst till värdsystemet!",
|
||||||
"Privileged installation declined": "Privilegierad installation minskade",
|
"Privileged installation declined": "Privilegierad installation minskade",
|
||||||
"Privileged: Full host access (less secure)": "Privilegerad: Full värdåtkomst (mindre säker)",
|
"Privileged: Full host access (less secure)": "Privilegerad: Full värdåtkomst (mindre säker)",
|
||||||
|
"Probe failed": "Sonden misslyckades",
|
||||||
"Proceed": "Fortsätta",
|
"Proceed": "Fortsätta",
|
||||||
"Proceed with removal": "Fortsätt med borttagning",
|
"Proceed with removal": "Fortsätt med borttagning",
|
||||||
"Proceed?": "Fortsätta?",
|
"Proceed?": "Fortsätta?",
|
||||||
@@ -5548,6 +5555,7 @@
|
|||||||
"Steps that will run:": "Steg som kommer att köras:",
|
"Steps that will run:": "Steg som kommer att köras:",
|
||||||
"Still has issues": "Har fortfarande problem",
|
"Still has issues": "Har fortfarande problem",
|
||||||
"Stop it first and run this option again.": "Stoppa det först och kör det här alternativet igen.",
|
"Stop it first and run this option again.": "Stoppa det först och kör det här alternativet igen.",
|
||||||
|
"Stop that VM, then choose:": "Stoppa den VM och välj sedan:",
|
||||||
"Stop the CT, unmount the disk on the HOST, and remount with:": "Stoppa CT, avmontera disken på HOST och montera om med:",
|
"Stop the CT, unmount the disk on the HOST, and remount with:": "Stoppa CT, avmontera disken på HOST och montera om med:",
|
||||||
"Stop the VM/CT before formatting this disk.": "Stoppa VM/CT innan du formaterar denna disk.",
|
"Stop the VM/CT before formatting this disk.": "Stoppa VM/CT innan du formaterar denna disk.",
|
||||||
"Stop the container before the NVIDIA refresh": "Stoppa behållaren innan NVIDIA-uppdateringen",
|
"Stop the container before the NVIDIA refresh": "Stoppa behållaren innan NVIDIA-uppdateringen",
|
||||||
|
|||||||
@@ -1459,9 +1459,8 @@ check_switch_mode() {
|
|||||||
msg="\n$(translate 'The selected GPU is already assigned to another VM that is currently running:')\n\n"
|
msg="\n$(translate 'The selected GPU is already assigned to another VM that is currently running:')\n\n"
|
||||||
msg+=" VM ${vm_src_id} (${vm_src_name:-VM-${vm_src_id}})\n\n"
|
msg+=" VM ${vm_src_id} (${vm_src_name:-VM-${vm_src_id}})\n\n"
|
||||||
msg+="$(translate 'The same GPU cannot be used by two VMs at the same time.')\n\n"
|
msg+="$(translate 'The same GPU cannot be used by two VMs at the same time.')\n\n"
|
||||||
msg+="$(translate 'Next step: stop that VM first, then run')\n"
|
msg+="$(translate 'Stop that VM, then choose:')\n"
|
||||||
msg+=" Hardware Graphics → Add GPU to VM\n"
|
msg+=" $(translate 'Hardware: GPUs and Coral-TPU') → $(translate 'Add GPU to VM (Intel | AMD | NVIDIA)')\n"
|
||||||
msg+="$(translate 'to move the GPU safely.')"
|
|
||||||
|
|
||||||
_pmx_msgbox "$(translate 'GPU Busy in Running VM')" "$msg" 16 78
|
_pmx_msgbox "$(translate 'GPU Busy in Running VM')" "$msg" 16 78
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -646,7 +646,13 @@ mount_existing_disk() {
|
|||||||
mkdir -p "$mount_path"
|
mkdir -p "$mount_path"
|
||||||
msg_ok "$(translate "Mount point created")"
|
msg_ok "$(translate "Mount point created")"
|
||||||
|
|
||||||
msg_info "$(translate "Mounting existing") $existing_fs $(translate "filesystem...")"
|
local mount_message
|
||||||
|
mount_message="$(translate "Mounting existing filesystem ({filesystem})...")"
|
||||||
|
if [[ "$mount_message" != *'{filesystem}'* ]]; then
|
||||||
|
mount_message="Mounting existing filesystem ({filesystem})..."
|
||||||
|
fi
|
||||||
|
mount_message="${mount_message//\{filesystem\}/$existing_fs}"
|
||||||
|
msg_info "$mount_message"
|
||||||
if ! mount "$disk" "$mount_path" 2>/dev/null; then
|
if ! mount "$disk" "$mount_path" 2>/dev/null; then
|
||||||
msg_error "$(translate "Failed to mount disk")"
|
msg_error "$(translate "Failed to mount disk")"
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ test_iscsi_connectivity() {
|
|||||||
if nc -z -w 2 "$portal_host" "$portal_port" 2>/dev/null; then
|
if nc -z -w 2 "$portal_host" "$portal_port" 2>/dev/null; then
|
||||||
echo -e " | iSCSI port $portal_port: ${GN}$(translate "Open")${CL}"
|
echo -e " | iSCSI port $portal_port: ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo -e " | iSCSI port $portal_port: ${RD}$(translate "Closed")${CL}"
|
echo -e " | iSCSI port $portal_port: ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${RD}$(translate "Unreachable")${CL}"
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ test_nfs_connectivity() {
|
|||||||
if pct exec "$CTID" -- nc -z -w 2 "$server" 2049 2>/dev/null; then
|
if pct exec "$CTID" -- nc -z -w 2 "$server" 2049 2>/dev/null; then
|
||||||
echo -e "\033[1;92m$(translate "Open")\033[0m"
|
echo -e "\033[1;92m$(translate "Open")\033[0m"
|
||||||
else
|
else
|
||||||
echo -e "\033[1;91m$(translate "Closed")\033[0m"
|
echo -e "\033[1;91m$(translate "Probe failed")\033[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Try to list exports
|
# Try to list exports
|
||||||
|
|||||||
@@ -839,7 +839,7 @@ test_nfs_connectivity() {
|
|||||||
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
||||||
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo -e " | NFS port 2049: ${RD}$(translate "Closed")${CL}"
|
echo -e " | NFS port 2049: ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if showmount -e "$server" >/dev/null 2>&1; then
|
if showmount -e "$server" >/dev/null 2>&1; then
|
||||||
@@ -882,7 +882,7 @@ test_nfs_connectivity() {
|
|||||||
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
||||||
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo -e " | NFS port 2049: ${RD}$(translate "Closed")${CL}"
|
echo -e " | NFS port 2049: ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${RD}$(translate "Unreachable")${CL}"
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
||||||
|
|||||||
@@ -1044,7 +1044,7 @@ test_samba_connectivity() {
|
|||||||
elif pct exec "$CTID" -- nc -z -w 2 "$server" 139 2>/dev/null; then
|
elif pct exec "$CTID" -- nc -z -w 2 "$server" 139 2>/dev/null; then
|
||||||
echo " $(translate "NetBIOS port 139:"): ${GN}$(translate "Open")${CL}"
|
echo " $(translate "NetBIOS port 139:"): ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo " $(translate "SMB ports:"): ${RD}$(translate "Closed")${CL}"
|
echo " $(translate "SMB ports:"): ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -918,7 +918,7 @@ test_samba_connectivity() {
|
|||||||
elif nc -z -w 2 "$server" 139 2>/dev/null; then
|
elif nc -z -w 2 "$server" 139 2>/dev/null; then
|
||||||
echo -e " | NetBIOS 139: ${GN}$(translate "Open")${CL}"
|
echo -e " | NetBIOS 139: ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo -e " | SMB ports: ${RD}$(translate "Closed")${CL}"
|
echo -e " | SMB ports: ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n " $(translate "Guest access test:"): "
|
echo -n " $(translate "Guest access test:"): "
|
||||||
@@ -964,7 +964,7 @@ test_samba_connectivity() {
|
|||||||
elif nc -z -w 2 "$server" 139 2>/dev/null; then
|
elif nc -z -w 2 "$server" 139 2>/dev/null; then
|
||||||
echo -e " | NetBIOS 139: ${GN}$(translate "Open")${CL}"
|
echo -e " | NetBIOS 139: ${GN}$(translate "Open")${CL}"
|
||||||
else
|
else
|
||||||
echo -e " | SMB ports: ${RD}$(translate "Closed")${CL}"
|
echo -e " | SMB ports: ${RD}$(translate "Probe failed")${CL}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${RD}$(translate "Unreachable")${CL}"
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ for DISK in $SELECTED; do
|
|||||||
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
|
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
|
||||||
dialog --backtitle "$BACKTITLE" \
|
dialog --backtitle "$BACKTITLE" \
|
||||||
--title "$(translate "RAID Detected")" \
|
--title "$(translate "RAID Detected")" \
|
||||||
--msgbox "\n$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, please remove the") RAID metadata $(translate "or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" $UI_RESULT_H $UI_RESULT_W
|
--msgbox "\n$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, remove the RAID metadata or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" $UI_RESULT_H $UI_RESULT_W
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,11 @@ run_pve8to9_check2() {
|
|||||||
echo -e
|
echo -e
|
||||||
done
|
done
|
||||||
echo -e
|
echo -e
|
||||||
msg_info2 "$(translate "Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues.")"
|
local check_help
|
||||||
|
check_help="$(translate "Once finished, repeat the check ({check}) to review any remaining issues.")"
|
||||||
|
[[ "$check_help" == *'{check}'* ]] || check_help="Once finished, repeat the check ({check}) to review any remaining issues."
|
||||||
|
check_help="${check_help//\{check\}/$(translate "Run PVE 8 to 9 check")}"
|
||||||
|
msg_info2 "$check_help"
|
||||||
echo -e
|
echo -e
|
||||||
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
||||||
read -r
|
read -r
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ ask_run_mode() {
|
|||||||
--menu "$text" 20 70 8 \
|
--menu "$text" 20 70 8 \
|
||||||
1 "$(translate "Automatic/Unattended")" \
|
1 "$(translate "Automatic/Unattended")" \
|
||||||
2 "$(translate "Interactive (guided, prompts visible)")" \
|
2 "$(translate "Interactive (guided, prompts visible)")" \
|
||||||
3 "$(translate "Run PVE 8 to 9") check" \
|
3 "$(translate "Run PVE 8 to 9 check")" \
|
||||||
4 "$(translate "Manual upgrade guide step by step")" \
|
4 "$(translate "Manual upgrade guide step by step")" \
|
||||||
3>&1 1>&2 2>&3
|
3>&1 1>&2 2>&3
|
||||||
); status=$?
|
); status=$?
|
||||||
@@ -178,7 +178,7 @@ ask_run_mode() {
|
|||||||
--menu "$(translate "Choose how to perform the upgrade:")" 20 70 8 \
|
--menu "$(translate "Choose how to perform the upgrade:")" 20 70 8 \
|
||||||
"1" "$(translate "Automatic/Unattended")" \
|
"1" "$(translate "Automatic/Unattended")" \
|
||||||
"2" "$(translate "Interactive (guided, prompts visible)")" \
|
"2" "$(translate "Interactive (guided, prompts visible)")" \
|
||||||
"3" "$(translate "Run PVE 8 to 9") check" \
|
"3" "$(translate "Run PVE 8 to 9 check")" \
|
||||||
"4" "$(translate "Manual upgrade guide step by step")" \
|
"4" "$(translate "Manual upgrade guide step by step")" \
|
||||||
3>&1 1>&2 2>&3
|
3>&1 1>&2 2>&3
|
||||||
); then
|
); then
|
||||||
@@ -777,7 +777,11 @@ run_pve8to9_check() {
|
|||||||
echo -e
|
echo -e
|
||||||
done
|
done
|
||||||
echo -e
|
echo -e
|
||||||
msg_info2 "$(translate "Once finished, re-run 'PVE 8 to 9 check' to verify that all issues are resolved \n before executing the PVE 8 → PVE 9 upgrade.")"
|
local check_help
|
||||||
|
check_help="$(translate "Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.")"
|
||||||
|
[[ "$check_help" == *'{check}'* ]] || check_help="Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade."
|
||||||
|
check_help="${check_help//\{check\}/$(translate "Run PVE 8 to 9 check")}"
|
||||||
|
msg_info2 "$check_help"
|
||||||
echo -e
|
echo -e
|
||||||
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
||||||
read -r
|
read -r
|
||||||
@@ -1143,7 +1147,11 @@ run_pve8to9_check2() {
|
|||||||
echo -e
|
echo -e
|
||||||
done
|
done
|
||||||
echo -e
|
echo -e
|
||||||
msg_info2 "$(translate "Once finished, re-run the script 'PVE 8 to 9 check' to verify that all issues are resolved \n before rebooting.")"
|
local check_help
|
||||||
|
check_help="$(translate "Once finished, repeat the check ({check}) to review any remaining issues before rebooting.")"
|
||||||
|
[[ "$check_help" == *'{check}'* ]] || check_help="Once finished, repeat the check ({check}) to review any remaining issues before rebooting."
|
||||||
|
check_help="${check_help//\{check\}/$(translate "Run PVE 8 to 9 check")}"
|
||||||
|
msg_info2 "$check_help"
|
||||||
echo -e
|
echo -e
|
||||||
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
msg_success "$(translate "Press Enter to exit the script after reading instructions...")"
|
||||||
read -r
|
read -r
|
||||||
|
|||||||
@@ -179,7 +179,12 @@ function run_gpu_passthrough_wizard() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f "$gpu_script" ]]; then
|
if [[ ! -f "$gpu_script" ]]; then
|
||||||
msg_warn "$(translate "GPU passthrough assistant not found. You can run it later from Hardware Graphics.")"
|
local gpu_notice
|
||||||
|
gpu_notice="$(translate "GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.")"
|
||||||
|
[[ "$gpu_notice" == *'{menu}'* && "$gpu_notice" == *'{action}'* ]] || gpu_notice="GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again."
|
||||||
|
gpu_notice="${gpu_notice//\{menu\}/$(translate "Hardware: GPUs and Coral-TPU")}"
|
||||||
|
gpu_notice="${gpu_notice//\{action\}/$(translate "Add GPU to VM (Intel | AMD | NVIDIA)")}"
|
||||||
|
msg_warn "$gpu_notice"
|
||||||
WIZARD_GPU_RESULT="cancelled"
|
WIZARD_GPU_RESULT="cancelled"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -234,7 +234,12 @@ function run_gpu_passthrough_wizard() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f "$gpu_script" ]]; then
|
if [[ ! -f "$gpu_script" ]]; then
|
||||||
msg_warn "$(translate "GPU passthrough assistant not found. You can run it later from Hardware Graphics.")"
|
local gpu_notice
|
||||||
|
gpu_notice="$(translate "GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.")"
|
||||||
|
[[ "$gpu_notice" == *'{menu}'* && "$gpu_notice" == *'{action}'* ]] || gpu_notice="GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again."
|
||||||
|
gpu_notice="${gpu_notice//\{menu\}/$(translate "Hardware: GPUs and Coral-TPU")}"
|
||||||
|
gpu_notice="${gpu_notice//\{action\}/$(translate "Add GPU to VM (Intel | AMD | NVIDIA)")}"
|
||||||
|
msg_warn "$gpu_notice"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,12 @@ function run_gpu_passthrough_wizard() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f "$gpu_script" ]]; then
|
if [[ ! -f "$gpu_script" ]]; then
|
||||||
msg_warn "$(translate "GPU passthrough assistant not found. You can run it later from Hardware Graphics.")"
|
local gpu_notice
|
||||||
|
gpu_notice="$(translate "GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.")"
|
||||||
|
[[ "$gpu_notice" == *'{menu}'* && "$gpu_notice" == *'{action}'* ]] || gpu_notice="GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again."
|
||||||
|
gpu_notice="${gpu_notice//\{menu\}/$(translate "Hardware: GPUs and Coral-TPU")}"
|
||||||
|
gpu_notice="${gpu_notice//\{action\}/$(translate "Add GPU to VM (Intel | AMD | NVIDIA)")}"
|
||||||
|
msg_warn "$gpu_notice"
|
||||||
WIZARD_GPU_RESULT="cancelled"
|
WIZARD_GPU_RESULT="cancelled"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
// Source-extracted, inert UI/message seams; never source administrative scripts.
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const os = require('node:os');
|
||||||
|
const path = require('node:path');
|
||||||
|
const cp = require('node:child_process');
|
||||||
|
const root = path.resolve(__dirname, '..');
|
||||||
|
const read = p => fs.readFileSync(path.join(root, p), 'utf8');
|
||||||
|
const bash = (code, env = {}) => {
|
||||||
|
const r = cp.spawnSync('bash', ['-c', code], {encoding: 'utf8', env: {...process.env, ...env}});
|
||||||
|
assert.equal(r.status, 0, `bash fixture failed: ${r.stderr}`);
|
||||||
|
return r.stdout.trim();
|
||||||
|
};
|
||||||
|
const func = (source, name) => {
|
||||||
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
const m = source.match(new RegExp(`(?:^|\\n)(?:function )?${escaped}\\(\\) \\{[\\s\\S]*?\\n\\}`, 'm'));
|
||||||
|
assert.ok(m, `function ${name} present`);
|
||||||
|
return m[0];
|
||||||
|
};
|
||||||
|
const lookup = func(read('scripts/utils.sh'), 'translate');
|
||||||
|
const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'pmx-tui-wording-'));
|
||||||
|
const it = JSON.parse(read('lang/it.json'));
|
||||||
|
const newKeys = [
|
||||||
|
'Once finished, repeat the check ({check}) to review any remaining issues.',
|
||||||
|
'Once finished, repeat the check ({check}) to review any remaining issues before starting the PVE 8 → PVE 9 upgrade.',
|
||||||
|
'Once finished, repeat the check ({check}) to review any remaining issues before rebooting.',
|
||||||
|
'GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again.',
|
||||||
|
];
|
||||||
|
const marker = Object.fromEntries(newKeys.map((k, i) => [k, i === 3
|
||||||
|
? 'TRADOTTO_3 {action} {menu}' : `TRADOTTO_${i} {check} fine`]));
|
||||||
|
const setup = `LANG_DIR=${JSON.stringify(temp)}; LANGUAGE="${'${LANGUAGE:-en}'}"; ${lookup}\nmsg_warn() { printf '%s\\n' "$1"; }; msg_info2() { printf '%s\\n' "$1"; }; msg_title() { printf '%s\\n' "$1"; };`;
|
||||||
|
const store = (locale, entries) => fs.writeFileSync(path.join(temp, `${locale}.json`), JSON.stringify(entries));
|
||||||
|
store('it', it); store('synthetic', {
|
||||||
|
...marker,
|
||||||
|
'Run PVE 8 to 9 check': 'CONTROLLO_LOCALIZZATO',
|
||||||
|
'Hardware: GPUs and Coral-TPU': 'HARDWARE_LOCALIZZATO',
|
||||||
|
'Add GPU to VM (Intel | AMD | NVIDIA)': 'AZIONE_LOCALIZZATA',
|
||||||
|
'Stop that VM, then choose:': 'SCELTA_LOCALIZZATA:',
|
||||||
|
});
|
||||||
|
const menuSrc = read('scripts/utilities/upgrade_pve8_to_pve9.sh');
|
||||||
|
const menuLines = menuSrc.split('\n').filter(l => /(?:^|\s)(?:3|"3") "\$\(translate .*PVE 8 to 9/.test(l));
|
||||||
|
assert.equal(menuLines.length, 2, 'both actual menu consumers');
|
||||||
|
const renderMenu = locale => menuLines.map(l => bash(setup + '\nprintf \'%s\\n\' ' + l.trim().replace(/\\$/, '').replace(/^(?:3|"3") /, '') + '\n', {LANGUAGE: locale}));
|
||||||
|
assert.deepEqual(renderMenu('en'), ['Run PVE 8 to 9 check', 'Run PVE 8 to 9 check']);
|
||||||
|
assert.deepEqual(renderMenu('it'), [it['Run PVE 8 to 9 check'], it['Run PVE 8 to 9 check']]);
|
||||||
|
assert.deepEqual(renderMenu('synthetic'), ['CONTROLLO_LOCALIZZATO', 'CONTROLLO_LOCALIZZATO']);
|
||||||
|
const locales = ['es', 'fr', 'de', 'it', 'pt', 'sk', 'sv'];
|
||||||
|
for (const locale of locales) {
|
||||||
|
const catalog = JSON.parse(read(`lang/${locale}.json`));
|
||||||
|
store(locale, catalog);
|
||||||
|
const label = catalog['Run PVE 8 to 9 check'] || 'Run PVE 8 to 9 check';
|
||||||
|
assert.deepEqual(renderMenu(locale), [label, label], `${locale}: both menus`);
|
||||||
|
}
|
||||||
|
const checker = read('scripts/utilities/pve8to9_check.sh');
|
||||||
|
const title = checker.split('\n').find(l => /^msg_title "\$\(translate "Run PVE 8 to 9 check"\)"$/.test(l));
|
||||||
|
assert.ok(title);
|
||||||
|
const checkHelp = checker.match(/^\s*check_help="\$\(translate "Once finished,[^\n]+\n(?:[^\n]*\n){2}\s*msg_info2 "\$check_help"/m)?.[0];
|
||||||
|
const upgradeHelp = [...menuSrc.matchAll(/^\s*check_help="\$\(translate "Once finished,[^\n]+\n(?:[^\n]*\n){2}\s*msg_info2 "\$check_help"/gm)].map(m => m[0]);
|
||||||
|
assert.equal(upgradeHelp.length, 2);
|
||||||
|
const helpLines = [checkHelp, ...upgradeHelp];
|
||||||
|
const renderHelp = (locale, entries) => {
|
||||||
|
if (entries) store(locale, entries);
|
||||||
|
return helpLines.map(l => bash(setup + '\n' + l.trim() + '\n', {LANGUAGE: locale}));
|
||||||
|
};
|
||||||
|
const helpEn = renderHelp('en');
|
||||||
|
assert.equal(helpEn.length, 3);
|
||||||
|
for (const line of helpEn) {
|
||||||
|
assert.ok(line.includes('Run PVE 8 to 9 check'), line);
|
||||||
|
assert.ok(line.includes('repeat the check (Run PVE 8 to 9 check) to review any remaining issues'), line);
|
||||||
|
assert.ok(!line.includes('{check}') && !line.includes('all issues are resolved') && !line.includes('run Run'), line);
|
||||||
|
}
|
||||||
|
const helpIt = renderHelp('it'); // New keys absent from shipped Italian cache: complete English fallback.
|
||||||
|
for (const line of helpIt) assert.ok(line.includes(it['Run PVE 8 to 9 check']), line);
|
||||||
|
for (const locale of locales) {
|
||||||
|
const catalog = JSON.parse(read(`lang/${locale}.json`));
|
||||||
|
store(locale, catalog);
|
||||||
|
const label = catalog['Run PVE 8 to 9 check'] || 'Run PVE 8 to 9 check';
|
||||||
|
for (const line of renderHelp(locale)) assert.ok(line.includes(`(${label})`) && !line.includes('{check}'), `${locale}: ${line}`);
|
||||||
|
}
|
||||||
|
const helpSynthetic = renderHelp('synthetic');
|
||||||
|
for (const [i, line] of helpSynthetic.entries()) assert.equal(line, `TRADOTTO_${i} CONTROLLO_LOCALIZZATO fine`);
|
||||||
|
const brokenHelp = renderHelp('malformed', {...marker, 'Run PVE 8 to 9 check': 'CONTROLLO_LOCALIZZATO', [newKeys[0]]: 'NON_VALIDA {wrong}'});
|
||||||
|
assert.ok(brokenHelp[0].includes('Once finished, repeat the check (CONTROLLO_LOCALIZZATO)'), brokenHelp[0]);
|
||||||
|
const vmPaths = ['scripts/vm/synology.sh', 'scripts/vm/vm_creator.sh', 'scripts/vm/zimaos.sh'];
|
||||||
|
const vmFunctions = vmPaths.map(p => func(read(p), 'run_gpu_passthrough_wizard'));
|
||||||
|
const renderVm = locale => vmFunctions.map(fn => bash(setup + `\nLOCAL_SCRIPTS=${JSON.stringify(path.join(temp, 'absent'))}; WIZARD_ADD_GPU=yes; ` + fn + '\nrun_gpu_passthrough_wizard\n', {LANGUAGE: locale}));
|
||||||
|
for (const line of renderVm('en')) {
|
||||||
|
assert.ok(line.includes('Hardware: GPUs and Coral-TPU → Add GPU to VM (Intel | AMD | NVIDIA)'), line);
|
||||||
|
assert.ok(!line.includes('Hardware Graphics') && !line.includes('{menu}') && !line.includes('{action}'), line);
|
||||||
|
}
|
||||||
|
for (const line of renderVm('it')) {
|
||||||
|
assert.ok(line.includes(`${it['Hardware: GPUs and Coral-TPU']} → ${it['Add GPU to VM (Intel | AMD | NVIDIA)']}`), line);
|
||||||
|
assert.ok(!line.includes('Hardware Graphics'), line);
|
||||||
|
}
|
||||||
|
for (const locale of locales) {
|
||||||
|
const catalog = JSON.parse(read(`lang/${locale}.json`));
|
||||||
|
const menu = catalog['Hardware: GPUs and Coral-TPU'] || 'Hardware: GPUs and Coral-TPU';
|
||||||
|
const action = catalog['Add GPU to VM (Intel | AMD | NVIDIA)'] || 'Add GPU to VM (Intel | AMD | NVIDIA)';
|
||||||
|
for (const line of renderVm(locale)) assert.ok(line.includes(`${menu} → ${action}`) && !line.includes('{menu}') && !line.includes('{action}'), `${locale}: ${line}`);
|
||||||
|
}
|
||||||
|
for (const line of renderVm('synthetic')) assert.ok(line.includes('AZIONE_LOCALIZZATA HARDWARE_LOCALIZZATO'), line);
|
||||||
|
store('malformed', {...marker, 'Hardware: GPUs and Coral-TPU': 'MENU', 'Add GPU to VM (Intel | AMD | NVIDIA)': 'ACTION', [newKeys[3]]: 'BROKEN {menu} {wrong}'});
|
||||||
|
for (const line of renderVm('malformed')) assert.ok(line.startsWith('GPU passthrough assistant not found.') && line.includes('MENU → ACTION'), line);
|
||||||
|
store('malformed', {...marker, 'Hardware: GPUs and Coral-TPU': 'MENU', 'Add GPU to VM (Intel | AMD | NVIDIA)': 'ACTION', [newKeys[3]]: 'BROKEN {action} {wrong}'});
|
||||||
|
for (const line of renderVm('malformed')) assert.ok(line.startsWith('GPU passthrough assistant not found.') && line.includes('MENU → ACTION'), line);
|
||||||
|
store('malformed', {...marker, 'Hardware: GPUs and Coral-TPU': 'MENU', 'Add GPU to VM (Intel | AMD | NVIDIA)': 'ACTION', [newKeys[3]]: 'BROKEN {wrong}'});
|
||||||
|
for (const line of renderVm('malformed')) assert.ok(line.startsWith('GPU passthrough assistant not found.') && line.includes('MENU → ACTION'), line);
|
||||||
|
const additionalLead = read('scripts/gpu_tpu/add_gpu_vm.sh').split('\n').find(l => l.includes('Stop that VM, then choose:') && l.includes('msg+='));
|
||||||
|
assert.ok(additionalLead, 'busy-VM guidance has a standalone instruction before the rendered labels');
|
||||||
|
assert.equal(bash(setup + '\n' + additionalLead.trim() + '\nprintf \'%b\\n\' "$msg"', {LANGUAGE: 'synthetic'}), 'SCELTA_LOCALIZZATA:');
|
||||||
|
assert.ok(!read('scripts/gpu_tpu/add_gpu_vm.sh').includes("msg+=\"$(translate 'to move the GPU safely.')\""), 'no clipped tail follows the route');
|
||||||
|
const additionalNav = read('scripts/gpu_tpu/add_gpu_vm.sh').split('\n').find(l => l.includes('→') && l.includes('Add GPU to VM') && l.includes('msg+='));
|
||||||
|
assert.ok(additionalNav?.includes("$(translate 'Hardware: GPUs and Coral-TPU')"), 'busy-VM guidance uses actual menu label');
|
||||||
|
assert.ok(additionalNav?.includes("$(translate 'Add GPU to VM (Intel | AMD | NVIDIA)')"), 'busy-VM guidance uses actual action label');
|
||||||
|
for (const locale of ['en', 'it', 'synthetic']) {
|
||||||
|
const label = locale === 'en' ? 'Hardware: GPUs and Coral-TPU' : locale === 'it' ? it['Hardware: GPUs and Coral-TPU'] : 'HARDWARE_LOCALIZZATO';
|
||||||
|
const action = locale === 'en' ? 'Add GPU to VM (Intel | AMD | NVIDIA)' : locale === 'it' ? it['Add GPU to VM (Intel | AMD | NVIDIA)'] : 'AZIONE_LOCALIZZATA';
|
||||||
|
const rendered = bash(setup + `\nmsg=''; ${additionalNav.trim()}; printf '%b\\n' "$msg"`, {LANGUAGE: locale});
|
||||||
|
assert.equal(rendered, `${label} → ${action}`);
|
||||||
|
}
|
||||||
|
// Actual checker disables localization before both title and help; no behavior changed here.
|
||||||
|
const bypass = func(checker, 'disable_translation_post_upgrade');
|
||||||
|
assert.equal(bash(setup + `\n${bypass}\ndisable_translation_post_upgrade\n` + title), 'Run PVE 8 to 9 check');
|
||||||
|
assert.equal(bash(setup + `\n${bypass}\ndisable_translation_post_upgrade\n` + checkHelp), helpEn[0]);
|
||||||
|
const extraction = cp.spawnSync('python3', ['-c', `import importlib.util,pathlib
|
||||||
|
p=pathlib.Path('.github/scripts/build_translation_cache.py'); s=importlib.util.spec_from_file_location('cache',p); m=importlib.util.module_from_spec(s); s.loader.exec_module(m)
|
||||||
|
keys=set(m.extract_translate_texts(pathlib.Path('scripts')))
|
||||||
|
required=${JSON.stringify(['Run PVE 8 to 9 check', ...newKeys, 'Hardware: GPUs and Coral-TPU', 'Add GPU to VM (Intel | AMD | NVIDIA)'])}
|
||||||
|
assert set(required)<=keys, set(required)-keys
|
||||||
|
print('EXTRACTED',len(required))`], {cwd: root, encoding: 'utf8'});
|
||||||
|
assert.equal(extraction.status, 0, extraction.stderr);
|
||||||
|
// No source catalog edits; synthetic translation and malformed placeholders only live in scratch.
|
||||||
|
assert.ok(!Object.keys(it).some(k => newKeys.includes(k)));
|
||||||
|
fs.rmSync(temp, {recursive: true, force: true});
|
||||||
|
console.log('PASS: extracted upgrade/GPU consumers, seven caches/fallbacks, synthetic and malformed placeholders, real extractor');
|
||||||
Reference in New Issue
Block a user