feat: type the plugin host record, move plugin strings out of core and add lint checks

This commit is contained in:
LukeGus committed 2026-09-29 13:08:39 -05:00
1 parent bba06f7ff6
commit b8bbcd2196
626 files changed
+23884 -4590

No files matched your search

@@ -0,0 +1,5 @@
-- ssh_data.autostart_password, autostart_key and autostart_key_password held
-- copies of a host's login for 2.8's autostart endpoint, which nothing has read
-- since. They leave the schema but stay in place, unused, until 3.0.0, so no
-- install loses what it stored.
SELECT 1;
File diff suppressed because it is too large. Load diff
+7
View File
@@ -449,6 +449,13 @@
"when": 1790700739900,
"tag": "0063_needy_radioactive_man",
"breakpoints": true
},
{
"idx": 64,
"version": "5",
"when": 1790704531888,
"tag": "0064_flippant_killer_shrike",
"breakpoints": true
}
]
}
@@ -0,0 +1,5 @@
-- ssh_data.autostart_password, autostart_key and autostart_key_password held
-- copies of a host's login for 2.8's autostart endpoint, which nothing has read
-- since. They leave the schema but stay in place, unused, until 3.0.0, so no
-- install loses what it stored.
SELECT 1;
File diff suppressed because it is too large. Load diff
+7
View File
@@ -449,6 +449,13 @@
"when": 1790700738799,
"tag": "0063_giant_starfox",
"breakpoints": true
},
{
"idx": 64,
"version": "7",
"when": 1790704531255,
"tag": "0064_sticky_pestilence",
"breakpoints": true
}
]
}
@@ -0,0 +1,5 @@
-- ssh_data.autostart_password, autostart_key and autostart_key_password held
-- copies of a host's login for 2.8's autostart endpoint, which nothing has read
-- since. They leave the schema but stay in place, unused, until 3.0.0, so no
-- install loses what it stored.
SELECT 1;
File diff suppressed because it is too large. Load diff
+7
View File
@@ -414,6 +414,13 @@
"when": 1790700721290,
"tag": "0058_bitter_thunderbolt",
"breakpoints": true
},
{
"idx": 59,
"version": "6",
"when": 1790704530590,
"tag": "0059_adorable_wrecking_crew",
"breakpoints": true
}
]
}
+1 -1
View File
@@ -19,7 +19,7 @@
"postinstall": "node scripts/patch-app-builder-lib.cjs && node scripts/patch-guacamole-lite.cjs && node scripts/patch-guacamole-common-js.cjs && node scripts/patch-better-sqlite3.cjs && node scripts/patch-nan.cjs && node scripts/patch-node-pty.cjs && node scripts/patch-xterm-android-ime.cjs && node scripts/patch-ssh2-agent.cjs",
"prepare": "husky || true",
"prebuild": "node scripts/write-electron-build-info.cjs",
"lint": "node scripts/generate-dialect-schema.cjs --check && npm run plugin:validate-manifest && eslint . && node scripts/check-importmap-csp.cjs && node scripts/check-core-plugin-ids.cjs",
"lint": "node scripts/generate-dialect-schema.cjs --check && npm run plugin:validate-manifest && eslint . && node scripts/check-importmap-csp.cjs && node scripts/check-core-plugin-ids.cjs && node scripts/check-sdk-ui-exports.cjs && node scripts/check-plugin-locales.cjs && node scripts/check-test-locations.cjs",
"lint:fix": "eslint --fix .",
"type-check": "tsc -b --force",
"test": "vitest run",
+90 -27
View File
@@ -556,55 +556,118 @@ export interface PluginHostSummary {
}
/**
* A host record wide enough for a plugin that creates or updates hosts on the
* user's behalf (import, discovery, sync), decrypted for that user. Unlike
* PluginHostSummary this carries the fields a plugin needs to set up a
* connectable host, not just what a list view shows. Still no secret auth
* material (password, key, vault tokens): a plugin that creates a host picks
* an authType and, for "credential", a credentialId it does not need to see
* the contents of.
* A host as ctx.hosts hands it to a plugin that creates, updates or scans
* hosts on the user's behalf (import, discovery, sync), decrypted for that
* user. Every field is listed here and core builds it field by field, so a
* core column a plugin needs has to be added to this contract first. Carries
* no secret auth material (password, key, vault tokens): a plugin that
* creates a host picks an authType and, for "credential", a credentialId it
* does not need to see the contents of.
*/
export interface PluginHostRecord {
id: number;
userId: string;
/** Stable across a desktop and the server it syncs with. */
syncId: string | null;
name: string | null;
ip: string;
port: number;
username: string;
authType: string;
credentialId?: number | null;
overrideCredentialUsername?: boolean | null;
connectionType?: string | null;
credentialId: number | null;
overrideCredentialUsername: boolean;
/** "ssh", or the id of the plugin protocol a host without SSH uses. */
connectionType: string;
/** Comma-separated, as ssh_data stores them. */
tags: string | null;
folder: string | null;
jumpHosts?: unknown;
enableSsh?: boolean | null;
parentHostId: number | null;
pin: boolean;
notes: string | null;
jumpHosts: PluginHostJumpHost[];
enableSsh: boolean;
sshPort: number | null;
statusCheckEnabled: boolean;
/** Seconds between status checks; null follows the global setting. */
statusCheckInterval: number | null;
connectionOrigin: "local" | "remote" | null;
/** Keepalive, legacy algorithms, agent and environment options. */
sshOptions?: HostSshOptions | null;
createdAt?: string | null;
updatedAt?: string | null;
[key: string]: unknown;
sshOptions: HostSshOptions;
/**
* The calling plugin's own host settings, secrets redacted. Another
* plugin's settings are that plugin's to hand out, through a service.
*/
pluginSettings: Record<string, unknown>;
/** Core's last reachability check, or null before the first one. */
status: PluginHostStatusEntry | null;
/** Desktop only: kept on this device, never synced to the server. */
localOnly: boolean;
createdAt: string | null;
updatedAt: string | null;
}
export interface PluginHostJumpHost {
hostId: number;
}
/**
* Fields a plugin may set when creating a host it will own or manage. Fields
* that belong to another plugin's host settings (a protocol switch or port) are
* handed to that plugin's host import normalizer, as on a bulk import.
* The fields a plugin may set when it creates a host. A key not listed here
* is refused with an error rather than dropped. Host settings go in
* `pluginSettings`, keyed by the plugin that declares them, and are
* validated against that plugin's manifest: an undeclared key is refused, and
* settings for a plugin that is not running are skipped and logged.
*/
export type PluginHostCreateInput = Partial<
Omit<PluginHostRecord, "id" | "userId">
> & {
export interface PluginHostCreateInput {
name: string;
ip: string;
port: number;
username: string;
authType: string;
};
credentialId?: number | null;
overrideCredentialUsername?: boolean;
connectionType?: string;
/** Comma-separated or a list. */
tags?: string | string[] | null;
folder?: string | null;
pin?: boolean;
notes?: string | null;
jumpHosts?: PluginHostJumpHost[] | null;
enableSsh?: boolean;
sshPort?: number | null;
statusCheckEnabled?: boolean;
statusCheckInterval?: number | null;
forceKeyboardInteractive?: boolean;
sshOptions?: HostSshOptions | null;
/** Host settings by plugin id, the shape a Termix export carries. */
pluginSettings?: Record<string, Record<string, unknown>>;
}
/** Fields a plugin may change on a host it already created or was granted access to. */
export type PluginHostUpdateInput = Partial<
Omit<PluginHostRecord, "id" | "userId">
>;
/** Fields a plugin may change on a host the acting user owns. */
export type PluginHostUpdateInput = Partial<PluginHostCreateInput>;
/** Every key PluginHostCreateInput and PluginHostUpdateInput accept. */
export const PLUGIN_HOST_INPUT_KEYS = [
"name",
"ip",
"port",
"username",
"authType",
"credentialId",
"overrideCredentialUsername",
"connectionType",
"tags",
"folder",
"pin",
"notes",
"jumpHosts",
"enableSsh",
"sshPort",
"statusCheckEnabled",
"statusCheckInterval",
"forceKeyboardInteractive",
"sshOptions",
"pluginSettings",
] as const satisfies readonly (keyof PluginHostCreateInput)[];
/** The same shape canAccessHost returns internally, without secrets. */
export interface PluginHostAccess {
+51 -4
View File
@@ -29,9 +29,10 @@ export type IconComponent = ComponentType<{
}>;
/**
* A host as the shell holds it. Only the identifying fields are typed; the
* rest of the record is passed through as the shell has it, so a plugin
* that needs a feature column reads it by name.
* A host as the shell hands it to a plugin. Every field is listed here and
* core builds the record field by field, so a plugin cannot come to depend on
* a core column that is not part of this contract. A plugin's own host
* settings are in `pluginSettings[<plugin id>]`.
*/
export interface PluginHostRecord {
id: string;
@@ -41,6 +42,25 @@ export interface PluginHostRecord {
username?: string;
folder?: string;
tags?: string[];
pin?: boolean;
notes?: string;
/** Stable across a desktop and the server it syncs with. */
syncId?: string | null;
/** Sub-host nesting: the host this one is organized under. */
parentHostId?: string | null;
authType?: string;
credentialId?: string | number | null;
overrideCredentialUsername?: boolean;
/** "ssh", or the id of the plugin protocol a host without SSH uses. */
connectionType?: string;
/** Desktop app: where connections to this host start from. */
connectionOrigin?: "local" | "remote" | null;
enableSsh?: boolean;
sshPort?: number;
jumpHosts?: { hostId: string | number }[];
statusCheckEnabled?: boolean;
/** Seconds between status checks; null follows the global setting. */
statusCheckInterval?: number | null;
/** Keepalive, legacy algorithms, agent and environment options. */
sshOptions?: HostSshOptions | null;
/** Each enabled plugin's host settings, secrets redacted. */
@@ -49,7 +69,34 @@ export interface PluginHostRecord {
protocolAuth?: Record<string, HostProtocolAuthSummary>;
/** Set on a Quick Connect host, which is never saved. */
quickConnectLogin?: QuickConnectLogin;
[key: string]: unknown;
/** Quick Connect only: core can save this host as it is. */
quickConnectSavable?: boolean;
/** Assigned when a host is opened in a tab; tells duplicate tabs apart. */
instanceId?: string;
/** Core's status: "online" once a login worked. */
status?: "online" | "reachable" | "offline" | "unknown";
online?: boolean;
/** Someone else owns this host and shared it with the user. */
isShared?: boolean;
permissionLevel?: "connect" | "view" | "edit" | "manage";
sharedExpiresAt?: string;
ownerUsername?: string;
/**
* A shared host's login per protocol ("ssh" or a plugin protocol): whether
* the owner shared theirs, and the recipient's own credential if they had
* to pick one.
*/
authOverrides?: Partial<Record<string, HostAuthOverrideSummary>>;
/** A read-only copy of a host shared with the linked account. */
sharedCopy?: boolean;
/** Desktop only: kept on this device, never synced to the server. */
localOnly?: boolean;
}
export interface HostAuthOverrideSummary {
credentialId?: number | string;
required: boolean;
ownerAuthShared: boolean;
}
/** The protocol login a Quick Connect host carries, in plain text. */
+80 -9
View File
@@ -8,7 +8,11 @@
* The vitest config these run under comes from @termix/plugin-sdk/vitest-preset.
*/
import { LoginMethodError, PluginCapabilityError } from "./backend.js";
import {
LoginMethodError,
PLUGIN_HOST_INPUT_KEYS,
PluginCapabilityError,
} from "./backend.js";
import type {
PluginContext,
PluginDisposables,
@@ -396,6 +400,74 @@ function noopLogger(): PluginLogger {
};
}
const HOST_INPUT_KEYS = new Set<string>(PLUGIN_HOST_INPUT_KEYS);
/** Refuses a key ctx.hosts does not take, the way core does. */
function checkHostInput(input: PluginHostUpdateInput): void {
const unknown = Object.keys(input ?? {}).filter(
(key) => !HOST_INPUT_KEYS.has(key),
);
if (unknown.length > 0) {
throw new Error(`ctx.hosts does not take ${unknown.join(", ")}`);
}
}
function emptyHostRecord(id: number, userId: string): PluginHostRecord {
return {
id,
userId,
syncId: null,
name: null,
ip: "",
port: 22,
username: "",
authType: "password",
credentialId: null,
overrideCredentialUsername: false,
connectionType: "ssh",
tags: null,
folder: null,
parentHostId: null,
pin: false,
notes: null,
jumpHosts: [],
enableSsh: true,
sshPort: null,
statusCheckEnabled: true,
statusCheckInterval: null,
connectionOrigin: null,
sshOptions: {},
pluginSettings: {},
status: null,
localOnly: false,
createdAt: null,
updatedAt: null,
};
}
function applyHostInput(
record: PluginHostRecord,
input: PluginHostUpdateInput,
): PluginHostRecord {
const {
tags,
pluginSettings: _settings,
forceKeyboardInteractive: _fki,
...rest
} = input;
const next: PluginHostRecord = { ...record };
for (const [key, value] of Object.entries(rest)) {
if (value !== undefined)
(next as unknown as Record<string, unknown>)[key] = value;
}
if (tags !== undefined) {
next.tags = Array.isArray(tags) ? tags.join(",") : tags;
}
if (next.jumpHosts === null) next.jumpHosts = [];
if (next.sshOptions === null) next.sshOptions = {};
return next;
}
/**
* A context double good enough to call activate() against in a unit test.
* Nothing here is capability-checked: a test asserting a capability gate
@@ -823,14 +895,12 @@ export function createFakeContext(
create: async (
host: PluginHostCreateInput,
): Promise<PluginHostRecord> => {
checkHostInput(host);
const id = nextHostId++;
const record: PluginHostRecord = {
tags: null,
folder: null,
...host,
id,
userId: actor ?? "unknown",
};
const record = applyHostInput(
emptyHostRecord(id, actor ?? "unknown"),
host,
);
hostRecordsById.set(id, record);
return record;
},
@@ -838,9 +908,10 @@ export function createFakeContext(
hostId: number,
patch: PluginHostUpdateInput,
): Promise<PluginHostRecord | null> => {
checkHostInput(patch);
const existing = hostRecordsById.get(hostId);
if (!existing) return null;
const updated = { ...existing, ...patch };
const updated = applyHostInput(existing, patch);
hostRecordsById.set(hostId, updated);
return updated;
},
+3
View File
@@ -112,5 +112,8 @@
"aiEnableTitle": "Turn it on",
"aiEnableDesc": "Adds an assistant that reads your setup and suggests changes you approve. Needs a provider you supply, such as a local Ollama.",
"aiNote": "Nothing is sent anywhere until you add a provider and send a message."
},
"hosts": {
"docsLink": "View docs"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Laat die KI-assistent toe om in hierdie gasheer se terminaal te help. Standaard afgeskakel, en KI moet steeds vir jou rekening geaktiveer word."
}
}
},
"hosts": {
"docsLink": "Bekyk dokumente"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "اسمح للمساعد الذكي بالمساعدة في طرفية هذا المضيف. هذه الميزة معطلة افتراضيًا، ولا يزال يتعين تفعيلها لحسابك."
}
}
},
"hosts": {
"docsLink": "عرض المستندات"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Разрешете на AI асистента да помага в терминала на този хост. Изключено по подразбиране и все още изисква AI да е активиран за вашия акаунт."
}
}
},
"hosts": {
"docsLink": "Преглед на документи"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "এই হোস্টের টার্মিনালে সাহায্য করার জন্য এআই অ্যাসিস্ট্যান্টকে অনুমতি দিন। এটি ডিফল্টরূপে বন্ধ থাকে এবং আপনার অ্যাকাউন্টের জন্য এআই চালু করা প্রয়োজন।"
}
}
},
"hosts": {
"docsLink": "নথি দেখুন"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Permet que l'assistent d'IA ajudi al terminal d'aquest amfitrió. Desactivat per defecte, però encara cal que la IA estigui activada per al teu compte."
}
}
},
"hosts": {
"docsLink": "Veure documents"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Povolit asistentovi s umělou inteligencí pomáhat v terminálu tohoto hostitele. Ve výchozím nastavení vypnuto, ale stále vyžaduje, aby byla pro váš účet povolena umělá inteligence."
}
}
},
"hosts": {
"docsLink": "Zobrazit dokumenty"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Tillad AI-assistenten at hjælpe i denne værts terminal. Deaktiveret som standard, og kræver stadig, at AI er aktiveret for din konto."
}
}
},
"hosts": {
"docsLink": "Se dokumenter"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Erlauben Sie dem KI-Assistenten, im Terminal dieses Hosts Hilfe zu leisten. Standardmäßig deaktiviert; die KI muss weiterhin für Ihr Konto aktiviert sein."
}
}
},
"hosts": {
"docsLink": "Dokumentation anzeigen"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Επιτρέψτε στον βοηθό τεχνητής νοημοσύνης να βοηθά στο τερματικό αυτού του κεντρικού υπολογιστή. Απενεργοποιημένο από προεπιλογή και εξακολουθεί να χρειάζεται ενεργοποιημένη την τεχνητή νοημοσύνη για τον λογαριασμό σας."
}
}
},
"hosts": {
"docsLink": "Προβολή εγγράφων"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Permite que el asistente de IA te ayude en la terminal de este host. Está desactivado por defecto y aún así necesitas tener la IA habilitada para tu cuenta."
}
}
},
"hosts": {
"docsLink": "Ver documentación"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Salli tekoälyavustaja auttaa tämän isännän terminaalissa. Oletusarvoisesti pois päältä, mutta tekoälyn on silti oltava käytössä tililläsi."
}
}
},
"hosts": {
"docsLink": "Näytä dokumentit"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Autoriser l'assistant IA à vous aider dans le terminal de cet hôte. Désactivé par défaut ; l'IA doit être activée pour votre compte."
}
}
},
"hosts": {
"docsLink": "Voir la documentation"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "אפשר לעוזר הבינה המלאכותית לסייע במסוף של מארח זה. כבוי כברירת מחדל, ועדיין נדרשת הפעלת בינה מלאכותית עבור חשבונך."
}
}
},
"hosts": {
"docsLink": "הצג מסמכים"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "इस होस्ट के टर्मिनल में एआई सहायक को मदद करने की अनुमति दें। यह डिफ़ॉल्ट रूप से बंद है, लेकिन आपके खाते के लिए एआई को सक्षम करना आवश्यक है।"
}
}
},
"hosts": {
"docsLink": "दस्तावेज़ देखें"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Engedélyezi a mesterséges intelligencia asszisztensének a gazdagép terminálján való segítséget. Alapértelmezés szerint ki van kapcsolva, de továbbra is engedélyeznie kell a mesterséges intelligenciát a fiókjában."
}
}
},
"hosts": {
"docsLink": "Dokumentumok megtekintése"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Izinkan asisten AI untuk membantu di terminal host ini. Secara default dinonaktifkan, dan AI tetap perlu diaktifkan untuk akun Anda."
}
}
},
"hosts": {
"docsLink": "Lihat dokumen"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Consenti all'assistente IA di fornire assistenza nel terminale di questo host. Disattivato per impostazione predefinita, ma è necessario abilitare l'IA per il tuo account."
}
}
},
"hosts": {
"docsLink": "Visualizza documentazione"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "このホストのターミナルでAIアシスタントによる支援を許可します。デフォルトでは無効になっており、アカウントでAIを有効にする必要があります。"
}
}
},
"hosts": {
"docsLink": "ドキュメントを表示"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "이 호스트의 터미널에서 AI 도우미의 도움을 받을 수 있도록 허용합니다. 기본적으로 비활성화되어 있으며, 계정에 AI 기능이 활성화되어 있어야 합니다."
}
}
},
"hosts": {
"docsLink": "문서 보기"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Sta de AI-assistent toe om te helpen in de terminal van deze host. Standaard uitgeschakeld, maar AI moet nog steeds voor uw account zijn ingeschakeld."
}
}
},
"hosts": {
"docsLink": "Documenten bekijken"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Tillat at AI-assistenten hjelper til i denne vertens terminal. Av som standard, og krever fortsatt at AI er aktivert for kontoen din."
}
}
},
"hosts": {
"docsLink": "Vis dokumenter"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Zezwól asystentowi AI na pomoc w terminalu tego hosta. Domyślnie wyłączone, ale nadal wymaga włączenia AI na Twoim koncie."
}
}
},
"hosts": {
"docsLink": "Zobacz dokumentację"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Permita que o assistente de IA ajude no terminal deste host. Desativado por padrão, mas ainda precisa que a IA esteja ativada para sua conta."
}
}
},
"hosts": {
"docsLink": "Ver documentos"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Permita que o assistente de IA ajude no terminal deste host. Desativado por defeito, mas ainda precisa que a IA esteja ativada para a sua conta."
}
}
},
"hosts": {
"docsLink": "Ver documentação"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Permiteți asistentului AI să vă ajute în terminalul acestei gazde. Dezactivat în mod implicit, dar este nevoie ca AI să fie activat pentru contul dvs."
}
}
},
"hosts": {
"docsLink": "Vizualizați documentele"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Разрешите помощнику с искусственным интеллектом помогать на терминале этого хоста. По умолчанию отключено, но для вашей учетной записи ИИ все равно должен быть включен."
}
}
},
"hosts": {
"docsLink": "Документация"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Дозволите вештачкој интелигенцији да помогне у терминалу овог хоста. Искључено је подразумевано, а и даље је потребно да вештачка интелигенција буде омогућена за ваш налог."
}
}
},
"hosts": {
"docsLink": "Прикажи документе"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Tillåt AI-assistenten att hjälpa till i den här värdens terminal. Av som standard och kräver fortfarande att AI är aktiverat för ditt konto."
}
}
},
"hosts": {
"docsLink": "Visa dokument"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "อนุญาตให้ผู้ช่วย AI ช่วยเหลือในเทอร์มินัลของโฮสต์นี้ โดยค่าเริ่มต้นจะปิดอยู่ และยังคงต้องเปิดใช้งาน AI สำหรับบัญชีของคุณก่อน"
}
}
},
"hosts": {
"docsLink": "ดูเอกสาร"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Bu sunucunun terminalinde yapay zeka asistanının yardımcı olmasına izin verin. Varsayılan olarak kapalıdır ve hesabınız için yapay zekanın etkinleştirilmiş olması gerekir."
}
}
},
"hosts": {
"docsLink": "Dokümanları görüntüle"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Дозволити помічнику зі штучним інтелектом допомагати в терміналі цього хоста. Вимкнено за замовчуванням, але все одно потребує ввімкнення штучного інтелекту для вашого облікового запису."
}
}
},
"hosts": {
"docsLink": "Переглянути документи"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "Cho phép trợ lý AI hỗ trợ trong thiết bị đầu cuối của máy chủ này. Mặc định là tắt, nhưng bạn vẫn cần bật AI cho tài khoản của mình."
}
}
},
"hosts": {
"docsLink": "Xem tài liệu"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "允许 AI 助手在此主机的终端上提供帮助。默认情况下处于关闭状态,但仍需在您的帐户中启用 AI 功能。"
}
}
},
"hosts": {
"docsLink": "查看文档"
}
}
+3
View File
@@ -83,5 +83,8 @@
"description": "允許 AI 助理在此主機的終端機上提供協助。預設為關閉狀態,但仍需在您的帳戶中啟用 AI 功能。"
}
}
},
"hosts": {
"docsLink": "檢視文件"
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
import type { Client } from "ssh2";
import type { PluginHostUpdateInput } from "@termix/plugin-sdk/backend";
import { execCommand } from "@termix/plugin-sdk/host-commands";
import { getTool } from "./catalog.js";
import type { ToolDeps } from "./types.js";
@@ -93,7 +94,7 @@ export async function applyProposal(
const hostId = requireNumber(payload.hostId, "hostId");
const changes = (payload.changes ?? {}) as Record<string, unknown>;
const updates: Record<string, unknown> = {};
const updates: PluginHostUpdateInput = {};
if (changes.name !== undefined)
updates.name = requireString(changes.name, "name");
if (changes.ip !== undefined)
+11 -1
View File
@@ -112,7 +112,9 @@
"feature_docker_desc": "See containers, read logs and watch stats on any host running Docker."
},
"terminal": {
"retry": "Retry"
"retry": "Retry",
"clipboardReadFailed": "Failed to read from clipboard. Make sure clipboard permissions are granted.",
"clipboardWriteFailed": "Failed to copy to clipboard. Make sure the page is served over HTTPS or localhost."
},
"permissions": {
"use": {
@@ -133,5 +135,13 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Remote server required. Connect a remote server in Settings to use this connection type."
},
"hosts": {
"docsLink": "View docs",
"hostNotFound": "Host not found",
"loadingHost": "Loading host..."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Afstandbediener word benodig. Koppel 'n afstandbediener in Instellings om hierdie verbindingstipe te gebruik."
},
"hosts": {
"docsLink": "Bekyk dokumente",
"hostNotFound": "Gasheer nie gevind nie",
"loadingHost": "Laai gasheer..."
},
"terminal": {
"clipboardReadFailed": "Kon nie vanaf knipbord lees nie. Maak seker dat knipbordtoestemmings toegestaan is.",
"clipboardWriteFailed": "Kon nie na knipbord kopieer nie. Maak seker dat die bladsy oor HTTPS of localhost bedien word."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "يلزم وجود خادم بعيد. قم بتوصيل خادم بعيد في الإعدادات لاستخدام نوع الاتصال هذا."
},
"hosts": {
"docsLink": "عرض المستندات",
"hostNotFound": "المضيف غير موجود",
"loadingHost": "جارٍ تحميل المضيف..."
},
"terminal": {
"clipboardReadFailed": "فشلت القراءة من الحافظة. تأكد من منح أذونات الحافظة.",
"clipboardWriteFailed": "فشل النسخ إلى الحافظة. تأكد من تقديم الصفحة عبر HTTPS أو localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Подман"
}
}
},
"errors": {
"remoteServerRequired": "Изисква се отдалечен сървър. Свържете се с отдалечен сървър в „Настройки“, за да използвате този тип връзка."
},
"hosts": {
"docsLink": "Преглед на документи",
"hostNotFound": "Хостът не е намерен",
"loadingHost": "Зареждане на хоста..."
},
"terminal": {
"clipboardReadFailed": "Четенето от клипборда не бе успешно. Уверете се, че са предоставени разрешения за достъп до клипборда.",
"clipboardWriteFailed": "Копирането в буфера не бе успешно. Уверете се, че страницата се предоставя през HTTPS или localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "পডম্যান"
}
}
},
"errors": {
"remoteServerRequired": "রিমোট সার্ভার প্রয়োজন। এই সংযোগের ধরণটি ব্যবহার করতে সেটিংস-এ একটি রিমোট সার্ভার সংযুক্ত করুন।"
},
"hosts": {
"docsLink": "নথি দেখুন",
"hostNotFound": "হোস্ট খুঁজে পাওয়া যায়নি",
"loadingHost": "হোস্ট লোড হচ্ছে..."
},
"terminal": {
"clipboardReadFailed": "ক্লিপবোর্ড থেকে পড়তে ব্যর্থ হয়েছে। নিশ্চিত করুন যে ক্লিপবোর্ডের অনুমতি দেওয়া আছে।",
"clipboardWriteFailed": "ক্লিপবোর্ডে কপি করা সম্ভব হয়নি। নিশ্চিত করুন যে পৃষ্ঠাটি HTTPS বা লোকালহোস্টের মাধ্যমে পরিবেশিত হচ্ছে।"
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Cal un servidor remot. Connecteu un servidor remot a Configuració per utilitzar aquest tipus de connexió."
},
"hosts": {
"docsLink": "Veure documents",
"hostNotFound": "No s'ha trobat l'amfitrió",
"loadingHost": "S'està carregant l'amfitrió..."
},
"terminal": {
"clipboardReadFailed": "No s'ha pogut llegir del porta-retalls. Assegureu-vos que els permisos del porta-retalls estiguin concedits.",
"clipboardWriteFailed": "No s'ha pogut copiar al porta-retalls. Assegureu-vos que la pàgina es serveix per HTTPS o localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Je vyžadován vzdálený server. Pro použití tohoto typu připojení se připojte ke vzdálenému serveru v Nastavení."
},
"hosts": {
"docsLink": "Zobrazit dokumenty",
"hostNotFound": "Hostitel nenalezen",
"loadingHost": "Načítání hostitele..."
},
"terminal": {
"clipboardReadFailed": "Čtení ze schránky se nezdařilo. Ujistěte se, že máte povolena přístup ke schránce.",
"clipboardWriteFailed": "Kopírování do schránky se nezdařilo. Ujistěte se, že stránka je zobrazována přes HTTPS nebo localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Fjernserver kræves. Opret forbindelse til en fjernserver i Indstillinger for at bruge denne forbindelsestype."
},
"hosts": {
"docsLink": "Se dokumenter",
"hostNotFound": "Værten blev ikke fundet",
"loadingHost": "Indlæser vært..."
},
"terminal": {
"clipboardReadFailed": "Kunne ikke læse fra udklipsholderen. Sørg for, at der er givet tilladelse til udklipsholderen.",
"clipboardWriteFailed": "Kunne ikke kopiere til udklipsholder. Sørg for, at siden serveres via HTTPS eller localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Remote-Server erforderlich. Um diesen Verbindungstyp zu verwenden, verbinden Sie einen Remote-Server in den Einstellungen."
},
"hosts": {
"docsLink": "Dokumentation anzeigen",
"hostNotFound": "Host nicht gefunden",
"loadingHost": "Host wird geladen..."
},
"terminal": {
"clipboardReadFailed": "Lesen aus der Zwischenablage fehlgeschlagen. Stellen Sie sicher, dass die Zwischenablageberechtigungen erteilt wurden.",
"clipboardWriteFailed": "Kopieren in die Zwischenablage fehlgeschlagen. Stellen Sie sicher, dass die Seite über HTTPS oder localhost bereitgestellt wird."
}
}
@@ -114,5 +114,17 @@
"podman": "Πόντμαν"
}
}
},
"errors": {
"remoteServerRequired": "Απαιτείται απομακρυσμένος διακομιστής. Συνδέστε έναν απομακρυσμένο διακομιστή στις Ρυθμίσεις για να χρησιμοποιήσετε αυτόν τον τύπο σύνδεσης."
},
"hosts": {
"docsLink": "Προβολή εγγράφων",
"hostNotFound": "Δεν βρέθηκε κεντρικός υπολογιστής",
"loadingHost": "Φόρτωση κεντρικού υπολογιστή..."
},
"terminal": {
"clipboardReadFailed": "Αποτυχία ανάγνωσης από το πρόχειρο. Βεβαιωθείτε ότι έχουν εκχωρηθεί δικαιώματα στο πρόχειρο.",
"clipboardWriteFailed": "Αποτυχία αντιγραφής στο πρόχειρο. Βεβαιωθείτε ότι η σελίδα προβάλλεται μέσω HTTPS ή localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Se requiere un servidor remoto. Conecte un servidor remoto en Configuración para usar este tipo de conexión."
},
"hosts": {
"docsLink": "Ver documentación",
"hostNotFound": "Host no encontrado",
"loadingHost": "Cargando host..."
},
"terminal": {
"clipboardReadFailed": "No se pudo leer del portapapeles. Asegúrese de que los permisos del portapapeles estén concedidos.",
"clipboardWriteFailed": "Error al copiar al portapapeles. Asegúrese de que la página se sirva a través de HTTPS o en localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Etäpalvelin vaaditaan. Yhdistä etäpalvelin asetuksissa käyttääksesi tätä yhteystyyppiä."
},
"hosts": {
"docsLink": "Näytä dokumentit",
"hostNotFound": "Isäntää ei löydy",
"loadingHost": "Ladataan isäntää..."
},
"terminal": {
"clipboardReadFailed": "Leikepöydän lukeminen epäonnistui. Varmista, että leikepöydän käyttöoikeudet on myönnetty.",
"clipboardWriteFailed": "Kopiointi leikepöydälle epäonnistui. Varmista, että sivua käytetään HTTPS:n tai paikallisen isännän kautta."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Serveur distant requis. Connectez un serveur distant dans les paramètres pour utiliser ce type de connexion."
},
"hosts": {
"docsLink": "Voir la documentation",
"hostNotFound": "Hôte introuvable",
"loadingHost": "Chargement de l'hôte..."
},
"terminal": {
"clipboardReadFailed": "Échec de la lecture du presse-papiers. Assurez-vous que les autorisations du presse-papiers sont accordées.",
"clipboardWriteFailed": "Échec de la copie dans le presse-papiers. Assurez-vous que la page est servie en HTTPS ou localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "פודמן"
}
}
},
"errors": {
"remoteServerRequired": "נדרש שרת מרוחק. יש להתחבר לשרת מרוחק בהגדרות כדי להשתמש בסוג חיבור זה."
},
"hosts": {
"docsLink": "הצג מסמכים",
"hostNotFound": "המארח לא נמצא",
"loadingHost": "טוען מארח..."
},
"terminal": {
"clipboardReadFailed": "הקריאה מהלוח נכשלה. ודא שהרשאות הלוח ניתנות.",
"clipboardWriteFailed": "ההעתקה ללוח נכשלה. ודא שהדף מוגש דרך HTTPS או localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "रिमोट सर्वर आवश्यक है। इस कनेक्शन प्रकार का उपयोग करने के लिए सेटिंग्स में जाकर रिमोट सर्वर कनेक्ट करें।"
},
"hosts": {
"docsLink": "दस्तावेज़ देखें",
"hostNotFound": "होस्ट नहीं मिला",
"loadingHost": "होस्ट लोड हो रहा है..."
},
"terminal": {
"clipboardReadFailed": "क्लिपबोर्ड से पढ़ने में विफल। सुनिश्चित करें कि क्लिपबोर्ड अनुमतियाँ दी गई हैं।",
"clipboardWriteFailed": "क्लिपबोर्ड पर कॉपी करने में विफल। सुनिश्चित करें कि पेज HTTPS या लोकलहोस्ट पर सर्व किया गया है।"
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Távoli szerver szükséges. Csatlakoztasson egy távoli szervert a Beállításokban a kapcsolattípus használatához."
},
"hosts": {
"docsLink": "Dokumentumok megtekintése",
"hostNotFound": "Nem található gazdagép",
"loadingHost": "Gazdagép betöltése..."
},
"terminal": {
"clipboardReadFailed": "Nem sikerült beolvasni a vágólapról. Győződjön meg arról, hogy a vágólapra vonatkozó engedélyek meg vannak adva.",
"clipboardWriteFailed": "Nem sikerült a vágólapra másolni. Győződjön meg arról, hogy az oldal HTTPS vagy localhost protokollon keresztül jelenik meg."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Diperlukan server jarak jauh. Hubungkan server jarak jauh di Pengaturan untuk menggunakan jenis koneksi ini."
},
"hosts": {
"docsLink": "Lihat dokumen",
"hostNotFound": "Host tidak ditemukan",
"loadingHost": "Memuat host..."
},
"terminal": {
"clipboardReadFailed": "Gagal membaca dari clipboard. Pastikan izin clipboard telah diberikan.",
"clipboardWriteFailed": "Gagal menyalin ke papan klip. Pastikan halaman disajikan melalui HTTPS atau localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "È necessario un server remoto. Per utilizzare questo tipo di connessione, collega un server remoto nelle Impostazioni."
},
"hosts": {
"docsLink": "Visualizza documentazione",
"hostNotFound": "Host non trovato",
"loadingHost": "Caricamento host..."
},
"terminal": {
"clipboardReadFailed": "Lettura dagli appunti non riuscita. Assicurati che i permessi degli appunti siano stati concessi.",
"clipboardWriteFailed": "Copia negli appunti non riuscita. Assicurati che la pagina sia servita via HTTPS o localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "リモートサーバーが必要です。この接続タイプを使用するには、設定でリモートサーバーを接続してください。"
},
"hosts": {
"docsLink": "ドキュメントを表示",
"hostNotFound": "ホストが見つかりません",
"loadingHost": "ホストを読み込み中..."
},
"terminal": {
"clipboardReadFailed": "クリップボードからの読み取りに失敗しました。クリップボードのアクセス許可が付与されていることを確認してください。",
"clipboardWriteFailed": "クリップボードへのコピーに失敗しました。ページがHTTPSまたはlocalhostで提供されていることを確認してください。"
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "원격 서버가 필요합니다. 이 연결 유형을 사용하려면 설정에서 원격 서버를 연결하세요."
},
"hosts": {
"docsLink": "문서 보기",
"hostNotFound": "호스트를 찾을 수 없습니다",
"loadingHost": "호스트 로드 중..."
},
"terminal": {
"clipboardReadFailed": "클립보드에서 읽지 못했습니다. 클립보드 권한이 허용되었는지 확인하세요.",
"clipboardWriteFailed": "클립보드에 복사하지 못했습니다. 페이지가 HTTPS 또는 localhost에서 제공되는지 확인하세요."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Externe server vereist. Verbind een externe server in de instellingen om dit verbindingstype te gebruiken."
},
"hosts": {
"docsLink": "Documenten bekijken",
"hostNotFound": "Host niet gevonden",
"loadingHost": "Host wordt geladen..."
},
"terminal": {
"clipboardReadFailed": "Het lezen van het klembord is mislukt. Zorg ervoor dat de juiste klembordrechten zijn verleend.",
"clipboardWriteFailed": "Kopiëren naar klembord mislukt. Zorg ervoor dat de pagina via HTTPS of localhost wordt aangeboden."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Ekstern server kreves. Koble til en ekstern server i Innstillinger for å bruke denne tilkoblingstypen."
},
"hosts": {
"docsLink": "Vis dokumenter",
"hostNotFound": "Verten ble ikke funnet",
"loadingHost": "Laster inn vert ..."
},
"terminal": {
"clipboardReadFailed": "Kunne ikke lese fra utklippstavlen. Sørg for at utklippstavlen har tillatelser.",
"clipboardWriteFailed": "Kunne ikke kopiere til utklippstavlen. Sørg for at siden serveres via HTTPS eller localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Wymagany jest serwer zdalny. Połącz się z serwerem zdalnym w Ustawieniach, aby korzystać z tego typu połączenia."
},
"hosts": {
"docsLink": "Zobacz dokumentację",
"hostNotFound": "Nie znaleziono hosta",
"loadingHost": "Ładowanie hosta..."
},
"terminal": {
"clipboardReadFailed": "Nie udało się odczytać danych ze schowka. Upewnij się, że uprawnienia do schowka zostały przyznane.",
"clipboardWriteFailed": "Nie udało się skopiować do schowka. Upewnij się, że strona jest serwowana przez HTTPS lub localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "É necessário um servidor remoto. Conecte um servidor remoto nas Configurações para usar este tipo de conexão."
},
"hosts": {
"docsLink": "Ver documentos",
"hostNotFound": "Host não encontrado",
"loadingHost": "Carregando host..."
},
"terminal": {
"clipboardReadFailed": "Não foi possível ler o conteúdo da área de transferência. Certifique-se de que as permissões de acesso à área de transferência estejam concedidas.",
"clipboardWriteFailed": "Falha ao copiar para a área de transferência. Certifique-se de que a página esteja sendo servida via HTTPS ou localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "É necessário um servidor remoto. Ligue um servidor remoto nas Definições para utilizar este tipo de ligação."
},
"hosts": {
"docsLink": "Ver documentação",
"hostNotFound": "Host não encontrado",
"loadingHost": "A carregar o host..."
},
"terminal": {
"clipboardReadFailed": "Erro ao ler da área de transferência. Certifique-se de que as permissões da área de transferência foram concedidas.",
"clipboardWriteFailed": "Erro ao copiar para a área de transferência. Certifique-se de que a página é servida via HTTPS ou localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Este necesar un server la distanță. Conectați un server la distanță în Setări pentru a utiliza acest tip de conexiune."
},
"hosts": {
"docsLink": "Vizualizați documentele",
"hostNotFound": "Gazdă negăsită",
"loadingHost": "Se încarcă gazda..."
},
"terminal": {
"clipboardReadFailed": "Citirea din clipboard nu a reușit. Asigurați-vă că permisiunile de acces la clipboard sunt acordate.",
"clipboardWriteFailed": "Copierea în clipboard nu a reușit. Asigurați-vă că pagina este servită prin HTTPS sau localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Требуется удаленный сервер. Для использования этого типа подключения подключите удаленный сервер в настройках."
},
"hosts": {
"docsLink": "Документация",
"hostNotFound": "Хост не найден",
"loadingHost": "Загрузка хоста..."
},
"terminal": {
"clipboardReadFailed": "Не удалось прочитать из буфера обмена. Убедитесь, что предоставлены разрешения на доступ к буферу обмена.",
"clipboardWriteFailed": "Не удалось скопировать в буфер обмена. Убедитесь, что страница загружена по HTTPS или с localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Подман"
}
}
},
"errors": {
"remoteServerRequired": "Потребан је удаљени сервер. Повежите се са удаљеним сервером у Подешавањима да бисте користили овај тип везе."
},
"hosts": {
"docsLink": "Прикажи документе",
"hostNotFound": "Хост није пронађен",
"loadingHost": "Учитавање хоста..."
},
"terminal": {
"clipboardReadFailed": "Читање из међуспремника није успело. Уверите се да су дозволе за међуспремник одобрене.",
"clipboardWriteFailed": "Копирање у међуспремник није успело. Уверите се да се страница приказује преко HTTPS-а или localhost-а."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Fjärrserver krävs. Anslut en fjärrserver i Inställningar för att använda den här anslutningstypen."
},
"hosts": {
"docsLink": "Visa dokument",
"hostNotFound": "Värden hittades inte",
"loadingHost": "Laddar värd..."
},
"terminal": {
"clipboardReadFailed": "Kunde inte läsa från urklipp. Kontrollera att behörigheter för urklipp är beviljade.",
"clipboardWriteFailed": "Kunde inte kopiera till urklipp. Kontrollera att sidan serveras via HTTPS eller localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "พอดแมน"
}
}
},
"errors": {
"remoteServerRequired": "จำเป็นต้องใช้เซิร์ฟเวอร์ระยะไกล เชื่อมต่อเซิร์ฟเวอร์ระยะไกลในการตั้งค่าเพื่อใช้ประเภทการเชื่อมต่อนี้"
},
"hosts": {
"docsLink": "ดูเอกสาร",
"hostNotFound": "ไม่พบโฮสต์",
"loadingHost": "กำลังโหลดโฮสต์..."
},
"terminal": {
"clipboardReadFailed": "ไม่สามารถอ่านข้อมูลจากคลิปบอร์ดได้ โปรดตรวจสอบให้แน่ใจว่าได้ให้สิทธิ์การเข้าถึงคลิปบอร์ดแล้ว",
"clipboardWriteFailed": "ไม่สามารถคัดลอกไปยังคลิปบอร์ดได้ โปรดตรวจสอบให้แน่ใจว่าหน้าเว็บนั้นให้บริการผ่าน HTTPS หรือ localhost"
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Uzak sunucu gereklidir. Bu bağlantı türünü kullanmak için Ayarlar'dan bir uzak sunucu bağlayın."
},
"hosts": {
"docsLink": "Dokümanları görüntüle",
"hostNotFound": "Host bulunamadı",
"loadingHost": "Host yükleniyor..."
},
"terminal": {
"clipboardReadFailed": "Panodan okuma başarısız oldu. Pano izinlerinin verildiğinden emin olun.",
"clipboardWriteFailed": "Panoya kopyalama başarısız oldu. Sayfanın HTTPS veya localhost üzerinden sunulduğundan emin olun."
}
}
@@ -114,5 +114,17 @@
"podman": "Подман"
}
}
},
"errors": {
"remoteServerRequired": "Потрібен віддалений сервер. Підключіться до віддаленого сервера в налаштуваннях, щоб використовувати цей тип підключення."
},
"hosts": {
"docsLink": "Переглянути документи",
"hostNotFound": "Хост не знайдено",
"loadingHost": "Завантаження хоста..."
},
"terminal": {
"clipboardReadFailed": "Не вдалося прочитати з буфера обміну. Переконайтеся, що надано дозволи на доступ до буфера обміну.",
"clipboardWriteFailed": "Не вдалося скопіювати в буфер обміну. Переконайтеся, що сторінка обслуговується через HTTPS або localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "Cần có máy chủ từ xa. Kết nối máy chủ từ xa trong Cài đặt để sử dụng loại kết nối này."
},
"hosts": {
"docsLink": "Xem tài liệu",
"hostNotFound": "Không tìm thấy máy chủ",
"loadingHost": "Đang tải máy chủ..."
},
"terminal": {
"clipboardReadFailed": "Đọc từ clipboard thất bại. Đảm bảo quyền truy cập clipboard đã được cấp.",
"clipboardWriteFailed": "Sao chép vào clipboard thất bại. Đảm bảo trang được phục vụ qua HTTPS hoặc localhost."
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "需要远程服务器。请在“设置”中连接远程服务器以使用此连接类型。"
},
"hosts": {
"docsLink": "查看文档",
"hostNotFound": "未找到主机",
"loadingHost": "正在加载主机..."
},
"terminal": {
"clipboardReadFailed": "从剪贴板读取失败。请确保已授予剪贴板权限。",
"clipboardWriteFailed": "复制到剪贴板失败。请确保页面通过 HTTPS 或 localhost 提供服务。"
}
}
@@ -114,5 +114,17 @@
"podman": "Podman"
}
}
},
"errors": {
"remoteServerRequired": "需要遠端伺服器。請在「設定」中連接遠端伺服器以使用此連線類型。"
},
"hosts": {
"docsLink": "檢視文件",
"hostNotFound": "找不到主機",
"loadingHost": "正在載入主機..."
},
"terminal": {
"clipboardReadFailed": "從剪貼簿讀取失敗。請確認已授予剪貼簿權限。",
"clipboardWriteFailed": "複製到剪貼簿失敗。請確認頁面是透過 HTTPS 或 localhost 提供。"
}
}
+2 -4
View File
@@ -2,7 +2,7 @@ import { ConnectionScreen, FullScreenAppWrapper } from "@termix/plugin-sdk/ui";
import React from "react";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { DockerManager } from "./DockerManager.tsx";
import { toDockerHost } from "./types";
import { toDockerHost, type DockerHostSource } from "./types";
interface DockerAppProps {
hostId?: string;
@@ -37,9 +37,7 @@ const DockerApp: React.FC<DockerAppProps> = ({ hostId }) => {
return (
<DockerManager
host={toDockerHost(
hostConfig as unknown as Record<string, unknown>,
)}
host={toDockerHost(hostConfig as unknown as DockerHostSource)}
title={hostConfig.name || `${hostConfig.username}@${hostConfig.ip}`}
isVisible={true}
isTopbarOpen={false}
@@ -90,10 +90,7 @@ function DockerManagerInner({
// standalone window has no shell, so it keeps the host it was given.
const liveRecord = useHost(host?.id);
const currentHost = React.useMemo(
() =>
liveRecord
? toDockerHost(liveRecord as unknown as Record<string, unknown>)
: host,
() => (liveRecord ? toDockerHost(liveRecord) : host),
[liveRecord, host],
);
const enabled = dockerEnabled(currentHost);
+1 -1
View File
@@ -27,7 +27,7 @@ function DockerWidget({
);
}
const host = toDockerHost(record as unknown as Record<string, unknown>);
const host = toDockerHost(record);
return (
<div className="flex flex-col w-full h-full overflow-hidden">
<WidgetTitle title={widget.title} icon={<Box size={11} />} />
+2 -2
View File
@@ -9,10 +9,10 @@ import type {
import { DockerManager } from "./DockerManager";
import DockerApp from "./DockerApp";
import { dockerWidget } from "./DockerWidget";
import { dockerEnabled, toDockerHost } from "./types";
import { dockerEnabled, toDockerHost, type DockerHostSource } from "./types";
function DockerTab({ host, sshHost, label, isVisible }: TabProps) {
const record = (host ?? sshHost) as Record<string, unknown> | undefined;
const record = host ?? (sshHost as DockerHostSource | undefined);
return (
<DockerManager
host={record ? toDockerHost(record) : undefined}
+14 -2
View File
@@ -59,11 +59,23 @@ export interface DockerHost {
pluginSettings?: Record<string, Record<string, unknown> | undefined>;
}
/** The fields toDockerHost reads from a shell or API host. */
export type DockerHostSource = Omit<DockerHost, "id" | "name"> & {
id: string | number;
name?: string | null;
};
/** Any host record the shell or an API hands over, as a DockerHost. */
export function toDockerHost(record: Record<string, unknown>): DockerHost {
export function toDockerHost(record: DockerHostSource): DockerHost {
return {
...(record as unknown as DockerHost),
id: Number(record.id),
name: record.name ?? undefined,
ip: record.ip,
port: record.port,
username: record.username,
syncId: record.syncId ?? null,
connectionOrigin: record.connectionOrigin ?? null,
pluginSettings: record.pluginSettings,
};
}
+113 -2
View File
@@ -360,7 +360,15 @@
"cannotLoadPdf": "Cannot load PDF",
"pdfLoadError": "There was an error loading this PDF file.",
"loadingPdf": "Loading PDF...",
"loadingPage": "Loading page..."
"loadingPage": "Loading page...",
"cancel": "Cancel",
"copiedItems_one": "Copied {{count}} item",
"copiedItems_other": "Copied {{count}} items",
"deleteCopiedFileFailed": "Could not delete the copy of {{name}}: {{error}}",
"dragMovedItems_one": "Moved {{count}} item to {{target}}",
"dragMovedItems_other": "Moved {{count}} items to {{target}}",
"moveBackFileFailed": "Could not move {{name}} back: {{error}}",
"terminal": "Terminal: {{host}} ({{path}})"
},
"sftpTransfer": {
"title": "SFTP",
@@ -409,6 +417,109 @@
"hosts": {
"fileManager": "File Manager",
"fileManagerUrlCopied": "File Manager URL copied",
"copyFileManagerUrlAction": "Copy File Manager URL"
"copyFileManagerUrlAction": "Copy File Manager URL",
"docsLink": "View docs",
"hostNotFound": "Host not found",
"loadingHost": "Loading host..."
},
"onboarding": {
"feature_files": "File manager",
"feature_files_desc": "Browse, upload, download and edit files over SFTP without leaving the app."
},
"terminal": {
"runTitle": "Running {{command}} - {{host}}",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Browse destination folders",
"browsePathError": "Could not open this path on the destination host.",
"browsePathWillBeCreated": "This folder does not exist yet. It will be created when the transfer starts.",
"cancel": "Cancel",
"cleanupDestFiles": "Clean up destination",
"cleanupDestFilesError": "Cleanup failed",
"cleanupDestFilesNothing": "Nothing to clean up on the destination",
"cleanupDestFilesPartial": "Some partial files could not be removed",
"cleanupDestFilesSuccess": "Removed partial files from the destination",
"confirmCopy": "Copy",
"confirmMove": "Move",
"copyFolderToHost": "Copy folder to host…",
"copyItemsToHost": "Copy {{count}} items to host…",
"copyToHost": "Copy to host…",
"destinationPath": "Destination path",
"destMustBeDirectory": "Destination must be a directory for multi-item transfers",
"goUp": "Go up",
"hostAuthRequired": "Authentication required — open File Manager on this host first",
"hostConnecting": "Connecting…",
"hostConnectionFailed": "Connection failed",
"hostDisconnected": "Not connected",
"hostReady": "Ready",
"itemsSummary": "{{count}} items",
"jumpHostLimitation": "Both hosts must be reachable from the Termix server. Direct host-to-host routing is not supported.",
"methodAuto": "Auto",
"methodAutoHint": "Picks tar or per-file SFTP based on file count, size, and compressibility. Single files always use streaming SFTP.",
"methodItemSftp": "Per-file SFTP",
"methodItemSftpHint": "Transfer each file individually over SFTP. Works on all hosts including Windows.",
"methodItemSftpLimitation": "Each file uses the same SFTP stream as a single-file copy, one after another. Progress is combined across all files, so the bar moves slowly during large files.",
"methodLabel": "Transfer method",
"methodPreviewError": "Could not preview transfer method. The server will still pick a method when you start.",
"methodPreviewLoading": "Calculating transfer method…",
"methodPreviewScanSummary": "{{fileCount}} files, {{totalSize}} total (scanned on source host).",
"methodPreviewWillUseItemSftp": "Will use: Per-file SFTP",
"methodPreviewWillUseTar": "Will use: Tar archive",
"methodReason": {
"user_item_sftp": "You chose per-file SFTP.",
"user_tar": "You chose tar archive.",
"tar_unavailable": "Tar is not available on one or both hosts — per-file SFTP will be used instead.",
"windows_host": "A Windows host is involved — tar is not used.",
"auto_multi_large": "Auto: multiple files including a large file ({{largestSize}}) with compressible data — tar bundles into one transfer.",
"auto_single_large_in_archive": "Auto: one large file ({{largestSize}}) in this set — per-file SFTP.",
"auto_many_incompressible": "Auto: mostly incompressible data — per-file SFTP.",
"auto_many_files": "Auto: many files ({{fileCount}}) — tar reduces per-file overhead.",
"auto_default": "Auto: per-file SFTP for this set."
},
"methodTar": "Tar archive",
"methodTarHint": "Compress on source, transfer one archive, extract on destination. Requires tar on both Unix hosts.",
"metricsCompress": "Compress on source: {{duration}}",
"metricsExtract": "Extract on destination: {{duration}}",
"metricsPrepare": "Prepare destination: {{duration}}",
"metricsRouteBenchmark": "Route probe — direct: {{direct}}, relay: {{relay}}",
"metricsSourceDelete": "Remove from source: {{duration}}",
"metricsTotal": "Total: {{duration}}",
"metricsTransfer": "End-to-end: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 verified: {{duration}}",
"moveFolderToHost": "Move folder to host…",
"moveItemsToHost": "Move {{count}} items to host…",
"moveToHost": "Move to host…",
"noHostsConnected": "No other file-manager hosts available.",
"noHostsConnectedHint": "Add another SSH host with File Manager enabled in Host Manager.",
"parallelSegmentsHint": "Large files are split into 256 MB chunks. Multiple lanes use separate connections (like starting several transfers) for higher total throughput.",
"parallelSegmentsLabel": "Parallel transfer lanes",
"parallelSegmentsOption": "{{count}} lanes",
"progressBenchmarking": "Selecting the fastest transfer route…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Cancel",
"progressCancelling": "Cancelling…",
"progressCompressing": "Compressing on source host…",
"progressExtracting": "Extracting on destination…",
"progressItems": "{{current}} / {{total}} files",
"progressReconnecting": "Reconnecting…",
"progressStalled": "Stalled",
"progressTotalSpeed": "{{speed}} total ({{lanes}} lanes)",
"progressTransferring": "Transferring data…",
"progressTransferringItems": "Transferring files ({{current}} of {{total}})…",
"progressVerifying": "Verifying file integrity…",
"recentDestinations": "Recent destinations",
"resumedHint": "Reconnected to an active transfer started in another window.",
"retryTransfer": "Retry",
"retryTransferError": "Retry failed",
"selectDestinationHost": "Select destination host",
"transferCancelled": "Transfer cancelled",
"transferCancelledCopyHint": "Partial files may remain on the destination.",
"transferCancelledMoveHint": "Partial files may remain on the destination. Source files were not removed.",
"transferError": "Transfer failed",
"transferFailedRetryHint": "Partial data was kept on the destination. Retry will resume when the connection is back.",
"transferPartialHint": "Could not transfer: {{paths}}",
"transferSuccess": "Transfer complete"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Standaardpad",
"fileManagerPathHint": "Die gids om oop te maak wanneer die lêerbestuurder vir hierdie gasheer begin.",
"fileManagerUrlCopied": "Lêerbestuurder-URL gekopieer",
"copyFileManagerUrlAction": "Kopieer Lêerbestuurder URL"
"copyFileManagerUrlAction": "Kopieer Lêerbestuurder URL",
"docsLink": "Bekyk dokumente",
"hostNotFound": "Gasheer nie gevind nie",
"loadingHost": "Laai gasheer..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Lêers"
},
"onboarding": {
"feature_files": "Lêerbestuurder",
"feature_files_desc": "Blaai, laai op, laai af en wysig lêers via SFTP sonder om die toepassing te verlaat."
},
"terminal": {
"runTitle": "Hardloop {{command}} - {{host}}",
"terminalTitle": "Terminaal - {{host}}",
"terminalWithPath": "Terminaal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Blaai deur bestemmingsmappe",
"browsePathError": "Kon nie hierdie pad op die bestemmingsgasheer oopmaak nie.",
"browsePathWillBeCreated": "Hierdie vouer bestaan nog nie. Dit sal geskep word wanneer die oordrag begin.",
"cancel": "Kanselleer",
"cleanupDestFiles": "Maak bestemming skoon",
"cleanupDestFilesError": "Opruiming het misluk",
"cleanupDestFilesNothing": "Niks om op die bestemming op te ruim nie",
"cleanupDestFilesPartial": "Sommige gedeeltelike lêers kon nie verwyder word nie",
"cleanupDestFilesSuccess": "Gedeeltelike lêers van die bestemming verwyder",
"confirmCopy": "Kopieer",
"confirmMove": "Beweeg",
"copyFolderToHost": "Kopieer lêergids na gasheer…",
"copyItemsToHost": "Kopieer {{count}} items om… aan te bied",
"copyToHost": "Kopieer na gasheer…",
"destinationPath": "Bestemmingspad",
"destMustBeDirectory": "Bestemming moet 'n gids wees vir oordragte van verskeie items",
"goUp": "Gaan op",
"hostAuthRequired": "Verifikasie vereis — maak eers Lêerbestuurder op hierdie gasheer oop",
"hostConnecting": "Verbind…",
"hostConnectionFailed": "Verbinding het misluk",
"hostDisconnected": "Nie gekoppel nie",
"hostReady": "Gereed",
"itemsSummary": "{{count}} items",
"jumpHostLimitation": "Beide gashere moet vanaf die Termix-bediener bereikbaar wees. Direkte gasheer-tot-gasheer-roetering word nie ondersteun nie.",
"methodAuto": "Outomaties",
"methodAutoHint": "Kies tar- of per-lêer SFTP gebaseer op lêertelling, grootte en saampersbaarheid. Enkele lêers gebruik altyd stroom-SFTP.",
"methodItemSftp": "SFTP per lêer",
"methodItemSftpHint": "Dra elke lêer individueel oor SFTP. Werk op alle gashere, insluitend Windows.",
"methodItemSftpLimitation": "Elke lêer gebruik dieselfde SFTP-stroom as 'n enkellêerkopie, een na die ander. Vordering word oor alle lêers gekombineer, so die balk beweeg stadig tydens groot lêers.",
"methodLabel": "Oordragmetode",
"methodPreviewError": "Kon nie oordragmetode voorskou nie. Die bediener sal steeds 'n metode kies wanneer jy begin.",
"methodPreviewLoading": "Berekening van oordragmetode…",
"methodPreviewScanSummary": "{{fileCount}} lêers, {{totalSize}} totaal (geskandeer op brongasheer).",
"methodPreviewWillUseItemSftp": "Sal gebruik: SFTP per lêer",
"methodPreviewWillUseTar": "Sal gebruik: Tar-argief",
"methodReason": {
"user_item_sftp": "Jy het SFTP per lêer gekies.",
"user_tar": "Jy het teer-argief gekies.",
"tar_unavailable": "Teer is nie beskikbaar op een of albei gashere nie — SFTP per lêer sal eerder gebruik word.",
"windows_host": "'n Windows-gasheer is betrokke — teer word nie gebruik nie.",
"auto_multi_large": "Outomaties: veelvuldige lêers, insluitend 'n groot lêer ({{largestSize}}) met saampersbare data — teer bundels in een oordrag.",
"auto_single_large_in_archive": "Outomaties: een groot lêer ({{largestSize}}) in hierdie stel — SFTP per lêer.",
"auto_many_incompressible": "Outomaties: meestal onsaampersbare data — SFTP per lêer.",
"auto_many_files": "Outomaties: baie lêers ({{fileCount}}) — teer verminder oorhoofse koste per lêer.",
"auto_default": "Outomaties: SFTP per lêer vir hierdie stel."
},
"methodTar": "Teer-argief",
"methodTarHint": "Komprimeer op bron, dra een argief oor, onttrek op bestemming. Vereis tar op beide Unix-gashere.",
"metricsCompress": "Kompresseer op bron: {{duration}}",
"metricsExtract": "Uittreksel op bestemming: {{duration}}",
"metricsPrepare": "Berei bestemming voor: {{duration}}",
"metricsRouteBenchmark": "Roete-sonde — direk: {{direct}}, aflos: {{relay}}",
"metricsSourceDelete": "Verwyder van bron: {{duration}}",
"metricsTotal": "Totaal: {{duration}}",
"metricsTransfer": "Van begin tot einde: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 geverifieer: {{duration}}",
"moveFolderToHost": "Skuif vouer na gasheer…",
"moveItemsToHost": "Skuif {{count}} items om… te huisves",
"moveToHost": "Skuif na gasheer…",
"noHostsConnected": "Geen ander lêerbestuurder-gashere beskikbaar nie.",
"noHostsConnectedHint": "Voeg nog 'n SSH-gasheer by met Lêerbestuurder geaktiveer in Gasheerbestuurder.",
"parallelSegmentsHint": "Groot lêers word in 256 MB-stukke verdeel. Verskeie bane gebruik afsonderlike verbindings (soos om verskeie oordragte te begin) vir hoër totale deurset.",
"parallelSegmentsLabel": "Parallelle oordragbane",
"parallelSegmentsOption": "{{count}} bane",
"progressBenchmarking": "Die vinnigste oordragroete kies…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Kanselleer",
"progressCancelling": "Kanselleer…",
"progressCompressing": "Kompressering op brongasheer…",
"progressExtracting": "Onttrek op bestemming…",
"progressItems": "{{current}} / {{total}} lêers",
"progressReconnecting": "Herverbind…",
"progressStalled": "Vasgevang",
"progressTotalSpeed": "{{speed}} totaal ({{lanes}} bane)",
"progressTransferring": "Oordrag van data…",
"progressTransferringItems": "Oordrag van lêers ({{current}} van {{total}})…",
"progressVerifying": "Verifieer lêerintegriteit…",
"recentDestinations": "Onlangse bestemmings",
"resumedHint": "Herverbind met 'n aktiewe oordrag wat in 'n ander venster begin is.",
"retryTransfer": "Probeer weer",
"retryTransferError": "Herprobeer het misluk",
"selectDestinationHost": "Kies bestemmingsgasheer",
"transferCancelled": "Oordrag gekanselleer",
"transferCancelledCopyHint": "Gedeeltelike lêers mag dalk op die bestemming bly.",
"transferCancelledMoveHint": "Gedeeltelike lêers mag dalk op die bestemming bly. Bronlêers is nie verwyder nie.",
"transferError": "Oordrag het misluk",
"transferFailedRetryHint": "Gedeeltelike data is op die bestemming gehou. Herprobeer sal hervat word wanneer die verbinding terug is.",
"transferPartialHint": "Kon nie oordra nie: {{paths}}",
"transferSuccess": "Oordrag voltooi"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "المسار الافتراضي",
"fileManagerPathHint": "الدليل الذي سيتم فتحه عند تشغيل مدير الملفات لهذا المضيف.",
"fileManagerUrlCopied": "تم نسخ رابط مدير الملفات",
"copyFileManagerUrlAction": "نسخ رابط مدير الملفات"
"copyFileManagerUrlAction": "نسخ رابط مدير الملفات",
"docsLink": "عرض المستندات",
"hostNotFound": "المضيف غير موجود",
"loadingHost": "جارٍ تحميل المضيف..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "الملفات"
},
"onboarding": {
"feature_files": "مدير الملفات",
"feature_files_desc": "تصفح الملفات وقم بتحميلها وتنزيلها وتعديلها عبر بروتوكول SFTP دون مغادرة التطبيق."
},
"terminal": {
"runTitle": "تشغيل {{command}} - {{host}}",
"terminalTitle": "الطرفية - {{host}}",
"terminalWithPath": "الطرفية - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "تصفح مجلدات الوجهة",
"browsePathError": "تعذر فتح هذا المسار على المضيف الوجهة.",
"browsePathWillBeCreated": "هذا المجلد غير موجود بعد. سيتم إنشاؤه عند بدء النقل.",
"cancel": "إلغاء",
"cleanupDestFiles": "تنظيف الوجهة",
"cleanupDestFilesError": "فشل التنظيف",
"cleanupDestFilesNothing": "لا شيء للتنظيف على الوجهة",
"cleanupDestFilesPartial": "تعذر إزالة بعض الملفات الجزئية",
"cleanupDestFilesSuccess": "تمت إزالة الملفات الجزئية من الوجهة",
"confirmCopy": "نسخ",
"confirmMove": "نقل",
"copyFolderToHost": "نسخ المجلد إلى المضيف…",
"copyItemsToHost": "نسخ {{count}} عناصر إلى المضيف…",
"copyToHost": "نسخ إلى المضيف…",
"destinationPath": "مسار الوجهة",
"destMustBeDirectory": "يجب أن تكون الوجهة مجلدًا لنقل عناصر متعددة",
"goUp": "للأعلى",
"hostAuthRequired": "المصادقة مطلوبة — افتح مدير الملفات على هذا المضيف أولاً",
"hostConnecting": "جارٍ الاتصال…",
"hostConnectionFailed": "فشل الاتصال",
"hostDisconnected": "غير متصل",
"hostReady": "جاهز",
"itemsSummary": "{{count}} عنصر",
"jumpHostLimitation": "يجب أن يكون كلا المضيفين قابلين للوصول من خادم Termix. التوجيه المباشر من مضيف إلى مضيف غير مدعوم.",
"methodAuto": "تلقائي",
"methodAutoHint": "يختار tar أو SFTP لكل ملف بناءً على عدد الملفات وحجمها وقابلية الضغط. الملفات المفردة تستخدم دائمًا SFTP التدفقي.",
"methodItemSftp": "SFTP لكل ملف",
"methodItemSftpHint": "نقل كل ملف على حدة عبر SFTP. يعمل على جميع المضيفين بما في ذلك Windows.",
"methodItemSftpLimitation": "يستخدم كل ملف نفس تدفق SFTP كنسخ الملف الواحد، واحداً تلو الآخر. يُجمع التقدم عبر جميع الملفات، لذا يتحرك الشريط ببطء أثناء الملفات الكبيرة.",
"methodLabel": "طريقة النقل",
"methodPreviewError": "تعذّر معاينة طريقة النقل. سيختار الخادم طريقة عند بدء النقل.",
"methodPreviewLoading": "جارٍ حساب طريقة النقل…",
"methodPreviewScanSummary": "{{fileCount}} ملفات، {{totalSize}} إجمالي (تم المسح على المضيف المصدر).",
"methodPreviewWillUseItemSftp": "سيُستخدم: SFTP لكل ملف",
"methodPreviewWillUseTar": "سيُستخدم: أرشيف Tar",
"methodReason": {
"user_item_sftp": "اخترت SFTP لكل ملف.",
"user_tar": "اخترت أرشيف tar.",
"tar_unavailable": "tar غير متوفر على أحد المضيفين أو كليهما — سيُستخدم SFTP لكل ملف بدلاً من ذلك.",
"windows_host": "يوجد مضيف Windows — لا يُستخدم tar.",
"auto_multi_large": "تلقائي: عدة ملفات بما فيها ملف كبير ({{largestSize}}) ببيانات قابلة للضغط — يجمعها tar في حزمة واحدة.",
"auto_single_large_in_archive": "تلقائي: ملف كبير واحد ({{largestSize}}) في هذه المجموعة — SFTP لكل ملف.",
"auto_many_incompressible": "تلقائي: البيانات غالبًا غير قابلة للضغط — SFTP لكل ملف.",
"auto_many_files": "تلقائي: عدة ملفات ({{fileCount}}) — يقلل tar الحمل لكل ملف.",
"auto_default": "تلقائي: SFTP لكل ملف لهذه المجموعة."
},
"methodTar": "أرشيف Tar",
"methodTarHint": "ضغط على المصدر، نقل أرشيف واحد، فك على الوجهة. يتطلب tar على كلا المضيفين Unix.",
"metricsCompress": "ضغط على المصدر: {{duration}}",
"metricsExtract": "فك على الوجهة: {{duration}}",
"metricsPrepare": "تحضير الوجهة: {{duration}}",
"metricsRouteBenchmark": "مسبار المسار — مباشر: {{direct}}، مرحل: {{relay}}",
"metricsSourceDelete": "إزالة من المصدر: {{duration}}",
"metricsTotal": "الإجمالي: {{duration}}",
"metricsTransfer": "نقل شامل: {{throughput}} ({{duration}})",
"metricsVerify": "تم التحقق من SHA-256: {{duration}}",
"moveFolderToHost": "نقل المجلد إلى المضيف…",
"moveItemsToHost": "نقل {{count}} عناصر إلى المضيف…",
"moveToHost": "نقل إلى المضيف…",
"noHostsConnected": "لا تتوفر مضيفات أخرى لمدير الملفات.",
"noHostsConnectedHint": "أضف مضيف SSH آخر مع تمكين مدير الملفات في مدير المضيفات.",
"parallelSegmentsHint": "تُقسم الملفات الكبيرة إلى أجزاء بحجم 256 ميغابايت. تستخدم المسارات المتعددة اتصالات منفصلة (مثل بدء عدة عمليات نقل) لتحقيق إنتاجية إجمالية أعلى.",
"parallelSegmentsLabel": "مسارات النقل المتوازية",
"parallelSegmentsOption": "{{count}} مسارات",
"progressBenchmarking": "اختيار أسرع مسار نقل…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "إلغاء",
"progressCancelling": "جارٍ الإلغاء…",
"progressCompressing": "جارٍ الضغط على المضيف المصدر…",
"progressExtracting": "جارٍ الفك على الوجهة…",
"progressItems": "{{current}} / {{total}} ملفات",
"progressReconnecting": "جارٍ إعادة الاتصال…",
"progressStalled": "متوقف",
"progressTotalSpeed": "{{speed}} إجمالي ({{lanes}} مسارات)",
"progressTransferring": "جارٍ نقل البيانات…",
"progressTransferringItems": "جارٍ نقل الملفات ({{current}} من {{total}})…",
"progressVerifying": "التحقق من سلامة الملف…",
"recentDestinations": "الوجهات الأخيرة",
"resumedHint": "تمت إعادة الاتصال بنقل نشط بدأ في نافذة أخرى.",
"retryTransfer": "إعادة المحاولة",
"retryTransferError": "فشلت إعادة المحاولة",
"selectDestinationHost": "تحديد المضيف الوجهة",
"transferCancelled": "تم إلغاء النقل",
"transferCancelledCopyHint": "قد تبقى ملفات جزئية على الوجهة.",
"transferCancelledMoveHint": "قد تبقى ملفات جزئية على الوجهة. لم يتم حذف ملفات المصدر.",
"transferError": "فشل النقل",
"transferFailedRetryHint": "تم الاحتفاظ بالبيانات الجزئية على الوجهة. ستُستأنف إعادة المحاولة عند عودة الاتصال.",
"transferPartialHint": "تعذر النقل: {{paths}}",
"transferSuccess": "اكتمل النقل"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Път по подразбиране",
"fileManagerPathHint": "Директорията, която да се отвори при стартиране на файловия мениджър за този хост.",
"fileManagerUrlCopied": "URL адресът на файловия мениджър е копиран",
"copyFileManagerUrlAction": "Копиране на URL адреса на файловия мениджър"
"copyFileManagerUrlAction": "Копиране на URL адреса на файловия мениджър",
"docsLink": "Преглед на документи",
"hostNotFound": "Хостът не е намерен",
"loadingHost": "Зареждане на хоста..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Файлове"
},
"onboarding": {
"feature_files": "Файлов мениджър",
"feature_files_desc": "Преглеждайте, качвайте, изтегляйте и редактирайте файлове през SFTP, без да напускате приложението."
},
"terminal": {
"runTitle": "Изпълнява се {{command}} - {{host}}",
"terminalTitle": "Терминал - {{host}}",
"terminalWithPath": "Терминал - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Преглед на целевите папки",
"browsePathError": "Не можа да се отвори този път на целевия хост.",
"browsePathWillBeCreated": "Тази папка все още не съществува. Тя ще бъде създадена, когато започне прехвърлянето.",
"cancel": "Отказ",
"cleanupDestFiles": "Почистване на дестинацията",
"cleanupDestFilesError": "Почистването не бе успешно",
"cleanupDestFilesNothing": "Няма нищо за почистване на дестинацията",
"cleanupDestFilesPartial": "Някои частични файлове не можаха да бъдат премахнати",
"cleanupDestFilesSuccess": "Премахнати частични файлове от местоназначението",
"confirmCopy": "Копиране",
"confirmMove": "Преместване",
"copyFolderToHost": "Копиране на папката на хост…",
"copyItemsToHost": "Копиране на {{count}} елементи за хостване на…",
"copyToHost": "Копиране към хост…",
"destinationPath": "Път на местоназначението",
"destMustBeDirectory": "Дестинацията трябва да е директория за прехвърляне на множество елементи",
"goUp": "Качи се нагоре",
"hostAuthRequired": "Изисква се удостоверяване — първо отворете Файловия мениджър на този хост",
"hostConnecting": "Свързване…",
"hostConnectionFailed": "Връзката не бе успешна",
"hostDisconnected": "Няма връзка",
"hostReady": "Готов",
"itemsSummary": "{{count}} артикули",
"jumpHostLimitation": "И двата хоста трябва да са достъпни от Termix сървъра. Директното маршрутизиране от хост към хост не се поддържа.",
"methodAuto": "Автоматично",
"methodAutoHint": "Избира tar или SFTP за всеки файл въз основа на броя, размера и компресируемостта на файловете. Отделните файлове винаги използват стрийминг SFTP.",
"methodItemSftp": "SFTP за всеки файл",
"methodItemSftpHint": "Прехвърляйте всеки файл поотделно през SFTP. Работи на всички хостове, включително Windows.",
"methodItemSftpLimitation": "Всеки файл използва същия SFTP поток като копие на един файл, следвани един след друг. Напредъкът се комбинира във всички файлове, така че лентата се движи бавно при големи файлове.",
"methodLabel": "Метод на прехвърляне",
"methodPreviewError": "Не можа да се прегледа методът за прехвърляне. Сървърът все пак ще избере метод, когато стартирате.",
"methodPreviewLoading": "Метод за изчисляване на трансфер…",
"methodPreviewScanSummary": "{{fileCount}} файлове, {{totalSize}} общо (сканирани на изходния хост).",
"methodPreviewWillUseItemSftp": "Ще използва: SFTP за всеки файл",
"methodPreviewWillUseTar": "Ще използвам: Tar архив",
"methodReason": {
"user_item_sftp": "Избрали сте SFTP за всеки файл.",
"user_tar": "Избрахте tar архив.",
"tar_unavailable": "Tar не е наличен на единия или и на двата хоста — вместо това ще се използва SFTP за всеки файл.",
"windows_host": "Включен е хост на Windows — tar не се използва.",
"auto_multi_large": "Автоматично: множество файлове, включително голям файл ({{largestSize}}) със свиваеми данни — tar пакети в един трансфер.",
"auto_single_large_in_archive": "Автоматично: един голям файл ({{largestSize}}) в този набор — SFTP за всеки файл.",
"auto_many_incompressible": "Автоматично: предимно некомпресируеми данни — SFTP за всеки файл.",
"auto_many_files": "Автоматично: много файлове ({{fileCount}}) — tar намалява натоварването на всеки файл.",
"auto_default": "Автоматично: SFTP за всеки файл за този набор."
},
"methodTar": "Тар архив",
"methodTarHint": "Компресиране при източника, прехвърляне на един архив, разархивиране при местоназначението. Изисква tar и на двата Unix хоста.",
"metricsCompress": "Компресиране при източника: {{duration}}",
"metricsExtract": "Извличане в местоназначението: {{duration}}",
"metricsPrepare": "Подготовка на дестинацията: {{duration}}",
"metricsRouteBenchmark": "Сонда за маршрут — директна: {{direct}}, релейна: {{relay}}",
"metricsSourceDelete": "Премахване от източника: {{duration}}",
"metricsTotal": "Общо: {{duration}}",
"metricsTransfer": "От край до край: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 проверен: {{duration}}",
"moveFolderToHost": "Преместване на папката на хост…",
"moveItemsToHost": "Преместете {{count}} елементи, за да хоствате…",
"moveToHost": "Преместване към хост…",
"noHostsConnected": "Няма други налични хостове за файлови мениджъри.",
"noHostsConnectedHint": "Добавете друг SSH хост с активиран файлов мениджър в Host Manager.",
"parallelSegmentsHint": "Големите файлове се разделят на парчета от 256 MB. Няколко канала използват отделни връзки (като стартиране на няколко трансфера) за по-висока обща пропускателна способност.",
"parallelSegmentsLabel": "Паралелни трансферни ленти",
"parallelSegmentsOption": "{{count}} ленти",
"progressBenchmarking": "Избор на най-бързия маршрут за трансфер…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Отказ",
"progressCancelling": "Анулиране…",
"progressCompressing": "Компресиране на изходния хост…",
"progressExtracting": "Извличане в местоназначението…",
"progressItems": "{{current}} / {{total}} файлове",
"progressReconnecting": "Повторно свързване…",
"progressStalled": "Застоял",
"progressTotalSpeed": "{{speed}} общо ({{lanes}} ленти)",
"progressTransferring": "Прехвърляне на данни…",
"progressTransferringItems": "Прехвърляне на файлове ({{current}} от {{total}})…",
"progressVerifying": "Проверка на целостта на файла…",
"recentDestinations": "Последни дестинации",
"resumedHint": "Възстановена е връзка с активно прехвърляне, започнато в друг прозорец.",
"retryTransfer": "Опитай отново",
"retryTransferError": "Повторният опит не бе успешен",
"selectDestinationHost": "Изберете целеви хост",
"transferCancelled": "Прехвърлянето е анулирано",
"transferCancelledCopyHint": "Частични файлове може да останат в местоназначението.",
"transferCancelledMoveHint": "Възможно е част от файловете да са останали в местоназначението. Изходните файлове не са премахнати.",
"transferError": "Прехвърлянето не бе успешно",
"transferFailedRetryHint": "В местоназначението са запазени частични данни. Повторният опит ще се възобнови, когато връзката се възстанови.",
"transferPartialHint": "Не можа да се прехвърли: {{paths}}",
"transferSuccess": "Прехвърлянето е завършено"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "ডিফল্ট পথ",
"fileManagerPathHint": "এই হোস্টের জন্য ফাইল ম্যানেজার চালু হলে যে ডিরেক্টরিটি খুলবে।",
"fileManagerUrlCopied": "ফাইল ম্যানেজার ইউআরএল কপি করা হয়েছে",
"copyFileManagerUrlAction": "ফাইল ম্যানেজার ইউআরএল কপি করুন"
"copyFileManagerUrlAction": "ফাইল ম্যানেজার ইউআরএল কপি করুন",
"docsLink": "নথি দেখুন",
"hostNotFound": "হোস্ট খুঁজে পাওয়া যায়নি",
"loadingHost": "হোস্ট লোড হচ্ছে..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "এসএফটিপি",
"files": "ফাইল"
},
"onboarding": {
"feature_files": "ফাইল ম্যানেজার",
"feature_files_desc": "অ্যাপ থেকে বের না হয়েই SFTP-এর মাধ্যমে ফাইল ব্রাউজ, আপলোড, ডাউনলোড এবং সম্পাদনা করুন।"
},
"terminal": {
"runTitle": "দৌড়ানো {{command}} - {{host}}",
"terminalTitle": "টার্মিনাল - {{host}}",
"terminalWithPath": "টার্মিনাল - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "গন্তব্য ফোল্ডারগুলি ব্রাউজ করুন",
"browsePathError": "গন্তব্য হোস্টে এই পাথটি খোলা সম্ভব হয়নি।",
"browsePathWillBeCreated": "এই ফোল্ডারটি এখনও তৈরি হয়নি। স্থানান্তর শুরু হলে এটি তৈরি হয়ে যাবে।",
"cancel": "বাতিল করুন",
"cleanupDestFiles": "পরিষ্কার করার গন্তব্য",
"cleanupDestFilesError": "পরিষ্কার করা ব্যর্থ হয়েছে",
"cleanupDestFilesNothing": "গন্তব্যে পরিষ্কার করার কিছু নেই।",
"cleanupDestFilesPartial": "কিছু আংশিক ফাইল সরানো যায়নি",
"cleanupDestFilesSuccess": "গন্তব্য থেকে আংশিক ফাইল সরানো হয়েছে",
"confirmCopy": "অনুলিপি",
"confirmMove": "স্থানান্তর",
"copyFolderToHost": "ফোল্ডারটি হোস্টে কপি করুন…",
"copyItemsToHost": "{{count}} টি আইটেম হোস্টে কপি করুন…",
"copyToHost": "হোস্টে কপি করুন…",
"destinationPath": "গন্তব্য পথ",
"destMustBeDirectory": "একাধিক আইটেম স্থানান্তরের জন্য গন্তব্য অবশ্যই একটি ডিরেক্টরি হতে হবে।",
"goUp": "উপরে যান",
"hostAuthRequired": "প্রমাণীকরণ আবশ্যক — প্রথমে এই হোস্টে ফাইল ম্যানেজার খুলুন।",
"hostConnecting": "… সংযোগ করা হচ্ছে",
"hostConnectionFailed": "সংযোগ ব্যর্থ হয়েছে",
"hostDisconnected": "সংযুক্ত নয়",
"hostReady": "প্রস্তুত",
"itemsSummary": "{{count}} আইটেম",
"jumpHostLimitation": "উভয় হোস্টকেই টারমিক্স সার্ভার থেকে পৌঁছানো সম্ভব হতে হবে। সরাসরি হোস্ট-টু-হোস্ট রাউটিং সমর্থিত নয়।",
"methodAuto": "অটো",
"methodAutoHint": "ফাইলের সংখ্যা, আকার এবং সংকোচনযোগ্যতার উপর ভিত্তি করে tar অথবা ফাইল-ভিত্তিক SFTP নির্বাচন করে। একক ফাইলের ক্ষেত্রে সর্বদা স্ট্রিমিং SFTP ব্যবহৃত হয়।",
"methodItemSftp": "প্রতি-ফাইল এসএফটিপি",
"methodItemSftpHint": "SFTP-এর মাধ্যমে প্রতিটি ফাইল আলাদাভাবে স্থানান্তর করুন। উইন্ডোজ সহ সকল হোস্টে কাজ করে।",
"methodItemSftpLimitation": "প্রতিটি ফাইল একই SFTP স্ট্রিম ব্যবহার করে একটির পর একটি একক-ফাইল কপি হিসেবে তৈরি হয়। সমস্ত ফাইলের অগ্রগতি একত্রিত করা হয়, তাই বড় ফাইলের ক্ষেত্রে বারটি ধীরে চলে।",
"methodLabel": "স্থানান্তর পদ্ধতি",
"methodPreviewError": "স্থানান্তর পদ্ধতির প্রিভিউ দেখা সম্ভব হয়নি। আপনি চালু করার সময় সার্ভার নিজেই একটি পদ্ধতি বেছে নেবে।",
"methodPreviewLoading": "স্থানান্তর পদ্ধতি গণনা করা হচ্ছে…",
"methodPreviewScanSummary": "{{fileCount}} টি ফাইল, {{totalSize}} টি মোট (উৎস হোস্টে স্ক্যান করা হয়েছে)।",
"methodPreviewWillUseItemSftp": "ব্যবহার করা হবে: প্রতি-ফাইল এসএফটিপি",
"methodPreviewWillUseTar": "ব্যবহৃত হবে: টার আর্কাইভ",
"methodReason": {
"user_item_sftp": "আপনি ফাইল-ভিত্তিক এসএফটিপি বেছে নিয়েছেন।",
"user_tar": "আপনি tar আর্কাইভটি বেছে নিয়েছেন।",
"tar_unavailable": "এক বা উভয় হোস্টে Tar উপলব্ধ না থাকায়, এর পরিবর্তে ফাইল-ভিত্তিক SFTP ব্যবহার করা হবে।",
"windows_host": "এখানে একটি উইন্ডোজ হোস্ট জড়িত — tar ব্যবহৃত হয় না।",
"auto_multi_large": "স্বয়ংক্রিয়: সংকোচনযোগ্য ডেটা সহ একটি বড় ফাইল ({{largestSize}}) সহ একাধিক ফাইল — tar বান্ডেল করে একটি একক স্থানান্তরে পাঠানো হয়।",
"auto_single_large_in_archive": "স্বয়ংক্রিয়: এই সেটে একটি বড় ফাইল ({{largestSize}}) — ফাইল-ভিত্তিক SFTP।",
"auto_many_incompressible": "স্বয়ংক্রিয়: প্রধানত অসংকোচনযোগ্য ডেটা — ফাইল-ভিত্তিক এসএফটিপি।",
"auto_many_files": "স্বয়ংক্রিয়: একাধিক ফাইল ({{fileCount}}) — tar প্রতি-ফাইল ওভারহেড কমায়।",
"auto_default": "স্বয়ংক্রিয়: এই সেটের জন্য প্রতি-ফাইল এসএফটিপি।"
},
"methodTar": "টার আর্কাইভ",
"methodTarHint": "উৎসস্থলে কম্প্রেস করুন, একটি আর্কাইভ স্থানান্তর করুন, এবং গন্তব্যে এক্সট্র্যাক্ট করুন। উভয় ইউনিক্স হোস্টে tar প্রয়োজন।",
"metricsCompress": "উৎস থেকে সংকুচিত করুন: {{duration}}",
"metricsExtract": "গন্তব্যে নিষ্কাশন: {{duration}}",
"metricsPrepare": "গন্তব্য প্রস্তুত করুন: {{duration}}",
"metricsRouteBenchmark": "রুট প্রোব — সরাসরি: {{direct}}, রিলে: {{relay}}",
"metricsSourceDelete": "উৎস থেকে সরান: {{duration}}",
"metricsTotal": "মোট: {{duration}}",
"metricsTransfer": "প্রান্ত থেকে প্রান্ত: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 দ্বারা যাচাইকৃত: {{duration}}",
"moveFolderToHost": "ফোল্ডারটি হোস্টে সরান…",
"moveItemsToHost": "{{count}} টি আইটেম… টি হোস্টে সরান",
"moveToHost": "হোস্টে যান…",
"noHostsConnected": "অন্য কোনো ফাইল-ম্যানেজার হোস্ট উপলব্ধ নেই।",
"noHostsConnectedHint": "হোস্ট ম্যানেজারে ফাইল ম্যানেজার সক্রিয় করা আছে এমন আরেকটি SSH হোস্ট যোগ করুন।",
"parallelSegmentsHint": "বড় ফাইলগুলোকে ২৫৬ মেগাবাইটের খণ্ডে ভাগ করা হয়। মোট থ্রুপুট বাড়ানোর জন্য একাধিক লেন আলাদা সংযোগ ব্যবহার করে (যেমন কয়েকটি ট্রান্সফার শুরু করা)।",
"parallelSegmentsLabel": "সমান্তরাল স্থানান্তর লেন",
"parallelSegmentsOption": "{{count}} লেন",
"progressBenchmarking": "দ্রুততম স্থানান্তর পথ নির্বাচন করা হচ্ছে…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "বাতিল করুন",
"progressCancelling": "বাতিল করা হচ্ছে…",
"progressCompressing": "উৎস হোস্টে সংকুচিত করা হচ্ছে…",
"progressExtracting": "গন্তব্য… থেকে নিষ্কাশন করা হচ্ছে",
"progressItems": "{{current}} / {{total}} ফাইল",
"progressReconnecting": "পুনরায় সংযোগ স্থাপন…",
"progressStalled": "স্থবির",
"progressTotalSpeed": "{{speed}} মোট ({{lanes}} লেন)",
"progressTransferring": "ডেটা স্থানান্তর করা হচ্ছে…",
"progressTransferringItems": "ফাইল স্থানান্তর করা হচ্ছে ({{current}} {{total}})…",
"progressVerifying": "ফাইলের অখণ্ডতা যাচাই করা হচ্ছে…",
"recentDestinations": "সাম্প্রতিক গন্তব্যস্থল",
"resumedHint": "অন্য একটি উইন্ডোতে শুরু হওয়া একটি সক্রিয় ট্রান্সফারের সাথে পুনরায় সংযুক্ত হওয়া গেছে।",
"retryTransfer": "পুনরায় চেষ্টা করুন",
"retryTransferError": "পুনরায় চেষ্টা ব্যর্থ হয়েছে",
"selectDestinationHost": "গন্তব্য হোস্ট নির্বাচন করুন",
"transferCancelled": "স্থানান্তর বাতিল করা হয়েছে",
"transferCancelledCopyHint": "গন্তব্যে আংশিক ফাইল থেকে যেতে পারে।",
"transferCancelledMoveHint": "গন্তব্যে আংশিক ফাইল থেকে যেতে পারে। মূল ফাইলগুলো সরানো হয়নি।",
"transferError": "স্থানান্তর ব্যর্থ হয়েছে",
"transferFailedRetryHint": "গন্তব্যে আংশিক ডেটা সংরক্ষিত হয়েছে। সংযোগ ফিরে এলে পুনরায় চেষ্টা শুরু হবে।",
"transferPartialHint": "স্থানান্তর করা যায়নি: {{paths}}",
"transferSuccess": "স্থানান্তর সম্পন্ন হয়েছে"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Camí predeterminat",
"fileManagerPathHint": "El directori que s'obrirà quan s'iniciï el gestor de fitxers per a aquest amfitrió.",
"fileManagerUrlCopied": "S'ha copiat l'URL del gestor de fitxers",
"copyFileManagerUrlAction": "Copia l'URL del gestor de fitxers"
"copyFileManagerUrlAction": "Copia l'URL del gestor de fitxers",
"docsLink": "Veure documents",
"hostNotFound": "No s'ha trobat l'amfitrió",
"loadingHost": "S'està carregant l'amfitrió..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Fitxers"
},
"onboarding": {
"feature_files": "Gestor de fitxers",
"feature_files_desc": "Navegueu, pengeu, descarregueu i editeu fitxers a través de SFTP sense sortir de l'aplicació."
},
"terminal": {
"runTitle": "Executant {{command}} - {{host}}",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Navega per les carpetes de destinació",
"browsePathError": "No s'ha pogut obrir aquesta ruta a l'amfitrió de destinació.",
"browsePathWillBeCreated": "Aquesta carpeta encara no existeix. Es crearà quan comenci la transferència.",
"cancel": "Cancel·la",
"cleanupDestFiles": "Neteja la destinació",
"cleanupDestFilesError": "La neteja ha fallat",
"cleanupDestFilesNothing": "Res a netejar a la destinació",
"cleanupDestFilesPartial": "No s'han pogut eliminar alguns fitxers parcials",
"cleanupDestFilesSuccess": "S'han eliminat fitxers parcials de la destinació",
"confirmCopy": "Còpia",
"confirmMove": "Moure",
"copyFolderToHost": "Copia la carpeta a l'amfitrió…",
"copyItemsToHost": "Copia els elements {{count}} a l'amfitrió…",
"copyToHost": "Copia a l'amfitrió…",
"destinationPath": "Camí de destinació",
"destMustBeDirectory": "La destinació ha de ser un directori per a transferències de diversos elements",
"goUp": "Puja",
"hostAuthRequired": "Cal autenticació: obriu primer el Gestor de fitxers en aquest amfitrió.",
"hostConnecting": "Connectant…",
"hostConnectionFailed": "La connexió ha fallat",
"hostDisconnected": "No connectat",
"hostReady": "Llest",
"itemsSummary": "{{count}} elements",
"jumpHostLimitation": "Tots dos hosts han de ser accessibles des del servidor Termix. No s'admet l'encaminament directe d'host a host.",
"methodAuto": "Automàtic",
"methodAutoHint": "Tria SFTP tar o per fitxer en funció del nombre de fitxers, la mida i la compressibilitat. Els fitxers individuals sempre utilitzen SFTP en temps real.",
"methodItemSftp": "SFTP per fitxer",
"methodItemSftpHint": "Transfereix cada fitxer individualment per SFTP. Funciona en tots els hosts, inclòs Windows.",
"methodItemSftpLimitation": "Cada fitxer utilitza el mateix flux SFTP com una còpia d'un sol fitxer, un darrere l'altre. El progrés es combina en tots els fitxers, de manera que la barra es mou lentament durant els fitxers grans.",
"methodLabel": "Mètode de transferència",
"methodPreviewError": "No s'ha pogut previsualitzar el mètode de transferència. El servidor encara triarà un mètode quan l'inicieu.",
"methodPreviewLoading": "Càlcul del mètode de transferència…",
"methodPreviewScanSummary": "{{fileCount}} fitxers, {{totalSize}} total (escanejats a l'amfitrió d'origen).",
"methodPreviewWillUseItemSftp": "Utilitzarà: SFTP per fitxer",
"methodPreviewWillUseTar": "Utilitzarà: Arxiu Tar",
"methodReason": {
"user_item_sftp": "Heu triat SFTP per fitxer.",
"user_tar": "Has triat l'arxiu tar.",
"tar_unavailable": "Tar no està disponible en un o tots dos hosts; s'utilitzarà SFTP per fitxer.",
"windows_host": "Hi ha un host de Windows implicat; no s'utilitza tar.",
"auto_multi_large": "Automàtic: diversos fitxers, inclòs un fitxer gran ({{largestSize}}) amb dades compressibles: paquets de fitxers tar en una sola transferència.",
"auto_single_large_in_archive": "Automàtic: un fitxer gran ({{largestSize}}) en aquest conjunt — SFTP per fitxer.",
"auto_many_incompressible": "Automàtic: dades majoritàriament incompressibles — SFTP per fitxer.",
"auto_many_files": "Automàtic: molts fitxers ({{fileCount}}) — tar redueix la sobrecàrrega per fitxer.",
"auto_default": "Automàtic: SFTP per fitxer per a aquest conjunt."
},
"methodTar": "Arxiu Tar",
"methodTarHint": "Comprimir a l'origen, transferir un arxiu, extreure a la destinació. Requereix tar en ambdós hosts Unix.",
"metricsCompress": "Comprimir a la font: {{duration}}",
"metricsExtract": "Extracte a la destinació: {{duration}}",
"metricsPrepare": "Prepara la destinació: {{duration}}",
"metricsRouteBenchmark": "Sonda de ruta — directa: {{direct}}, relé: {{relay}}",
"metricsSourceDelete": "Elimina de la font: {{duration}}",
"metricsTotal": "Total: {{duration}}",
"metricsTransfer": "Extrem a extrem: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 verificat: {{duration}}",
"moveFolderToHost": "Mou la carpeta a l'amfitrió…",
"moveItemsToHost": "Mou els elements {{count}} a l'amfitrió…",
"moveToHost": "Moure a l'amfitrió…",
"noHostsConnected": "No hi ha altres amfitrions de gestors de fitxers disponibles.",
"noHostsConnectedHint": "Afegiu un altre amfitrió SSH amb el Gestor de fitxers habilitat al Gestor d'amfitrions.",
"parallelSegmentsHint": "Els fitxers grans es divideixen en blocs de 256 MB. Els carrils múltiples utilitzen connexions separades (com ara iniciar diverses transferències) per a un rendiment total més alt.",
"parallelSegmentsLabel": "Carrils de transferència paral·lels",
"parallelSegmentsOption": "carrils {{count}}",
"progressBenchmarking": "Selecció de la ruta de transferència més ràpida…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Cancel·la",
"progressCancelling": "Cancel·lant…",
"progressCompressing": "Compressió a l'amfitrió d'origen…",
"progressExtracting": "Extraient a la destinació…",
"progressItems": "{{current}} / {{total}} fitxers",
"progressReconnecting": "Reconnectant…",
"progressStalled": "Estancat",
"progressTotalSpeed": "{{speed}} total ({{lanes}} carrils)",
"progressTransferring": "Transferència de dades…",
"progressTransferringItems": "Transferència de fitxers ({{current}} de {{total}})…",
"progressVerifying": "Verificació de la integritat del fitxer…",
"recentDestinations": "Destinacions recents",
"resumedHint": "S'ha tornat a connectar a una transferència activa iniciada en una altra finestra.",
"retryTransfer": "Torna-ho a intentar",
"retryTransferError": "No s'ha pogut reintentar.",
"selectDestinationHost": "Selecciona l'amfitrió de destinació",
"transferCancelled": "Transferència cancel·lada",
"transferCancelledCopyHint": "És possible que hi hagi fitxers parcials a la destinació.",
"transferCancelledMoveHint": "És possible que hi hagi fitxers parcials a la destinació. No s'han eliminat els fitxers d'origen.",
"transferError": "La transferència ha fallat",
"transferFailedRetryHint": "S'han conservat dades parcials a la destinació. El reintent es reprendrà quan es restableixi la connexió.",
"transferPartialHint": "No s'ha pogut transferir: {{paths}}",
"transferSuccess": "Transferència completada"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Výchozí cesta",
"fileManagerPathHint": "Adresář, který se má otevřít při spuštění správce souborů pro tento hostitel.",
"fileManagerUrlCopied": "URL adresa Správce souborů zkopírována",
"copyFileManagerUrlAction": "Kopírovat URL Správce souborů"
"copyFileManagerUrlAction": "Kopírovat URL Správce souborů",
"docsLink": "Zobrazit dokumenty",
"hostNotFound": "Hostitel nenalezen",
"loadingHost": "Načítání hostitele..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Soubory"
},
"onboarding": {
"feature_files": "Správce souborů",
"feature_files_desc": "Procházejte, nahrávejte, stahujte a upravujte soubory přes SFTP, aniž byste museli opustit aplikaci."
},
"terminal": {
"runTitle": "Spuštěno {{command}} - {{host}}",
"terminalTitle": "Terminál - {{host}}",
"terminalWithPath": "Terminál - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Procházet cílové složky",
"browsePathError": "Tuto cestu se nepodařilo otevřít na cílovém hostiteli.",
"browsePathWillBeCreated": "Tato složka zatím neexistuje. Bude vytvořena po zahájení přenosu.",
"cancel": "Zrušit",
"cleanupDestFiles": "Vyčistit cíl",
"cleanupDestFilesError": "Vyčištění se nezdařilo",
"cleanupDestFilesNothing": "Na cílové destinaci není co uklízet",
"cleanupDestFilesPartial": "Některé částečné soubory se nepodařilo odstranit.",
"cleanupDestFilesSuccess": "Z cílového umístění byly odstraněny částečné soubory.",
"confirmCopy": "Kopie",
"confirmMove": "Pohyb",
"copyFolderToHost": "Zkopírovat složku na hostitele…",
"copyItemsToHost": "Zkopírovat {{count}} položek pro hostování…",
"copyToHost": "Kopírovat na hostitele…",
"destinationPath": "Cílová cesta",
"destMustBeDirectory": "Cíl musí být adresář pro přenosy více položek.",
"goUp": "Jdi nahoru",
"hostAuthRequired": "Vyžadováno ověření – nejprve otevřete Správce souborů na tomto hostiteli.",
"hostConnecting": "Připojování…",
"hostConnectionFailed": "Připojení se nezdařilo",
"hostDisconnected": "Nepřipojeno",
"hostReady": "Připraveno",
"itemsSummary": "{{count}} položek",
"jumpHostLimitation": "Oba hostitelé musí být dosažitelné ze serveru Termix. Přímé směrování mezi hostiteli není podporováno.",
"methodAuto": "Auto",
"methodAutoHint": "Vybírá tar nebo SFTP pro jednotlivé soubory na základě počtu souborů, velikosti a komprimovatelnosti. Jednotlivé soubory vždy používají streamovaný SFTP.",
"methodItemSftp": "SFTP pro jednotlivé soubory",
"methodItemSftpHint": "Přeneste každý soubor jednotlivě přes SFTP. Funguje na všech hostitelích včetně Windows.",
"methodItemSftpLimitation": "Každý soubor používá stejný SFTP stream jako kopie jednoho souboru, jeden po druhém. Průběh je sloučen napříč všemi soubory, takže se ukazatel u velkých souborů pohybuje pomalu.",
"methodLabel": "Způsob přenosu",
"methodPreviewError": "Nepodařilo se zobrazit náhled metody přenosu. Server si metodu vybere i po spuštění.",
"methodPreviewLoading": "Výpočet metody převodu…",
"methodPreviewScanSummary": "{{fileCount}} souborů, {{totalSize}} celkem (naskenováno na zdrojovém hostiteli).",
"methodPreviewWillUseItemSftp": "Použije se: SFTP pro jednotlivé soubory",
"methodPreviewWillUseTar": "Použiji: archiv Tar",
"methodReason": {
"user_item_sftp": "Zvolili jste SFTP pro jednotlivé soubory.",
"user_tar": "Zvolili jste archiv tar.",
"tar_unavailable": "Tar není k dispozici na jednom nebo obou hostitelích — místo toho bude použit protokol SFTP pro jednotlivé soubory.",
"windows_host": "Je zapojen hostitelský systém Windows – tar se nepoužívá.",
"auto_multi_large": "Automaticky: více souborů včetně velkého souboru ({{largestSize}}) s komprimovatelnými daty — tar se sbalí do jednoho přenosu.",
"auto_single_large_in_archive": "Automaticky: jeden velký soubor ({{largestSize}}) v této sadě – SFTP pro každý soubor.",
"auto_many_incompressible": "Auto: většinou nekomprimovatelná data – SFTP pro jednotlivé soubory.",
"auto_many_files": "Automaticky: mnoho souborů ({{fileCount}}) – tar snižuje režii pro každý soubor.",
"auto_default": "Automaticky: SFTP pro jednotlivé soubory pro tuto sadu."
},
"methodTar": "Archiv Tar",
"methodTarHint": "Komprimace ve zdroji, přenos jednoho archivu, extrakce v cíli. Vyžaduje tar na obou unixových hostitelích.",
"metricsCompress": "Komprimovat u zdroje: {{duration}}",
"metricsExtract": "Extrahovat v cíli: {{duration}}",
"metricsPrepare": "Připravit cíl: {{duration}}",
"metricsRouteBenchmark": "Sonda trasy — přímá: {{direct}}, relé: {{relay}}",
"metricsSourceDelete": "Odebrat ze zdroje: {{duration}}",
"metricsTotal": "Celkem: {{duration}}",
"metricsTransfer": "Konec od konce: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 ověřeno: {{duration}}",
"moveFolderToHost": "Přesunout složku na hostitele…",
"moveItemsToHost": "Přesunout {{count}} položek na hostitele…",
"moveToHost": "Přesunout na hostitele…",
"noHostsConnected": "Žádní další hostitelé souborů nejsou k dispozici.",
"noHostsConnectedHint": "Přidejte dalšího hostitele SSH s povoleným Správcem souborů ve Správci hostitelů.",
"parallelSegmentsHint": "Velké soubory jsou rozděleny na bloky o velikosti 256 MB. Více linek používá samostatná připojení (například spuštění několika přenosů) pro vyšší celkovou propustnost.",
"parallelSegmentsLabel": "Paralelní přestupní pruhy",
"parallelSegmentsOption": "{{count}} jízdních pruhů",
"progressBenchmarking": "Výběr nejrychlejší trasy přestupu…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Zrušit",
"progressCancelling": "Zrušení…",
"progressCompressing": "Komprese na zdrojovém hostiteli…",
"progressExtracting": "Extrahování v cíli…",
"progressItems": "{{current}} / {{total}} souborů",
"progressReconnecting": "Opětovné připojení…",
"progressStalled": "Zastaveno",
"progressTotalSpeed": "{{speed}} celkem ({{lanes}} pruhů)",
"progressTransferring": "Přenos dat…",
"progressTransferringItems": "Přenos souborů ({{current}} z {{total}})…",
"progressVerifying": "Ověřování integrity souboru…",
"recentDestinations": "Nedávné destinace",
"resumedHint": "Znovu připojeno k aktivnímu přenosu zahájenému v jiném okně.",
"retryTransfer": "Zkusit znovu",
"retryTransferError": "Opakovaný pokus se nezdařil",
"selectDestinationHost": "Vyberte cílového hostitele",
"transferCancelled": "Převod zrušen",
"transferCancelledCopyHint": "V cílovém úložišti mohou zůstat jen částečné soubory.",
"transferCancelledMoveHint": "V cílovém umístění mohou zůstat jen některé soubory. Zdrojové soubory nebyly odstraněny.",
"transferError": "Přenos se nezdařil",
"transferFailedRetryHint": "V cíli byla uložena částečná data. Po obnovení připojení bude pokus pokračovat.",
"transferPartialHint": "Nepodařilo se přenést: {{paths}}",
"transferSuccess": "Převod dokončen"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Standardsti",
"fileManagerPathHint": "Den mappe, der skal åbnes, når filhåndteringen starter for denne vært.",
"fileManagerUrlCopied": "URL'en til filhåndtering er kopieret",
"copyFileManagerUrlAction": "Kopiér URL til filhåndtering"
"copyFileManagerUrlAction": "Kopiér URL til filhåndtering",
"docsLink": "Se dokumenter",
"hostNotFound": "Værten blev ikke fundet",
"loadingHost": "Indlæser vært..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Filer"
},
"onboarding": {
"feature_files": "Filhåndtering",
"feature_files_desc": "Gennemse, upload, download og rediger filer via SFTP uden at forlade appen."
},
"terminal": {
"runTitle": "Kører {{command}} - {{host}}",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Gennemse destinationsmapper",
"browsePathError": "Kunne ikke åbne denne sti på destinationsværten.",
"browsePathWillBeCreated": "Denne mappe findes ikke endnu. Den vil blive oprettet, når overførslen starter.",
"cancel": "Ophæve",
"cleanupDestFiles": "Oprydningsdestination",
"cleanupDestFilesError": "Oprydning mislykkedes",
"cleanupDestFilesNothing": "Intet at rydde op på destinationen",
"cleanupDestFilesPartial": "Nogle delvise filer kunne ikke fjernes",
"cleanupDestFilesSuccess": "Fjernede delvise filer fra destinationen",
"confirmCopy": "Kopi",
"confirmMove": "Flytte",
"copyFolderToHost": "Kopiér mappe til vært…",
"copyItemsToHost": "Kopiér {{count}} elementer til at være vært for…",
"copyToHost": "Kopiér til vært…",
"destinationPath": "Destinationssti",
"destMustBeDirectory": "Destinationen skal være en mappe for overførsler af flere elementer",
"goUp": "Gå op",
"hostAuthRequired": "Godkendelse kræves — åbn først Filhåndtering på denne vært",
"hostConnecting": "Forbinder…",
"hostConnectionFailed": "Forbindelsen mislykkedes",
"hostDisconnected": "Ikke forbundet",
"hostReady": "Parat",
"itemsSummary": "{{count}} elementer",
"jumpHostLimitation": "Begge værter skal kunne nås fra Termix-serveren. Direkte vært-til-vært-routing understøttes ikke.",
"methodAuto": "Bil",
"methodAutoHint": "Vælger tar eller SFTP pr. fil baseret på antal filer, størrelse og komprimerbarhed. Enkeltfiler bruger altid streaming SFTP.",
"methodItemSftp": "SFTP pr. fil",
"methodItemSftpHint": "Overfør hver fil individuelt via SFTP. Fungerer på alle værter, inklusive Windows.",
"methodItemSftpLimitation": "Hver fil bruger den samme SFTP-strøm som en enkelt filkopi, én efter én. Status kombineres på tværs af alle filer, så bjælken bevæger sig langsomt under store filer.",
"methodLabel": "Overførselsmetode",
"methodPreviewError": "Kunne ikke forhåndsvise overførselsmetoden. Serveren vil stadig vælge en metode, når du starter.",
"methodPreviewLoading": "Beregning af overførselsmetode…",
"methodPreviewScanSummary": "{{fileCount}} filer, {{totalSize}} i alt (scannet på kildevært).",
"methodPreviewWillUseItemSftp": "Vil bruge: SFTP pr. fil",
"methodPreviewWillUseTar": "Vil bruge: Tar-arkiv",
"methodReason": {
"user_item_sftp": "Du valgte SFTP pr. fil.",
"user_tar": "Du valgte tar-arkivet.",
"tar_unavailable": "Tar er ikke tilgængelig på en eller begge værter — SFTP pr. fil vil blive brugt i stedet.",
"windows_host": "En Windows-vært er involveret — tar bruges ikke.",
"auto_multi_large": "Auto: flere filer inklusive en stor fil ({{largestSize}}) med komprimerbare data — tar samler filer i én overførsel.",
"auto_single_large_in_archive": "Auto: én stor fil ({{largestSize}}) i dette sæt — SFTP pr. fil.",
"auto_many_incompressible": "Auto: for det meste inkomprimerbare data — SFTP pr. fil.",
"auto_many_files": "Auto: mange filer ({{fileCount}}) — tar reducerer overhead pr. fil.",
"auto_default": "Auto: SFTP pr. fil for dette sæt."
},
"methodTar": "Tar-arkiv",
"methodTarHint": "Komprimer ved kildekode, overfør ét arkiv, udpak ved destination. Kræver tar på begge Unix-værter.",
"metricsCompress": "Komprimer på kilde: {{duration}}",
"metricsExtract": "Udtræk på destination: {{duration}}",
"metricsPrepare": "Forbered destination: {{duration}}",
"metricsRouteBenchmark": "Rutesonde — direkte: {{direct}}, relæ: {{relay}}",
"metricsSourceDelete": "Fjern fra kilde: {{duration}}",
"metricsTotal": "I alt: {{duration}}",
"metricsTransfer": "End-to-end: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 verificeret: {{duration}}",
"moveFolderToHost": "Flyt mappe til vært…",
"moveItemsToHost": "Flyt {{count}} elementer til at være vært for…",
"moveToHost": "Flyt til vært…",
"noHostsConnected": "Ingen andre filhåndteringsværter tilgængelige.",
"noHostsConnectedHint": "Tilføj en anden SSH-vært med Filhåndtering aktiveret i Værtshåndtering.",
"parallelSegmentsHint": "Store filer opdeles i bidder på 256 MB. Flere baner bruger separate forbindelser (f.eks. at starte flere overførsler) for at opnå en højere samlet gennemløbshastighed.",
"parallelSegmentsLabel": "Parallelle overførselsbaner",
"parallelSegmentsOption": "{{count}} baner",
"progressBenchmarking": "Valg af den hurtigste overførselsrute…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Ophæve",
"progressCancelling": "Annullerer…",
"progressCompressing": "Komprimering på kildevært…",
"progressExtracting": "Udpakning på destination…",
"progressItems": "{{current}} / {{total}} filer",
"progressReconnecting": "Genopretter forbindelse…",
"progressStalled": "Standset",
"progressTotalSpeed": "{{speed}} i alt ({{lanes}} baner)",
"progressTransferring": "Overførsel af data…",
"progressTransferringItems": "Overførsel af filer ({{current}} af {{total}})…",
"progressVerifying": "Bekræfter filintegritet…",
"recentDestinations": "Seneste destinationer",
"resumedHint": "Genoprettet forbindelse til en aktiv overførsel, der er startet i et andet vindue.",
"retryTransfer": "Prøv igen",
"retryTransferError": "Genforsøg mislykkedes",
"selectDestinationHost": "Vælg destinationsvært",
"transferCancelled": "Overførsel annulleret",
"transferCancelledCopyHint": "Delvise filer kan forblive på destinationen.",
"transferCancelledMoveHint": "Delvise filer kan forblive på destinationen. Kildefilerne blev ikke fjernet.",
"transferError": "Overførslen mislykkedes",
"transferFailedRetryHint": "Delvise data blev gemt på destinationen. Forsøget genoptages, når forbindelsen er tilbage.",
"transferPartialHint": "Kunne ikke overføre: {{paths}}",
"transferSuccess": "Overførsel fuldført"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Standardpfad",
"fileManagerPathHint": "Das Verzeichnis, das geöffnet wird, wenn der Dateimanager für diesen Host gestartet wird.",
"fileManagerUrlCopied": "Dateimanager-URL kopiert",
"copyFileManagerUrlAction": "Dateimanager-URL kopieren"
"copyFileManagerUrlAction": "Dateimanager-URL kopieren",
"docsLink": "Dokumentation anzeigen",
"hostNotFound": "Host nicht gefunden",
"loadingHost": "Host wird geladen..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Dateien"
},
"onboarding": {
"feature_files": "Dateimanager",
"feature_files_desc": "Durchsuchen, hochladen, herunterladen und bearbeiten Sie Dateien über SFTP, ohne die App zu verlassen."
},
"terminal": {
"runTitle": "Ausführung: {{command}} - {{host}}",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Zielordner durchsuchen",
"browsePathError": "Dieser Pfad konnte auf dem Zielhost nicht geöffnet werden.",
"browsePathWillBeCreated": "Dieser Ordner existiert noch nicht. Er wird beim Start der Übertragung erstellt.",
"cancel": "Abbrechen",
"cleanupDestFiles": "Ziel bereinigen",
"cleanupDestFilesError": "Bereinigung fehlgeschlagen.",
"cleanupDestFilesNothing": "Nichts zum Bereinigen am Ziel.",
"cleanupDestFilesPartial": "Einige unvollständige Dateien konnten nicht entfernt werden.",
"cleanupDestFilesSuccess": "Unvollständige Dateien vom Ziel entfernt.",
"confirmCopy": "Kopieren",
"confirmMove": "Verschieben",
"copyFolderToHost": "Ordner zum Host kopieren …",
"copyItemsToHost": "{{count}} Elemente auf Host kopieren…",
"copyToHost": "Auf Host kopieren…",
"destinationPath": "Zielpfad",
"destMustBeDirectory": "Bei Übertragung mehrerer Elemente muss das Ziel ein Verzeichnis sein.",
"goUp": "Nach oben",
"hostAuthRequired": "Authentifizierung erforderlich — öffnen Sie zuerst den Dateimanager auf diesem Host",
"hostConnecting": "Verbinden …",
"hostConnectionFailed": "Verbindung fehlgeschlagen",
"hostDisconnected": "Nicht verbunden",
"hostReady": "Bereit",
"itemsSummary": "{{count}} Elemente",
"jumpHostLimitation": "Beide Hosts müssen vom Termix-Server aus erreichbar sein. Direktes Host-zu-Host-Routing wird nicht unterstützt.",
"methodAuto": "Automatisch",
"methodAutoHint": "Wählt Tar-Archiv oder dateiweise SFTP basierend auf Dateianzahl, Größe und Komprimierbarkeit. Einzelne Dateien verwenden immer Streaming-SFTP.",
"methodItemSftp": "Dateiweise SFTP",
"methodItemSftpHint": "Jede Datei einzeln per SFTP übertragen. Funktioniert auf allen Hosts einschließlich Windows.",
"methodItemSftpLimitation": "Jede Datei verwendet denselben SFTP-Stream wie bei einer Einzeldatei-Kopie, eine nach der anderen. Der Fortschritt wird über alle Dateien kombiniert, sodass der Balken bei großen Dateien nur langsam voranschreitet.",
"methodLabel": "Übertragungsmethode",
"methodPreviewError": "Vorschau der Übertragungsmethode nicht möglich. Der Server wählt beim Start trotzdem eine Methode.",
"methodPreviewLoading": "Übertragungsmethode wird berechnet…",
"methodPreviewScanSummary": "{{fileCount}} Dateien, {{totalSize}} gesamt (auf Quellhost gescannt).",
"methodPreviewWillUseItemSftp": "Verwendet: Dateiweise SFTP",
"methodPreviewWillUseTar": "Verwendet: Tar-Archiv",
"methodReason": {
"user_item_sftp": "Sie haben dateiweises SFTP ausgewählt.",
"user_tar": "Sie haben tar-Archiv ausgewählt.",
"tar_unavailable": "Tar ist auf einem oder beiden Hosts nicht verfügbar – stattdessen wird dateiweises SFTP verwendet.",
"windows_host": "Ein Windows-Host ist beteiligt – tar wird nicht verwendet.",
"auto_multi_large": "Automatisch: mehrere Dateien, darunter eine große Datei ({{largestSize}}) mit komprimierbaren Daten – tar bündelt sie in eine Übertragung.",
"auto_single_large_in_archive": "Automatisch: eine große Datei ({{largestSize}}) in diesem Satz – dateiweises SFTP.",
"auto_many_incompressible": "Automatisch: überwiegend nicht komprimierbare Daten – dateiweises SFTP.",
"auto_many_files": "Automatisch: viele Dateien ({{fileCount}}) – tar reduziert den Overhead pro Datei.",
"auto_default": "Automatisch: dateiweises SFTP für diesen Satz."
},
"methodTar": "Tar-Archiv",
"methodTarHint": "Komprimieren auf der Quelle, ein Archiv übertragen, auf dem Ziel entpacken. Erfordert tar auf beiden Unix-Hosts.",
"metricsCompress": "Komprimieren auf der Quelle: {{duration}}",
"metricsExtract": "Entpacken auf dem Ziel: {{duration}}",
"metricsPrepare": "Ziel vorbereiten: {{duration}}",
"metricsRouteBenchmark": "Routenprüfung — direkt: {{direct}}, Relay: {{relay}}",
"metricsSourceDelete": "Löschen von der Quelle: {{duration}}",
"metricsTotal": "Gesamt: {{duration}}",
"metricsTransfer": "Ende-zu-Ende: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 verifiziert: {{duration}}",
"moveFolderToHost": "Ordner zum Host verschieben …",
"moveItemsToHost": "{{count}} Elemente zum Host verschieben…",
"moveToHost": "Auf Host verschieben…",
"noHostsConnected": "Keine weiteren Dateimanager-Hosts verfügbar.",
"noHostsConnectedHint": "Fügen Sie einen weiteren SSH-Host mit aktiviertem Dateimanager im Host-Manager hinzu.",
"parallelSegmentsHint": "Große Dateien werden in 256-MB-Blöcke aufgeteilt. Mehrere Kanäle verwenden eigene Verbindungen (ähnlich wie mehrere gleichzeitige Übertragungen) für einen höheren Gesamtdurchsatz.",
"parallelSegmentsLabel": "Parallele Übertragungskanäle",
"parallelSegmentsOption": "{{count}} Kanäle",
"progressBenchmarking": "Auswahl der schnellsten Transferroute…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Abbrechen",
"progressCancelling": "Wird abgebrochen…",
"progressCompressing": "Komprimieren auf dem Quellhost…",
"progressExtracting": "Entpacken auf dem Zielhost…",
"progressItems": "{{current}} / {{total}} Dateien",
"progressReconnecting": "Neu verbinden…",
"progressStalled": "Stockt",
"progressTotalSpeed": "{{speed}} gesamt ({{lanes}} Kanäle)",
"progressTransferring": "Daten übertragen…",
"progressTransferringItems": "Übertragen von Dateien ({{current}} von {{total}})…",
"progressVerifying": "Dateiintegrität wird überprüft…",
"recentDestinations": "Letzte Ziele",
"resumedHint": "Erneut mit einer aktiven Übertragung verbunden, die in einem anderen Fenster gestartet wurde.",
"retryTransfer": "Wiederholen",
"retryTransferError": "Wiederholung fehlgeschlagen.",
"selectDestinationHost": "Zielhost auswählen",
"transferCancelled": "Übertragung abgebrochen",
"transferCancelledCopyHint": "Unvollständige Dateien können am Zielort verbleiben.",
"transferCancelledMoveHint": "Unvollständige Dateien können am Zielort verbleiben. Quelldateien wurden nicht entfernt.",
"transferError": "Übertragung fehlgeschlagen",
"transferFailedRetryHint": "Unvollständige Daten wurden am Ziel beibehalten. Die Wiederholung wird fortgesetzt, sobald die Verbindung wiederhergestellt ist.",
"transferPartialHint": "Konnte nicht übertragen werden: {{paths}}",
"transferSuccess": "Übertragung abgeschlossen"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Προεπιλεγμένη διαδρομή",
"fileManagerPathHint": "Ο κατάλογος που θα ανοίξει κατά την εκκίνηση του διαχειριστή αρχείων για αυτόν τον κεντρικό υπολογιστή.",
"fileManagerUrlCopied": "Η διεύθυνση URL του διαχειριστή αρχείων αντιγράφηκε",
"copyFileManagerUrlAction": "Αντιγραφή URL Διαχείρισης Αρχείων"
"copyFileManagerUrlAction": "Αντιγραφή URL Διαχείρισης Αρχείων",
"docsLink": "Προβολή εγγράφων",
"hostNotFound": "Δεν βρέθηκε κεντρικός υπολογιστής",
"loadingHost": "Φόρτωση κεντρικού υπολογιστή..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Αρχεία"
},
"onboarding": {
"feature_files": "Διαχειριστής αρχείων",
"feature_files_desc": "Περιηγηθείτε, ανεβάστε, κατεβάστε και επεξεργαστείτε αρχεία μέσω SFTP χωρίς να φύγετε από την εφαρμογή."
},
"terminal": {
"runTitle": "Εκτέλεση {{command}} - {{host}}",
"terminalTitle": "Τερματικό - {{host}}",
"terminalWithPath": "Τερματικό - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Αναζήτηση φακέλων προορισμού",
"browsePathError": "Δεν ήταν δυνατό το άνοιγμα αυτής της διαδρομής στον κεντρικό υπολογιστή προορισμού.",
"browsePathWillBeCreated": "Αυτός ο φάκελος δεν υπάρχει ακόμη. Θα δημιουργηθεί όταν ξεκινήσει η μεταφορά.",
"cancel": "Ματαίωση",
"cleanupDestFiles": "Καθαρισμός προορισμού",
"cleanupDestFilesError": "Ο καθαρισμός απέτυχε",
"cleanupDestFilesNothing": "Δεν υπάρχει τίποτα προς διόρθωση στον προορισμό",
"cleanupDestFilesPartial": "Δεν ήταν δυνατή η κατάργηση ορισμένων τμηματικών αρχείων",
"cleanupDestFilesSuccess": "Αφαιρέθηκαν μερικά αρχεία από τον προορισμό",
"confirmCopy": "Αντίγραφο",
"confirmMove": "Κίνηση",
"copyFolderToHost": "Αντιγραφή φακέλου στον κεντρικό υπολογιστή…",
"copyItemsToHost": "Αντιγραφή στοιχείων {{count}} για φιλοξενία…",
"copyToHost": "Αντιγραφή στον κεντρικό υπολογιστή…",
"destinationPath": "Διαδρομή προορισμού",
"destMustBeDirectory": "Ο προορισμός πρέπει να είναι ένας κατάλογος για μεταφορές πολλαπλών στοιχείων",
"goUp": "Ανεβαίνω",
"hostAuthRequired": "Απαιτείται έλεγχος ταυτότητας — ανοίξτε πρώτα τη Διαχείριση αρχείων σε αυτόν τον κεντρικό υπολογιστή",
"hostConnecting": "Σύνδεση…",
"hostConnectionFailed": "Η σύνδεση απέτυχε",
"hostDisconnected": "Δεν είναι συνδεδεμένο",
"hostReady": "Ετοιμος",
"itemsSummary": "{{count}} στοιχεία",
"jumpHostLimitation": "Και οι δύο κεντρικοί υπολογιστές πρέπει να είναι προσβάσιμοι από τον διακομιστή Termix. Δεν υποστηρίζεται η άμεση δρομολόγηση από κεντρικό υπολογιστή σε κεντρικό υπολογιστή.",
"methodAuto": "Αυτο",
"methodAutoHint": "Επιλέγει SFTP tar ή ανά αρχείο με βάση τον αριθμό αρχείων, το μέγεθος και τη συμπιεστότητα. Τα μεμονωμένα αρχεία χρησιμοποιούν πάντα SFTP ροής.",
"methodItemSftp": "SFTP ανά αρχείο",
"methodItemSftpHint": "Μεταφέρετε κάθε αρχείο ξεχωριστά μέσω SFTP. Λειτουργεί σε όλους τους κεντρικούς υπολογιστές, συμπεριλαμβανομένων των Windows.",
"methodItemSftpLimitation": "Κάθε αρχείο χρησιμοποιεί την ίδια ροή SFTP ως αντίγραφο ενός μόνο αρχείου, το ένα μετά το άλλο. Η πρόοδος συνδυάζεται σε όλα τα αρχεία, επομένως η γραμμή κινείται αργά κατά τη διάρκεια μεγάλων αρχείων.",
"methodLabel": "Μέθοδος μεταφοράς",
"methodPreviewError": "Δεν ήταν δυνατή η προεπισκόπηση της μεθόδου μεταφοράς. Ο διακομιστής θα επιλέξει μια μέθοδο κατά την εκκίνηση.",
"methodPreviewLoading": "Υπολογισμός μεθόδου μεταφοράς…",
"methodPreviewScanSummary": "{{fileCount}} αρχεία, {{totalSize}} συνολικά (σαρωμένα στον κεντρικό υπολογιστή προέλευσης).",
"methodPreviewWillUseItemSftp": "Θα χρησιμοποιηθεί: SFTP ανά αρχείο",
"methodPreviewWillUseTar": "Θα χρησιμοποιηθεί: Αρχείο Tar",
"methodReason": {
"user_item_sftp": "Επιλέξατε SFTP ανά αρχείο.",
"user_tar": "Επιλέξατε το αρχείο tar.",
"tar_unavailable": "Το Tar δεν είναι διαθέσιμο σε έναν ή και στους δύο κεντρικούς υπολογιστές — θα χρησιμοποιηθεί αντ' αυτού το SFTP ανά αρχείο.",
"windows_host": "Εμπλέκεται ένας κεντρικός υπολογιστής των Windows — δεν χρησιμοποιείται το tar.",
"auto_multi_large": "Αυτόματα: πολλά αρχεία, συμπεριλαμβανομένου ενός μεγάλου αρχείου ({{largestSize}}) με συμπιέσιμα δεδομένα — tar ομαδοποιεί σε μία μεταφορά.",
"auto_single_large_in_archive": "Αυτόματα: ένα μεγάλο αρχείο ({{largestSize}}) σε αυτό το σύνολο — ανά αρχείο SFTP.",
"auto_many_incompressible": "Αυτόματα: ως επί το πλείστον ασυμπίεστα δεδομένα — SFTP ανά αρχείο.",
"auto_many_files": "Αυτόματα: πολλά αρχεία ({{fileCount}}) — το tar μειώνει την επιβάρυνση ανά αρχείο.",
"auto_default": "Αυτόματα: SFTP ανά αρχείο για αυτό το σύνολο."
},
"methodTar": "Αρχείο Tar",
"methodTarHint": "Συμπίεση στην πηγή, μεταφορά ενός αρχείου, εξαγωγή στον προορισμό. Απαιτείται tar και στους δύο κεντρικούς υπολογιστές Unix.",
"metricsCompress": "Συμπίεση στην πηγή: {{duration}}",
"metricsExtract": "Εξαγωγή στον προορισμό: {{duration}}",
"metricsPrepare": "Προετοιμασία προορισμού: {{duration}}",
"metricsRouteBenchmark": "Δρομολόγηση ανιχνευτή — άμεση: {{direct}}, αναμετάδοση: {{relay}}",
"metricsSourceDelete": "Αφαίρεση από την πηγή: {{duration}}",
"metricsTotal": "Σύνολο: {{duration}}",
"metricsTransfer": "Από άκρο σε άκρο: {{throughput}} ({{duration}})",
"metricsVerify": "Επαληθεύτηκε το SHA-256: {{duration}}",
"moveFolderToHost": "Μετακίνηση φακέλου στον κεντρικό υπολογιστή…",
"moveItemsToHost": "Μετακίνηση στοιχείων {{count}} για να φιλοξενήσει το…",
"moveToHost": "Μετακίνηση στον κεντρικό υπολογιστή…",
"noHostsConnected": "Δεν υπάρχουν άλλοι διαθέσιμοι κεντρικοί υπολογιστές διαχείρισης αρχείων.",
"noHostsConnectedHint": "Προσθέστε έναν άλλο κεντρικό υπολογιστή SSH με ενεργοποιημένο το File Manager στο Host Manager.",
"parallelSegmentsHint": "Τα μεγάλα αρχεία χωρίζονται σε κομμάτια των 256 MB. Πολλαπλές λωρίδες χρησιμοποιούν ξεχωριστές συνδέσεις (όπως η έναρξη αρκετών μεταφορών) για υψηλότερη συνολική απόδοση.",
"parallelSegmentsLabel": "Παράλληλες λωρίδες μετεπιβίβασης",
"parallelSegmentsOption": "{{count}} λωρίδες",
"progressBenchmarking": "Επιλογή της ταχύτερης διαδρομής μεταφοράς…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Ματαίωση",
"progressCancelling": "Ακύρωση…",
"progressCompressing": "Συμπίεση στον κεντρικό υπολογιστή προέλευσης…",
"progressExtracting": "Εξαγωγή στον προορισμό…",
"progressItems": "{{current}} / {{total}} αρχεία",
"progressReconnecting": "Επανασύνδεση…",
"progressStalled": "Σταματημένο",
"progressTotalSpeed": "{{speed}} σύνολο ({{lanes}} λωρίδες)",
"progressTransferring": "Μεταφορά δεδομένων…",
"progressTransferringItems": "Μεταφορά αρχείων ({{current}} από {{total}})…",
"progressVerifying": "Επαλήθευση ακεραιότητας αρχείου…",
"recentDestinations": "Πρόσφατοι προορισμοί",
"resumedHint": "Επανασύνδεση με μια ενεργή μεταφορά που ξεκίνησε σε άλλο παράθυρο.",
"retryTransfer": "Δοκιμάζω πάλι",
"retryTransferError": "Η επανάληψη απέτυχε",
"selectDestinationHost": "Επιλέξτε κεντρικό υπολογιστή προορισμού",
"transferCancelled": "Η μεταφορά ακυρώθηκε.",
"transferCancelledCopyHint": "Ενδέχεται να παραμείνουν μερικά αρχεία στον προορισμό.",
"transferCancelledMoveHint": "Ενδέχεται να παραμείνουν μερικά αρχεία στον προορισμό. Τα αρχεία προέλευσης δεν καταργήθηκαν.",
"transferError": "Η μεταφορά απέτυχε",
"transferFailedRetryHint": "Μερικά δεδομένα διατηρήθηκαν στον προορισμό. Η επανάληψη θα συνεχιστεί όταν αποκατασταθεί η σύνδεση.",
"transferPartialHint": "Δεν ήταν δυνατή η μεταφορά: {{paths}}",
"transferSuccess": "Η μεταφορά ολοκληρώθηκε"
}
}
@@ -382,7 +382,10 @@
"defaultPathLabel": "Ruta predeterminada",
"fileManagerPathHint": "Directorio que se abre al iniciar el gestor de archivos para este host.",
"fileManagerUrlCopied": "URL del gestor de archivos copiada",
"copyFileManagerUrlAction": "Copiar URL del gestor de archivos"
"copyFileManagerUrlAction": "Copiar URL del gestor de archivos",
"docsLink": "Ver documentación",
"hostNotFound": "Host no encontrado",
"loadingHost": "Cargando host..."
},
"settings": {
"host": {
@@ -406,5 +409,105 @@
"nav": {
"sftp": "SFTP",
"files": "Archivos"
},
"onboarding": {
"feature_files": "Gestor de archivos",
"feature_files_desc": "Navega, sube, descarga y edita archivos a través de SFTP sin salir de la aplicación."
},
"terminal": {
"runTitle": "Ejecutando {{command}} - {{host}}",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}"
},
"transfer": {
"browseFolders": "Examinar carpetas de destino",
"browsePathError": "No se pudo abrir esta ruta en el host de destino.",
"browsePathWillBeCreated": "Esta carpeta no existe aún. Se creará al iniciar la transferencia.",
"cancel": "Cancelar",
"cleanupDestFiles": "Limpiar destino",
"cleanupDestFilesError": "Error al limpiar",
"cleanupDestFilesNothing": "Nada que limpiar en el destino",
"cleanupDestFilesPartial": "Algunos archivos parciales no se pudieron eliminar",
"cleanupDestFilesSuccess": "Se eliminaron los archivos parciales del destino",
"confirmCopy": "Copiar",
"confirmMove": "Mover",
"copyFolderToHost": "Copiar carpeta al host…",
"copyItemsToHost": "Copiar {{count}} elementos al host…",
"copyToHost": "Copiar al host…",
"destinationPath": "Ruta de destino",
"destMustBeDirectory": "El destino debe ser un directorio para transferencias de múltiples elementos",
"goUp": "Subir",
"hostAuthRequired": "Se requiere autenticación — abre primero el Gestor de Archivos en este host",
"hostConnecting": "Conectando…",
"hostConnectionFailed": "Conexión fallida",
"hostDisconnected": "No conectado",
"hostReady": "Listo",
"itemsSummary": "{{count}} elementos",
"jumpHostLimitation": "Ambos equipos deben ser accesibles desde el servidor de Termix. No se admite el enrutamiento directo entre equipos.",
"methodAuto": "Automático",
"methodAutoHint": "Elige tar o SFTP por archivo según el número de archivos, tamaño y compresibilidad. Los archivos individuales siempre usan SFTP por transmisión continua.",
"methodItemSftp": "SFTP por archivo",
"methodItemSftpHint": "Transfiere cada archivo individualmente por SFTP. Funciona en todos los equipos, incluido Windows.",
"methodItemSftpLimitation": "Cada archivo usa el mismo flujo SFTP que una copia de un solo archivo, uno tras otro. El progreso se combina en todos los archivos, por lo que la barra se mueve lentamente durante archivos grandes.",
"methodLabel": "Método de transferencia",
"methodPreviewError": "No se pudo previsualizar el método de transferencia. El servidor seleccionará un método al iniciar.",
"methodPreviewLoading": "Calculando el método de transferencia…",
"methodPreviewScanSummary": "{{fileCount}} archivos, {{totalSize}} total (analizado en el equipo de origen).",
"methodPreviewWillUseItemSftp": "Se usará: SFTP por archivo",
"methodPreviewWillUseTar": "Se usará: Archivo Tar",
"methodReason": {
"user_item_sftp": "Has elegido SFTP por archivo.",
"user_tar": "Has elegido archivo tar.",
"tar_unavailable": "Tar no está disponible en uno o ambos hosts; se usará SFTP por archivo.",
"windows_host": "Hay un host Windows implicado; no se usa tar.",
"auto_multi_large": "Auto: múltiples archivos incluido uno grande ({{largestSize}}) con datos comprimibles; tar los agrupa en una sola transferencia.",
"auto_single_large_in_archive": "Auto: un archivo grande ({{largestSize}}) en este conjunto; SFTP por archivo.",
"auto_many_incompressible": "Auto: datos mayoritariamente incompresibles; SFTP por archivo.",
"auto_many_files": "Auto: muchos archivos ({{fileCount}}); tar reduce la sobrecarga por archivo.",
"auto_default": "Auto: SFTP por archivo para este conjunto."
},
"methodTar": "Archivo Tar",
"methodTarHint": "Comprime en origen, transfiere un archivo, extrae en destino. Necesita tar en ambos equipos Unix.",
"metricsCompress": "Compresión en origen: {{duration}}",
"metricsExtract": "Extracción en destino: {{duration}}",
"metricsPrepare": "Preparar destino: {{duration}}",
"metricsRouteBenchmark": "Sondeo de ruta: directo: {{direct}}, retransmisión: {{relay}}",
"metricsSourceDelete": "Eliminación del origen: {{duration}}",
"metricsTotal": "Total: {{duration}}",
"metricsTransfer": "Extremo a extremo: {{throughput}} ({{duration}})",
"metricsVerify": "SHA-256 verificado: {{duration}}",
"moveFolderToHost": "Mover carpeta al host…",
"moveItemsToHost": "Mover {{count}} elementos al host…",
"moveToHost": "Mover al host…",
"noHostsConnected": "No hay otros hosts de gestor de archivos disponibles.",
"noHostsConnectedHint": "Añade otro host SSH con el Gestor de Archivos habilitado en el Administrador de Hosts.",
"parallelSegmentsHint": "Los archivos grandes se dividen en fragmentos de 256 MB. Varias vías utilizan conexiones separadas (como iniciar varias transferencias) para un mayor rendimiento total.",
"parallelSegmentsLabel": "Vías de transferencia en paralelo",
"parallelSegmentsOption": "{{count}} vías",
"progressBenchmarking": "Seleccionar la ruta de transferencia más rápida…",
"progressBytes": "{{transferred}} / {{total}}",
"progressCancel": "Cancelar",
"progressCancelling": "Cancelando…",
"progressCompressing": "Comprimiendo en el equipo de origen…",
"progressExtracting": "Extrayendo en el destino…",
"progressItems": "{{current}} / {{total}} archivos",
"progressReconnecting": "Reconectando…",
"progressStalled": "Estancado",
"progressTotalSpeed": "{{speed}} total ({{lanes}} vías)",
"progressTransferring": "Transfiriendo datos…",
"progressTransferringItems": "Transfiriendo archivos ({{current}} de {{total}})…",
"progressVerifying": "Verificando la integridad del archivo…",
"recentDestinations": "Destinos recientes",
"resumedHint": "Reconectado a una transferencia activa iniciada en otra ventana.",
"retryTransfer": "Reintentar",
"retryTransferError": "Error al reintentar",
"selectDestinationHost": "Seleccionar host de destino",
"transferCancelled": "Transferencia cancelada",
"transferCancelledCopyHint": "Pueden quedar archivos parciales en el destino.",
"transferCancelledMoveHint": "Pueden quedar archivos parciales en el destino. Los archivos de origen no se eliminaron.",
"transferError": "Transferencia fallida",
"transferFailedRetryHint": "Se conservaron datos parciales en el destino. El reintento se reanudará cuando se restablezca la conexión.",
"transferPartialHint": "No se pudo transferir: {{paths}}",
"transferSuccess": "Transferencia completada"
}
}
Loaded 100 of 626 files, more files were not shown because too many files have changed in this diff. Show more