diff --git a/client/src/console/App.tsx b/client/src/console/App.tsx index 6513cee1..b306bb06 100644 --- a/client/src/console/App.tsx +++ b/client/src/console/App.tsx @@ -1,7 +1,7 @@ -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { call, isOffline, onTokenExpired } from "./api"; import { focusElement, onNavAction, type InputMap } from "./nav"; -import { SECTIONS } from "./sections"; +import { SECTIONS, type SectionContext, type SectionParams } from "./sections"; import { HintBar } from "./shell/HintBar"; import { Rail } from "./shell/Rail"; import { ReloadBanner } from "./shell/ReloadBanner"; @@ -21,6 +21,16 @@ export function App({ inputMap }: { inputMap: InputMap }) { const [expired, setExpired] = useState(false); const [status, setStatus] = useState(null); const [offline, setOffline] = useState(false); + /** Bumped to read /api/status again at once. */ + const [statusTick, setStatusTick] = useState(0); + /** What the active section was opened with (Home's Browse USB → Files at a path). */ + const [params, setParams] = useState(null); + + /** Switch section; params go only to a section opened through openSection. */ + const show = useCallback((id: string, p: SectionParams | null = null) => { + setActive(id); + setParams(p); + }, []); useEffect(() => onTokenExpired(() => setExpired(true)), []); @@ -46,7 +56,7 @@ export function App({ inputMap }: { inputMap: InputMap }) { live = false; window.clearInterval(timer); }; - }, [expired]); + }, [expired, statusTick]); // Start with focus on the rail, so the D-pad works at once. useEffect(() => { @@ -62,7 +72,7 @@ export function App({ inputMap }: { inputMap: InputMap }) { if (action === "prevSection" || action === "nextSection") { const step = action === "nextSection" ? 1 : SECTIONS.length - 1; const next = SECTIONS[(i + step) % SECTIONS.length].id; - setActive(next); + show(next); const el = railButton(next); if (el) focusElement(el); return true; @@ -73,7 +83,7 @@ export function App({ inputMap }: { inputMap: InputMap }) { const el = railButton(active); if (el) focusElement(el); } else if (active !== SECTIONS[0].id) { - setActive(SECTIONS[0].id); + show(SECTIONS[0].id); const el = railButton(SECTIONS[0].id); if (el) focusElement(el); } @@ -81,7 +91,23 @@ export function App({ inputMap }: { inputMap: InputMap }) { } return false; }), - [active], + [active, show], + ); + + const ctx = useMemo( + () => ({ + status, + refreshStatus: () => setStatusTick((n) => n + 1), + openSection: (id, p) => { + if (!SECTIONS.some((s) => s.id === id)) return; + show(id, p ?? null); + const el = railButton(id); + if (el) focusElement(el); + }, + canOpen: (id) => SECTIONS.some((s) => s.id === id && s.acceptsParams), + params, + }), + [status, params, show], ); const section = SECTIONS.find((s) => s.id === active) ?? SECTIONS[0]; @@ -91,8 +117,8 @@ export function App({ inputMap }: { inputMap: InputMap }) {
- -
{section.render()}
+ show(id)} /> +
{section.render(ctx)}
{expired ? : null} diff --git a/client/src/console/console.css b/client/src/console/console.css index a38dbc28..7b824895 100644 --- a/client/src/console/console.css +++ b/client/src/console/console.css @@ -243,3 +243,236 @@ button { width: 1.2rem; height: 1.2rem; } +.cw-button.is-danger { + background: var(--color-bad); + color: #fff; +} +.cw-button.is-danger:focus { + background: var(--color-bad); + box-shadow: 0 0 0 4px var(--color-bad-soft); +} + +/* ---- shared text ---- */ +.cw-h2 { + margin: 0 0 0.5rem; + font-size: 1.1rem; + font-weight: 600; +} +.cw-dim { + color: var(--color-muted); +} +.cw-mono { + font-family: var(--font-mono, ui-monospace, monospace); + font-size: 0.8rem; +} +.cw-tag { + display: inline-block; + padding: 0.05rem 0.5rem; + margin-left: 0.6rem; + border-radius: var(--radius-control); + background: var(--color-pill); + color: var(--color-muted); + font-size: 0.75rem; + font-weight: 500; + white-space: nowrap; +} +.cw-tag.is-pc { + background: var(--color-accent-soft); + color: var(--color-accent); +} + +/* ---- progress bar ---- */ +.cw-bar { + height: 0.4rem; + margin: 0.35rem 0; + border-radius: 0.2rem; + background: var(--color-surface-3); + overflow: hidden; +} +.cw-bar-fill { + height: 100%; + border-radius: 0.2rem; + background: var(--accent-fill); +} +.cw-bar-fill.is-warn { + background: var(--color-warn); +} +.cw-bar-fill.is-unknown { + opacity: 0.4; +} + +/* ---- confirm dialog ---- */ +.cw-scrim { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + background: var(--overlay-scrim, rgba(0, 0, 0, 0.6)); + z-index: 20; +} +.cw-dialog { + width: 32rem; + max-width: calc(100vw - 2rem); + padding: 1.2rem 1.4rem; + border-radius: var(--radius-panel); + background: var(--color-float); + border: 1px solid var(--color-border-strong); + box-shadow: var(--shadow-3); +} +.cw-dialog h2 { + margin: 0 0 0.4rem; + font-size: 1.2rem; +} +.cw-dialog p { + margin: 0 0 1rem; + color: var(--color-muted); +} +.cw-dialog-buttons { + display: flex; + justify-content: flex-end; +} +.cw-dialog-buttons .cw-button { + margin-left: 0.8rem; +} + +/* ---- Home ---- */ +.cw-msg { + margin: 0 0 0.8rem; + padding: 0.5rem 0.9rem; + border-radius: var(--radius-field); + background: var(--color-surface-2); +} +.cw-msg.is-error { + background: var(--color-bad-soft); + color: var(--color-bad); +} +.cw-msg.is-info { + background: var(--color-good-soft); + color: var(--color-good); +} +.cw-quick { + display: flex; + flex-wrap: wrap; + margin-bottom: 0.6rem; +} +.cw-quick .cw-button { + margin: 0 0.7rem 0.5rem 0; +} +.cw-card { + border-radius: var(--radius-card); + background: var(--color-surface); + border: 1px solid var(--color-border); +} +.cw-game { + display: flex; + align-items: center; + padding: 0.8rem 1rem; + margin-bottom: 1.2rem; +} +.cw-game-icon { + flex: none; + width: 2rem; + height: 2rem; + margin-right: 0.9rem; + color: var(--color-muted); +} +.cw-game-text { + flex: 1; + min-width: 0; +} +.cw-game-title { + font-size: 1.15rem; + font-weight: 600; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.cw-home-section { + margin-bottom: 1.2rem; +} +.cw-home-section > p { + margin: 0; +} +.cw-tasks, +.cw-volumes { + list-style: none; + margin: 0; + padding: 0; +} +.cw-task { + display: flex; + align-items: center; + margin-bottom: 0.5rem; + padding-right: 0.8rem; + border-radius: var(--radius-card); + background: var(--color-surface); + border: 1px solid var(--color-border); +} +.cw-task-main { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + padding: 0.6rem 0.9rem; + text-align: left; +} +.cw-task-icon { + flex: none; + width: 1.5rem; + height: 1.5rem; + margin-right: 0.8rem; + color: var(--color-muted); +} +.cw-task-text { + flex: 1; + min-width: 0; +} +.cw-task-title { + font-weight: 600; +} +.cw-task-sub { + font-size: 0.85rem; +} +.cw-task.is-failed .cw-task-sub { + color: var(--color-bad); +} +.cw-task.is-done .cw-task-sub { + color: var(--color-good); +} +.cw-task > .cw-button { + flex: none; + margin-left: 0.8rem; +} +.cw-volumes { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); + grid-gap: 0.8rem; + gap: 0.8rem; +} +.cw-volume { + padding: 0.7rem 0.9rem; + border-radius: var(--radius-card); + background: var(--color-surface); + border: 1px solid var(--color-border); +} +.cw-volume-head { + display: flex; + align-items: center; +} +.cw-volume-head svg { + flex: none; + width: 1.3rem; + height: 1.3rem; + margin-right: 0.5rem; + color: var(--color-muted); +} +.cw-volume-name { + font-weight: 600; +} +.cw-volume-free { + font-size: 0.85rem; +} diff --git a/client/src/console/home/Home.test.tsx b/client/src/console/home/Home.test.tsx new file mode 100644 index 00000000..52d5b9dc --- /dev/null +++ b/client/src/console/home/Home.test.tsx @@ -0,0 +1,234 @@ +import { isValidElement, type ReactElement, type ReactNode } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("../api", async (importOriginal) => { + const real = await importOriginal(); + return { ...real, call: vi.fn() }; +}); + +import { ApiError, call } from "../api"; +import { t } from "../strings"; +import { ConfirmDialog, dialogNavHandler } from "../ui/ConfirmDialog"; +import { errorText, firstUsbVolume, HomeView, runAsk, type Ask, type HomeViewProps, type Volume } from "./Home"; +import { TaskRow } from "./TaskRow"; +import { cancelJob, type Job } from "./useJobs"; + +const mockCall = vi.mocked(call); + +const job = (over: Partial = {}): Job => ({ + job: "0123456789abcdef0123456789abcdef", + kind: "copy", + state: "running", + files_done: 1, + files_total: 4, + bytes_done: 100, + bytes_total: 400, + mine: true, + ...over, +}); + +const vol = (path: string, mount_from: string, over: Partial = {}): Volume => ({ + path, + mount_from, + fs_type: "ufs", + total_bytes: 1000, + free_bytes: 250, + writable: true, + ...over, +}); + +/** Every element in `node`'s tree (function components are not expanded). */ +function elements(node: ReactNode): ReactElement>[] { + const out: ReactElement>[] = []; + const walk = (n: ReactNode) => { + if (Array.isArray(n)) return n.forEach(walk); + if (!isValidElement(n)) return; + const el = n as ReactElement>; + out.push(el); + walk(el.props.children as ReactNode); + }; + walk(node); + return out; +} + +const byAction = (node: ReactNode, action: string) => { + const el = elements(node).find((e) => e.props["data-action"] === action); + if (!el) throw new Error(`no element with data-action=${action}`); + return el; +}; + +function viewProps(over: Partial = {}): HomeViewProps { + return { + status: null, + volumes: [], + volumesError: false, + jobs: [], + jobsLoaded: true, + jobsError: false, + ask: null, + busy: false, + message: null, + onAsk: vi.fn(), + onConfirm: vi.fn(), + onDismiss: vi.fn(), + onBrowseUsb: null, + ...over, + }; +} + +beforeEach(() => { + mockCall.mockReset(); + mockCall.mockResolvedValue({}); +}); + +describe("Home", () => { + it("shows_pc_job_as_from_pc", () => { + expect(t("cw_task_from_pc")).not.toBe("cw_task_from_pc"); + const pc = renderToStaticMarkup( {}} />); + expect(pc).toContain(t("cw_task_from_pc")); + expect(pc).not.toContain(t("cw_task_from_console")); + const mine = renderToStaticMarkup( {}} />); + expect(mine).toContain(t("cw_task_from_console")); + }); + + it("cancel_asks_confirm_then_calls_api", async () => { + const running = job({ mine: false }); + // Cancel on the row only asks. + const onCancel = vi.fn(); + (byAction(TaskRow({ job: running, onCancel }), "cancel").props.onClick as () => void)(); + expect(onCancel).toHaveBeenCalledWith(running); + expect(mockCall).not.toHaveBeenCalled(); + + // The ask opens the confirm dialog; focus starts on the safe choice. + const ask: Ask = { kind: "cancel", job: running }; + const props = viewProps({ ask, jobs: [running] }); + const html = renderToStaticMarkup(); + expect(html).toContain("data-nav-modal"); + expect(html).toContain(t("cw_home_confirm_cancel_title")); + const dialog = elements(HomeView(props)).find((e) => e.type === ConfirmDialog); + expect(dialog).toBeDefined(); + expect(mockCall).not.toHaveBeenCalled(); + + // "Keep going" (or ○) closes it with no call. + (dialog!.props.onCancel as () => void)(); + expect(props.onDismiss).toHaveBeenCalled(); + expect(mockCall).not.toHaveBeenCalled(); + + // Confirm runs the ask: POST /api/jobs/cancel {job}. + (dialog!.props.onConfirm as () => void)(); + expect(props.onConfirm).toHaveBeenCalled(); + await runAsk(ask, { cancel: cancelJob }); + expect(mockCall).toHaveBeenCalledWith("/api/jobs/cancel", { + job: running.job, + }); + }); + + it("a finished task has no Cancel", () => { + expect(() => byAction(TaskRow({ job: job({ state: "done" }), onCancel: () => {} }), "cancel")).toThrow(); + }); + + it("close game asks, then posts the app id", async () => { + const props = viewProps({ + status: { + version: null, + firmware: null, + model: null, + temp_c: null, + running: { title_id: "PPSA01234", app_id: 77, name: null }, + }, + }); + (byAction(HomeView(props), "close-game").props.onClick as () => void)(); + const ask: Ask = { kind: "close", appId: 77, titleId: "PPSA01234" }; + expect(props.onAsk).toHaveBeenCalledWith(ask); + expect(mockCall).not.toHaveBeenCalled(); + await runAsk(ask, { cancel: cancelJob }); + expect(mockCall).toHaveBeenCalledWith("/api/app/close", { app_id: 77 }); + }); + + it("rest mode and restart ask, then post the power action", async () => { + const props = viewProps(); + (byAction(HomeView(props), "rest").props.onClick as () => void)(); + (byAction(HomeView(props), "restart").props.onClick as () => void)(); + expect(props.onAsk).toHaveBeenNthCalledWith(1, { + kind: "power", + action: "rest", + }); + expect(props.onAsk).toHaveBeenNthCalledWith(2, { + kind: "power", + action: "reboot", + }); + expect(mockCall).not.toHaveBeenCalled(); + await runAsk({ kind: "power", action: "rest" }, { cancel: cancelJob }); + expect(mockCall).toHaveBeenCalledWith("/api/power", { action: "rest" }); + await runAsk({ kind: "power", action: "reboot" }, { cancel: cancelJob }); + expect(mockCall).toHaveBeenCalledWith("/api/power", { action: "reboot" }); + }); + + it("Browse USB shows only when there is somewhere to go", () => { + expect(() => byAction(HomeView(viewProps()), "browse-usb")).toThrow(); + const go = vi.fn(); + (byAction(HomeView(viewProps({ onBrowseUsb: go })), "browse-usb").props.onClick as () => void)(); + expect(go).toHaveBeenCalled(); + }); + + it("first USB volume: a /mnt/usbN stick or USB extended storage, never internal or M.2", () => { + expect(firstUsbVolume([vol("/data", "/dev/ssd0.user"), vol("/mnt/ext0", "/dev/nvme0p1")])).toBeNull(); + expect( + firstUsbVolume([vol("/data", "x"), vol("/mnt/ext1", "/dev/da0"), vol("/mnt/usb0", "/dev/da1s1")])?.path, + ).toBe("/mnt/ext1"); + expect(firstUsbVolume([vol("/mnt/usb0", "/dev/da0s1")])?.path).toBe("/mnt/usb0"); + }); + + it("one storage card per drive with free of total", () => { + const html = renderToStaticMarkup( + , + ); + expect(html).toContain(t("cw_home_vol_internal")); + expect(html).toContain(t("cw_home_vol_usb")); + expect(html.split("data-volume=").length - 1).toBe(2); + }); + + it("errors become short translated messages", () => { + expect(errorText(new ApiError(0, "offline"))).toBe(t("cw_home_err_offline")); + expect(errorText(new ApiError(409, "busy"))).toBe(t("cw_home_err_busy")); + expect(errorText(new ApiError(404, "unknown_job"))).toBe(t("cw_home_err_gone")); + expect(errorText(new ApiError(500, "io_error"))).toBe(t("cw_home_err_failed", { code: "io_error" })); + expect(errorText(new ApiError(401, "token"))).toBeNull(); // the reload banner says it + expect(errorText(new Error("x"))).toBe(t("cw_home_err_failed", { code: "x" })); + }); + + it("the shown message renders as an alert", () => { + const html = renderToStaticMarkup(); + expect(html).toContain('role="alert"'); + expect(html).toContain("Nope"); + }); +}); + +describe("ConfirmDialog", () => { + it("is a nav modal whose safe choice is the default focus", () => { + const html = renderToStaticMarkup( + {}} onCancel={() => {}} />, + ); + expect(html).toContain("data-nav-modal"); + expect(html).toContain('role="alertdialog"'); + // The cancel button comes first and carries data-nav-default. + const safe = html.indexOf("data-nav-default"); + expect(safe).toBeGreaterThan(-1); + expect(safe).toBeLessThan(html.indexOf("Do it")); + expect(html).toContain(t("cw_dialog_cancel")); + }); + + it("○ cancels; other actions are swallowed while it is open", () => { + const onCancel = vi.fn(); + const handle = dialogNavHandler(onCancel); + expect(handle("back")).toBe(true); + expect(onCancel).toHaveBeenCalledTimes(1); + expect(handle("nextSection")).toBe(true); + expect(onCancel).toHaveBeenCalledTimes(1); + }); +}); diff --git a/client/src/console/home/Home.tsx b/client/src/console/home/Home.tsx new file mode 100644 index 00000000..423f8dc5 --- /dev/null +++ b/client/src/console/home/Home.tsx @@ -0,0 +1,399 @@ +import { useCallback, useEffect, useState } from "react"; +import { FolderOpen, Gamepad2, HardDrive, Moon, RotateCw, Usb, X } from "lucide-react"; +import { formatBytes } from "../../lib/format"; +import { ApiError, call, isOffline } from "../api"; +import type { SectionContext } from "../sections"; +import type { ConsoleStatus } from "../shell/TopBar"; +import { t } from "../strings"; +import { ConfirmDialog } from "../ui/ConfirmDialog"; +import { TaskRow } from "./TaskRow"; +import { useJobs, type Job } from "./useJobs"; + +/** Free space moves with every write: re-read this often while Home is open. */ +const VOLUMES_POLL_MS = 15_000; +/** An action's result line clears itself after this long. */ +const MESSAGE_MS = 8_000; + +/** One /api/volumes entry (payload/src/runtime.c handle_fs_list_volumes). */ +export interface Volume { + path: string; + mount_from: string; + fs_type: string; + total_bytes: number; + free_bytes: number; + writable: boolean; + source_image?: string; +} + +/** Something Home asks about before doing it. */ +export type Ask = + | { kind: "cancel"; job: Job } + | { kind: "close"; appId: number; titleId: string } + | { kind: "power"; action: "rest" | "reboot" }; + +export interface Message { + tone: "error" | "info"; + text: string; +} + +/* ---- volumes ---- */ + +const isUsbStick = (v: Volume) => /^\/mnt\/usb\d+$/.test(v.path); +const isExt = (v: Volume) => /^\/mnt\/ext\d+$/.test(v.path); +/** A USB drive formatted as PS5 extended storage (M.2 is /dev/nvme*). */ +const isUsbExt = (v: Volume) => isExt(v) && v.mount_from.startsWith("/dev/da"); + +/** The console's drives: internal, extended/M.2 and USB. Mounted disk images are left out. */ +export function isDrive(v: Volume): boolean { + return v.path === "/data" || isExt(v) || isUsbStick(v); +} + +/** The first USB drive in the helper's order (a stick or USB extended storage), or null. */ +export function firstUsbVolume(volumes: Volume[]): Volume | null { + return volumes.find((v) => isUsbStick(v) || isUsbExt(v)) ?? null; +} + +export function volumeLabel(v: Volume): string { + if (v.path === "/data") return t("cw_home_vol_internal"); + if (isUsbStick(v)) return t("cw_home_vol_usb"); + if (isUsbExt(v)) return t("cw_home_vol_usb_ext"); + if (v.mount_from.startsWith("/dev/nvme")) return t("cw_home_vol_m2"); + return t("cw_home_vol_ext"); +} + +/* ---- actions ---- */ + +/** A failed call as one short translated line; null for a 401 (the reload banner says it). */ +export function errorText(err: unknown): string | null { + if (err instanceof ApiError) { + if (err.status === 401) return null; + if (isOffline(err)) return t("cw_home_err_offline"); + if (err.code === "busy") return t("cw_home_err_busy"); + if (err.code === "unknown_job") return t("cw_home_err_gone"); + return t("cw_home_err_failed", { code: err.code }); + } + return t("cw_home_err_failed", { + code: err instanceof Error ? err.message : String(err), + }); +} + +/** Do what was confirmed. Resolves to a line to show (the power actions), throws the ApiError. */ +export async function runAsk(ask: Ask, deps: { cancel: (id: string) => Promise }): Promise { + switch (ask.kind) { + case "cancel": + await deps.cancel(ask.job.job); + return null; + case "close": + await call("/api/app/close", { app_id: ask.appId }); + return null; + case "power": + await call("/api/power", { action: ask.action }); + return t(ask.action === "rest" ? "cw_home_rest_sent" : "cw_home_restart_sent"); + } +} + +function askCopy(ask: Ask): { + title: string; + body: string; + confirm: string; + cancel?: string; + danger: boolean; +} { + switch (ask.kind) { + case "cancel": + return { + title: t("cw_home_confirm_cancel_title"), + body: t(ask.job.mine ? "cw_home_confirm_cancel_body" : "cw_home_confirm_cancel_body_pc"), + confirm: t("cw_home_cancel_task_confirm"), + cancel: t("cw_home_keep_task"), + danger: true, + }; + case "close": + return { + title: t("cw_home_confirm_close_title", { name: ask.titleId }), + body: t("cw_home_confirm_close_body"), + confirm: t("cw_home_close_game"), + danger: true, + }; + case "power": + return ask.action === "rest" + ? { + title: t("cw_home_confirm_rest_title"), + body: t("cw_home_confirm_rest_body"), + confirm: t("cw_home_rest"), + danger: false, + } + : { + title: t("cw_home_confirm_restart_title"), + body: t("cw_home_confirm_restart_body"), + confirm: t("cw_home_restart"), + danger: true, + }; + } +} + +/* ---- view ---- */ + +export interface HomeViewProps { + status: ConsoleStatus | null; + /** null until the first answer. */ + volumes: Volume[] | null; + volumesError: boolean; + jobs: Job[]; + jobsLoaded: boolean; + jobsError: boolean; + ask: Ask | null; + busy: boolean; + message: Message | null; + onAsk: (ask: Ask) => void; + onConfirm: () => void; + onDismiss: () => void; + /** Browse USB, or null to hide it (no USB drive, or Files cannot open a path yet). */ + onBrowseUsb: (() => void) | null; +} + +function VolumeCard({ v }: { v: Volume }) { + const used = v.total_bytes > 0 ? Math.max(0, Math.min(100, 100 - (v.free_bytes / v.total_bytes) * 100)) : 0; + const Icon = isUsbStick(v) || isUsbExt(v) ? Usb : HardDrive; + return ( +
  • +
    + + {volumeLabel(v)} + {!v.writable ? {t("cw_home_vol_readonly")} : null} +
    +
    {v.path}
    +
    +
    = 90 ? " is-warn" : ""}`} style={{ width: `${used}%` }} /> +
    +
    + {t("cw_home_free_of", { + free: formatBytes(v.free_bytes), + total: formatBytes(v.total_bytes), + })} +
    +
  • + ); +} + +/** Home without state: everything comes in through props (tests render it directly). */ +export function HomeView(p: HomeViewProps) { + const running = p.status?.running ?? null; + const tasks = p.jobs.filter((j) => j.state === "running").concat(p.jobs.filter((j) => j.state !== "running")); + const drives = (p.volumes ?? []).filter(isDrive); + const copy = p.ask ? askCopy(p.ask) : null; + + let tasksNote: string | null = null; + if (p.jobsError && !tasks.length) tasksNote = t("cw_home_err_load_tasks"); + else if (!p.jobsLoaded) tasksNote = t("cw_home_loading"); + else if (!tasks.length) tasksNote = t("cw_home_no_tasks"); + + let drivesNote: string | null = null; + if (p.volumesError && !drives.length) drivesNote = t("cw_home_err_load_storage"); + else if (p.volumes == null) drivesNote = t("cw_home_loading"); + + return ( +
    +

    {t("cw_nav_home")}

    + {p.message ? ( +
    + {p.message.text} +
    + ) : null} + +
    + {p.onBrowseUsb ? ( + + ) : null} + + +
    + +
    + + {running ? ( + <> +
    +
    {t("cw_home_now_running")}
    +
    {running.name ?? running.title_id}
    + {running.name ?
    {running.title_id}
    : null} +
    + + + ) : ( +
    {p.status ? t("cw_home_no_game") : t("cw_home_loading")}
    + )} +
    + +
    +

    {t("cw_home_tasks")}

    + {p.jobsError && tasks.length ?
    {t("cw_home_err_load_tasks")}
    : null} + {tasksNote ? ( +

    {tasksNote}

    + ) : ( +
      + {tasks.map((j) => ( + p.onAsk({ kind: "cancel", job })} /> + ))} +
    + )} +
    + +
    +

    {t("cw_home_storage")}

    + {drivesNote ? ( +

    {drivesNote}

    + ) : ( +
      + {drives.map((v) => ( + + ))} +
    + )} +
    + + {p.ask && copy ? ( + + ) : null} +
    + ); +} + +/* ---- the section ---- */ + +function useVolumes(): { volumes: Volume[] | null; error: boolean } { + const [volumes, setVolumes] = useState(null); + const [error, setError] = useState(false); + useEffect(() => { + let live = true; + let timer: ReturnType | undefined; + const load = () => { + call<{ volumes?: unknown }>("/api/volumes").then( + (r) => { + if (!live) return; + setVolumes(Array.isArray(r?.volumes) ? (r.volumes as Volume[]) : []); + setError(false); + timer = setTimeout(load, VOLUMES_POLL_MS); + }, + (e: unknown) => { + if (!live) return; + setError(true); + // The token is gone: every read would 401 until the page reloads. + if (!(e instanceof ApiError && e.status === 401)) timer = setTimeout(load, VOLUMES_POLL_MS); + }, + ); + }; + load(); + return () => { + live = false; + if (timer !== undefined) clearTimeout(timer); + }; + }, []); + return { volumes, error }; +} + +/** The Home section: the running game, tasks, storage and quick actions. */ +export function Home({ ctx }: { ctx: SectionContext }) { + const { jobs, loaded, error: jobsError, cancel } = useJobs(); + const { volumes, error: volumesError } = useVolumes(); + const [ask, setAsk] = useState(null); + const [busy, setBusy] = useState(false); + const [message, setMessage] = useState(null); + const { refreshStatus, openSection, canOpen } = ctx; + + useEffect(() => { + if (!message) return; + const timer = setTimeout(() => setMessage(null), MESSAGE_MS); + return () => clearTimeout(timer); + }, [message]); + + const onConfirm = useCallback(() => { + if (!ask || busy) return; + setBusy(true); + runAsk(ask, { cancel }) + .then( + (notice) => { + setMessage(notice ? { tone: "info", text: notice } : null); + if (ask.kind === "close") refreshStatus(); + }, + (e: unknown) => { + const text = errorText(e); + setMessage(text ? { tone: "error", text } : null); + }, + ) + .finally(() => { + setBusy(false); + setAsk(null); + }); + }, [ask, busy, cancel, refreshStatus]); + + const onDismiss = useCallback(() => { + if (!busy) setAsk(null); + }, [busy]); + + const usb = volumes ? firstUsbVolume(volumes) : null; + const onBrowseUsb = usb && canOpen("files") ? () => openSection("files", { path: usb.path }) : null; + + return ( + { + setMessage(null); + setAsk(a); + }} + onConfirm={onConfirm} + onDismiss={onDismiss} + onBrowseUsb={onBrowseUsb} + /> + ); +} diff --git a/client/src/console/home/TaskRow.tsx b/client/src/console/home/TaskRow.tsx new file mode 100644 index 00000000..b596a4e6 --- /dev/null +++ b/client/src/console/home/TaskRow.tsx @@ -0,0 +1,88 @@ +import { CircleX, Copy, Download, FolderCog, ListTodo, Upload, type LucideIcon } from "lucide-react"; +import { formatBytes } from "../../lib/format"; +import { t } from "../strings"; +import type { Job } from "./useJobs"; + +const KIND_ICON: Record = { + upload: Upload, + download: Download, + copy: Copy, + op: FolderCog, + other: ListTodo, +}; + +export function kindLabel(kind: Job["kind"]): string { + return t(`cw_home_kind_${KIND_ICON[kind] ? kind : "other"}`); +} + +/** 0–100 from bytes, else from files; null when the job reports neither. */ +export function jobPercent(j: Job): number | null { + const [done, total] = j.bytes_total > 0 ? [j.bytes_done, j.bytes_total] : [j.files_done, j.files_total]; + if (!(total > 0)) return null; + return Math.max(0, Math.min(100, Math.floor((done / total) * 100))); +} + +function progressText(j: Job): string { + const parts: string[] = []; + if (j.bytes_total > 0) + parts.push( + t("cw_home_progress_bytes", { + done: formatBytes(j.bytes_done), + total: formatBytes(j.bytes_total), + }), + ); + if (j.files_total > 0) parts.push(t("cw_home_progress_files", { done: j.files_done, total: j.files_total })); + return parts.join(" · "); +} + +/** + * One task on Home: what it is, who started it, how far it is. The row itself + * is focusable so the D-pad reaches (and scrolls to) every task; a running one + * has a Cancel button, which only asks (Home shows the confirm). + */ +export function TaskRow({ job, onCancel }: { job: Job; onCancel: (job: Job) => void }) { + const Icon = KIND_ICON[job.kind] ?? ListTodo; + const pct = jobPercent(job); + const running = job.state === "running"; + const progress = progressText(job); + return ( +
  • +
    + +
    +
    + {kindLabel(job.kind)} + + {t(job.mine ? "cw_task_from_console" : "cw_task_from_pc")} + +
    + {running ? ( +
    +
    +
    + ) : null} +
    + {running + ? pct != null + ? t("cw_home_percent", { n: pct }) + : t("cw_home_state_running") + : t(job.state === "done" ? "cw_home_state_done" : "cw_home_state_failed")} + {progress ? {` · ${progress}`} : null} +
    +
    +
    + {running ? ( + + ) : null} +
  • + ); +} diff --git a/client/src/console/home/useJobs.test.ts b/client/src/console/home/useJobs.test.ts new file mode 100644 index 00000000..c29b6df3 --- /dev/null +++ b/client/src/console/home/useJobs.test.ts @@ -0,0 +1,121 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("../api", async (importOriginal) => { + const real = await importOriginal(); + return { ...real, call: vi.fn() }; +}); + +import { ApiError, call } from "../api"; +import { cancelJob, createJobsPoller, JOBS_FAST_MS, JOBS_SLOW_MS, nextJobsDelay, type Job } from "./useJobs"; + +const mockCall = vi.mocked(call); + +const job = (state: Job["state"], over: Partial = {}): Job => ({ + job: "0123456789abcdef0123456789abcdef", + kind: "copy", + state, + files_done: 1, + files_total: 4, + bytes_done: 100, + bytes_total: 400, + mine: true, + ...over, +}); + +const jobsCalls = () => mockCall.mock.calls.filter((c) => c[0] === "/api/jobs").length; + +describe("useJobs poller", () => { + beforeEach(() => { + vi.useFakeTimers(); + mockCall.mockReset(); + }); + afterEach(() => { + vi.useRealTimers(); + }); + + it("polls_fast_while_running_then_slow", async () => { + const replies = [[job("running")], [job("done")], [job("done")]]; + mockCall.mockImplementation(async () => ({ jobs: replies.shift() ?? [] })); + const seen: Job[][] = []; + const p = createJobsPoller({ + onJobs: (j) => seen.push(j), + onError: () => {}, + }); + p.start(); + await vi.advanceTimersByTimeAsync(0); + expect(jobsCalls()).toBe(1); + expect(seen[0][0].state).toBe("running"); + + // something runs: the next read comes after JOBS_FAST_MS + await vi.advanceTimersByTimeAsync(JOBS_FAST_MS - 1); + expect(jobsCalls()).toBe(1); + await vi.advanceTimersByTimeAsync(1); + expect(jobsCalls()).toBe(2); + + // nothing runs any more: the poller backs off to JOBS_SLOW_MS + await vi.advanceTimersByTimeAsync(JOBS_FAST_MS); + expect(jobsCalls()).toBe(2); + await vi.advanceTimersByTimeAsync(JOBS_SLOW_MS - JOBS_FAST_MS); + expect(jobsCalls()).toBe(3); + p.stop(); + }); + + it("stops polling once stopped (the section unmounted)", async () => { + mockCall.mockResolvedValue({ jobs: [job("running")] }); + const p = createJobsPoller({ onJobs: () => {}, onError: () => {} }); + p.start(); + await vi.advanceTimersByTimeAsync(0); + p.stop(); + await vi.advanceTimersByTimeAsync(JOBS_SLOW_MS * 3); + expect(jobsCalls()).toBe(1); + }); + + it("reports errors and backs off; stops for good on 401", async () => { + mockCall.mockRejectedValueOnce(new ApiError(0, "offline")).mockRejectedValueOnce(new ApiError(401, "token")); + const errors: unknown[] = []; + const p = createJobsPoller({ + onJobs: () => {}, + onError: (e) => errors.push(e), + }); + p.start(); + await vi.advanceTimersByTimeAsync(0); + expect(errors).toHaveLength(1); + await vi.advanceTimersByTimeAsync(JOBS_FAST_MS); + expect(jobsCalls()).toBe(1); // an error backs off, it does not hammer + await vi.advanceTimersByTimeAsync(JOBS_SLOW_MS); + expect(jobsCalls()).toBe(2); + expect(errors).toHaveLength(2); + await vi.advanceTimersByTimeAsync(JOBS_SLOW_MS * 3); + expect(jobsCalls()).toBe(2); // the token is gone: every read would 401 + }); + + it("refresh reads at once without overlapping a read in flight", async () => { + let release: (v: unknown) => void = () => {}; + mockCall.mockImplementationOnce(() => new Promise((r) => (release = r))); + mockCall.mockResolvedValue({ jobs: [] }); + const p = createJobsPoller({ onJobs: () => {}, onError: () => {} }); + p.start(); + await vi.advanceTimersByTimeAsync(0); + p.refresh(); + await vi.advanceTimersByTimeAsync(0); + expect(jobsCalls()).toBe(1); // still waiting for the first answer + release({ jobs: [] }); + await vi.advanceTimersByTimeAsync(0); + expect(jobsCalls()).toBe(2); // the refresh ran right after it + p.stop(); + }); + + it("delay: fast only while some job is running", () => { + expect(nextJobsDelay([])).toBe(JOBS_SLOW_MS); + expect(nextJobsDelay([job("done"), job("failed")])).toBe(JOBS_SLOW_MS); + expect(nextJobsDelay([job("done"), job("running")])).toBe(JOBS_FAST_MS); + expect(JOBS_FAST_MS).toBe(1000); + expect(JOBS_SLOW_MS).toBe(5000); + }); + + it("cancelJob posts the job id", async () => { + mockCall.mockResolvedValue({}); + await cancelJob("abc"); + expect(mockCall).toHaveBeenCalledWith("/api/jobs/cancel", { job: "abc" }); + }); +}); diff --git a/client/src/console/home/useJobs.ts b/client/src/console/home/useJobs.ts new file mode 100644 index 00000000..c2113e07 --- /dev/null +++ b/client/src/console/home/useJobs.ts @@ -0,0 +1,152 @@ +/** + * The helper's jobs, every owner's (the PC app's uploads and copies as well as + * the page's own), read from /api/jobs: about once a second while one runs, + * every five seconds otherwise. The poller stops when the section unmounts and + * for good on a 401 (the token is gone; the reload banner takes over). + */ +import { useCallback, useEffect, useRef, useState } from "react"; +import { ApiError, call } from "../api"; + +/** One /api/jobs entry (payload/src/webui_codec.c webui_jobs_to_json). */ +export interface Job { + /** 32 lowercase hex chars. */ + job: string; + kind: "upload" | "download" | "copy" | "op" | "other"; + state: "running" | "done" | "failed"; + files_done: number; + files_total: number; + bytes_done: number; + bytes_total: number; + /** Started from this page (false: a paired PC's job). */ + mine: boolean; +} + +export const JOBS_FAST_MS = 1000; +export const JOBS_SLOW_MS = 5000; + +/** How long until the next read after `jobs`. */ +export function nextJobsDelay(jobs: Job[]): number { + return jobs.some((j) => j.state === "running") ? JOBS_FAST_MS : JOBS_SLOW_MS; +} + +async function fetchJobs(): Promise { + const r = await call<{ jobs?: unknown }>("/api/jobs"); + return Array.isArray(r?.jobs) ? (r.jobs as Job[]) : []; +} + +/** Ask the helper to stop job `id` (any owner's). */ +export async function cancelJob(id: string): Promise { + await call("/api/jobs/cancel", { job: id }); +} + +export interface JobsPoller { + start(): void; + stop(): void; + /** Read now (after a cancel), never two reads at once. */ + refresh(): void; +} + +/** The polling loop behind useJobs, with no React in it. */ +export function createJobsPoller(opts: { onJobs: (jobs: Job[]) => void; onError: (err: unknown) => void }): JobsPoller { + let timer: ReturnType | undefined; + let stopped = false; + let inFlight = false; + let again = false; + + const schedule = (ms: number) => { + if (stopped) return; + if (timer !== undefined) clearTimeout(timer); + timer = setTimeout(tick, ms); + }; + + async function tick(): Promise { + timer = undefined; + if (stopped) return; + if (inFlight) { + again = true; + return; + } + inFlight = true; + let delay = JOBS_SLOW_MS; + try { + const jobs = await fetchJobs(); + if (stopped) return; + opts.onJobs(jobs); + delay = nextJobsDelay(jobs); + } catch (e) { + if (stopped) return; + opts.onError(e); + if (e instanceof ApiError && e.status === 401) { + stopped = true; + return; + } + } finally { + inFlight = false; + } + if (again) { + again = false; + delay = 0; + } + schedule(delay); + } + + return { + start() { + schedule(0); + }, + stop() { + stopped = true; + if (timer !== undefined) clearTimeout(timer); + timer = undefined; + }, + refresh() { + if (stopped) return; + if (inFlight) again = true; + else schedule(0); + }, + }; +} + +export interface JobsState { + jobs: Job[]; + /** The first answer has come in. */ + loaded: boolean; + /** The last read failed (null after a good one). */ + error: unknown; + /** Stop job `id`; throws the ApiError when the helper refuses. Re-reads either way. */ + cancel(id: string): Promise; +} + +export function useJobs(): JobsState { + const [jobs, setJobs] = useState([]); + const [loaded, setLoaded] = useState(false); + const [error, setError] = useState(null); + const poller = useRef(null); + + useEffect(() => { + const p = createJobsPoller({ + onJobs: (j) => { + setJobs(j); + setLoaded(true); + setError(null); + }, + onError: setError, + }); + poller.current = p; + p.start(); + return () => { + p.stop(); + if (poller.current === p) poller.current = null; + }; + }, []); + + const cancel = useCallback(async (id: string) => { + try { + await cancelJob(id); + } finally { + poller.current?.refresh(); + } + }, []); + + return { jobs, loaded, error, cancel }; +} diff --git a/client/src/console/sections.tsx b/client/src/console/sections.tsx index adc82b8c..85f2612d 100644 --- a/client/src/console/sections.tsx +++ b/client/src/console/sections.tsx @@ -1,13 +1,34 @@ import type { ReactNode } from "react"; import { Folder, House, Settings, type LucideIcon } from "lucide-react"; +import { Home } from "./home/Home"; +import type { ConsoleStatus } from "./shell/TopBar"; import { t } from "./strings"; +/** What a section is opened with, e.g. Files at {path: "/mnt/usb0"}. */ +export type SectionParams = Record; + +/** What App hands every section. */ +export interface SectionContext { + /** The last /api/status answer (App polls it for the console chip). */ + status: ConsoleStatus | null; + /** Read /api/status again now (after closing a game). */ + refreshStatus: () => void; + /** Switch to section `id`, opened with `params`. */ + openSection: (id: string, params?: SectionParams) => void; + /** Whether section `id` exists and reads params (e.g. Files at a path). */ + canOpen: (id: string) => boolean; + /** The params this section was opened with, or null. */ + params: SectionParams | null; +} + /** One entry of the Rail. Only implemented sections are listed. */ export interface Section { id: string; icon: LucideIcon; labelKey: string; - render: () => ReactNode; + render: (ctx: SectionContext) => ReactNode; + /** It reads ctx.params, so other sections may open it at a place (Home's Browse USB → Files). */ + acceptsParams?: boolean; } /** A section whose screen is not built yet: its heading only. */ @@ -15,10 +36,22 @@ function Placeholder({ labelKey }: { labelKey: string }) { return

    {t(labelKey)}

    ; } -// Tasks 8–10 replace these renders with the Home, Files and Settings screens. +// Tasks 9–10 replace these renders with the Files and Settings screens. Files +// sets acceptsParams once it opens at ctx.params.path: until then Home hides +// Browse USB. export const SECTIONS: Section[] = [ - { id: "home", icon: House, labelKey: "cw_nav_home", render: () => }, - { id: "files", icon: Folder, labelKey: "cw_nav_files", render: () => }, + { + id: "home", + icon: House, + labelKey: "cw_nav_home", + render: (ctx) => , + }, + { + id: "files", + icon: Folder, + labelKey: "cw_nav_files", + render: () => , + }, { id: "settings", icon: Settings, diff --git a/client/src/console/strings.gen.json b/client/src/console/strings.gen.json index ddd57901..76006387 100644 --- a/client/src/console/strings.gen.json +++ b/client/src/console/strings.gen.json @@ -1,11 +1,61 @@ { "ar": { "cw_actions": "إجراءات", + "cw_dialog_cancel": "إلغاء", "cw_hint_back": "رجوع", "cw_hint_filter": "تصفية", "cw_hint_open": "فتح", "cw_hint_switch_section": "تبديل القسم", "cw_hints_label": "أزرار وحدة التحكم", + "cw_home_browse_usb": "تصفح USB", + "cw_home_cancel_task": "إلغاء", + "cw_home_cancel_task_confirm": "إلغاء المهمة", + "cw_home_close_game": "إغلاق اللعبة", + "cw_home_confirm_cancel_body": "ستتوقف الآن. لا يمكن التراجع عن ذلك.", + "cw_home_confirm_cancel_body_pc": "بدأ حاسوب هذه المهمة. ستتوقف على الحاسوب أيضًا.", + "cw_home_confirm_cancel_title": "إلغاء هذه المهمة؟", + "cw_home_confirm_close_body": "سيضيع التقدم غير المحفوظ في اللعبة.", + "cw_home_confirm_close_title": "إغلاق {name}؟", + "cw_home_confirm_rest_body": "تنقطع هذه الصفحة حتى يستيقظ الجهاز.", + "cw_home_confirm_rest_title": "وضع الجهاز في وضع الراحة؟", + "cw_home_confirm_restart_body": "تتوقف الألعاب والمهام الجارية. تنقطع هذه الصفحة حتى يعود الجهاز.", + "cw_home_confirm_restart_title": "إعادة تشغيل الجهاز؟", + "cw_home_err_busy": "الجهاز مشغول. حاول مرة أخرى بعد قليل.", + "cw_home_err_failed": "لم ينجح ذلك ({code}).", + "cw_home_err_gone": "انتهت هذه المهمة بالفعل.", + "cw_home_err_load_storage": "تعذّرت قراءة المحركات.", + "cw_home_err_load_tasks": "تعذّرت قراءة قائمة المهام.", + "cw_home_err_offline": "لم يستجب الجهاز. حاول مرة أخرى.", + "cw_home_free_of": "{free} متاحة من {total}", + "cw_home_keep_task": "متابعة", + "cw_home_kind_copy": "نسخ", + "cw_home_kind_download": "تنزيل", + "cw_home_kind_op": "عملية ملفات", + "cw_home_kind_other": "مهمة", + "cw_home_kind_upload": "رفع", + "cw_home_loading": "جارٍ التحميل…", + "cw_home_no_game": "لا توجد لعبة قيد التشغيل.", + "cw_home_no_tasks": "لا توجد مهام حاليًا.", + "cw_home_now_running": "قيد التشغيل الآن", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} من {total}", + "cw_home_progress_files": "{done} من {total} ملفات", + "cw_home_quick": "إجراءات سريعة", + "cw_home_rest": "وضع الراحة", + "cw_home_rest_sent": "ينتقل الجهاز إلى وضع الراحة.", + "cw_home_restart": "إعادة التشغيل", + "cw_home_restart_sent": "يُعاد تشغيل الجهاز. أعد تحميل هذه الصفحة عند عودته.", + "cw_home_state_done": "اكتملت", + "cw_home_state_failed": "فشلت", + "cw_home_state_running": "قيد التشغيل", + "cw_home_storage": "التخزين", + "cw_home_tasks": "المهام", + "cw_home_vol_ext": "تخزين موسّع", + "cw_home_vol_internal": "التخزين الداخلي", + "cw_home_vol_m2": "تخزين M.2", + "cw_home_vol_readonly": "للقراءة فقط", + "cw_home_vol_usb": "محرك USB", + "cw_home_vol_usb_ext": "تخزين موسّع عبر USB", "cw_nav_files": "الملفات", "cw_nav_home": "الرئيسية", "cw_nav_sections": "الأقسام", @@ -15,15 +65,67 @@ "cw_reload_title": "أُعيد تشغيل مساعد ps5upload", "cw_select": "تحديد", "cw_status_connecting": "جارٍ الاتصال…", - "cw_status_offline": "غير متصل" + "cw_status_offline": "غير متصل", + "cw_task_from_console": "من هذا الجهاز", + "cw_task_from_pc": "من حاسوب" }, "bn": { "cw_actions": "কাজ", + "cw_dialog_cancel": "বাতিল", "cw_hint_back": "পিছনে", "cw_hint_filter": "ফিল্টার", "cw_hint_open": "খুলুন", "cw_hint_switch_section": "বিভাগ বদলান", "cw_hints_label": "কন্ট্রোলারের বোতাম", + "cw_home_browse_usb": "USB ব্রাউজ করুন", + "cw_home_cancel_task": "বাতিল", + "cw_home_cancel_task_confirm": "কাজ বাতিল করুন", + "cw_home_close_game": "গেম বন্ধ করুন", + "cw_home_confirm_cancel_body": "এটি এখনই থেমে যাবে। এটি পূর্বাবস্থায় ফেরানো যাবে না।", + "cw_home_confirm_cancel_body_pc": "একটি PC এই কাজটি শুরু করেছিল। এটি PC-তেও থেমে যাবে।", + "cw_home_confirm_cancel_title": "এই কাজটি বাতিল করবেন?", + "cw_home_confirm_close_body": "গেমের সেভ না করা অগ্রগতি হারিয়ে যাবে।", + "cw_home_confirm_close_title": "{name} বন্ধ করবেন?", + "cw_home_confirm_rest_body": "কনসোল জেগে না ওঠা পর্যন্ত এই পেজ বিচ্ছিন্ন থাকবে।", + "cw_home_confirm_rest_title": "কনসোলকে রেস্ট মোডে রাখবেন?", + "cw_home_confirm_restart_body": "চলমান গেম ও কাজ থেমে যাবে। কনসোল ফিরে না আসা পর্যন্ত এই পেজ বিচ্ছিন্ন থাকবে।", + "cw_home_confirm_restart_title": "কনসোল রিস্টার্ট করবেন?", + "cw_home_err_busy": "কনসোল ব্যস্ত। একটু পরে আবার চেষ্টা করুন।", + "cw_home_err_failed": "এটি কাজ করেনি ({code})।", + "cw_home_err_gone": "সেই কাজটি আগেই শেষ হয়েছে।", + "cw_home_err_load_storage": "ড্রাইভগুলো পড়া যায়নি।", + "cw_home_err_load_tasks": "কাজের তালিকা পড়া যায়নি।", + "cw_home_err_offline": "কনসোল সাড়া দেয়নি। আবার চেষ্টা করুন।", + "cw_home_free_of": "{total}-এর মধ্যে {free} খালি", + "cw_home_keep_task": "চলতে দিন", + "cw_home_kind_copy": "কপি", + "cw_home_kind_download": "ডাউনলোড", + "cw_home_kind_op": "ফাইল অপারেশন", + "cw_home_kind_other": "কাজ", + "cw_home_kind_upload": "আপলোড", + "cw_home_loading": "লোড হচ্ছে…", + "cw_home_no_game": "কোনো গেম চলছে না।", + "cw_home_no_tasks": "এখন কোনো কাজ নেই।", + "cw_home_now_running": "এখন চলছে", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{total}-এর মধ্যে {done}", + "cw_home_progress_files": "{total}টির মধ্যে {done}টি ফাইল", + "cw_home_quick": "দ্রুত কাজ", + "cw_home_rest": "রেস্ট মোড", + "cw_home_rest_sent": "কনসোল রেস্ট মোডে যাচ্ছে।", + "cw_home_restart": "রিস্টার্ট", + "cw_home_restart_sent": "কনসোল রিস্টার্ট হচ্ছে। ফিরে এলে এই পেজটি আবার লোড করুন।", + "cw_home_state_done": "সম্পন্ন", + "cw_home_state_failed": "ব্যর্থ", + "cw_home_state_running": "চলছে", + "cw_home_storage": "স্টোরেজ", + "cw_home_tasks": "কাজ", + "cw_home_vol_ext": "এক্সটেন্ডেড স্টোরেজ", + "cw_home_vol_internal": "অভ্যন্তরীণ স্টোরেজ", + "cw_home_vol_m2": "M.2 স্টোরেজ", + "cw_home_vol_readonly": "শুধু পড়া যায়", + "cw_home_vol_usb": "USB ড্রাইভ", + "cw_home_vol_usb_ext": "USB এক্সটেন্ডেড স্টোরেজ", "cw_nav_files": "ফাইল", "cw_nav_home": "হোম", "cw_nav_sections": "বিভাগ", @@ -33,15 +135,67 @@ "cw_reload_title": "ps5upload সাহায্যকারী আবার চালু হয়েছে", "cw_select": "বাছাই করুন", "cw_status_connecting": "সংযোগ হচ্ছে…", - "cw_status_offline": "সংযুক্ত নয়" + "cw_status_offline": "সংযুক্ত নয়", + "cw_task_from_console": "এই কনসোল থেকে", + "cw_task_from_pc": "PC থেকে" }, "de": { "cw_actions": "Aktionen", + "cw_dialog_cancel": "Abbrechen", "cw_hint_back": "Zurück", "cw_hint_filter": "Filter", "cw_hint_open": "Öffnen", "cw_hint_switch_section": "Bereich wechseln", "cw_hints_label": "Controller-Tasten", + "cw_home_browse_usb": "USB durchsuchen", + "cw_home_cancel_task": "Abbrechen", + "cw_home_cancel_task_confirm": "Aufgabe abbrechen", + "cw_home_close_game": "Spiel schließen", + "cw_home_confirm_cancel_body": "Sie stoppt sofort. Das lässt sich nicht rückgängig machen.", + "cw_home_confirm_cancel_body_pc": "Ein PC hat diese Aufgabe gestartet. Sie stoppt auch auf dem PC.", + "cw_home_confirm_cancel_title": "Diese Aufgabe abbrechen?", + "cw_home_confirm_close_body": "Nicht gespeicherter Spielfortschritt geht verloren.", + "cw_home_confirm_close_title": "{name} schließen?", + "cw_home_confirm_rest_body": "Diese Seite ist getrennt, bis die Konsole aufwacht.", + "cw_home_confirm_rest_title": "Konsole in den Ruhemodus versetzen?", + "cw_home_confirm_restart_body": "Laufende Spiele und Aufgaben werden beendet. Diese Seite ist getrennt, bis die Konsole wieder da ist.", + "cw_home_confirm_restart_title": "Konsole neu starten?", + "cw_home_err_busy": "Die Konsole ist beschäftigt. Versuche es gleich noch einmal.", + "cw_home_err_failed": "Das hat nicht funktioniert ({code}).", + "cw_home_err_gone": "Diese Aufgabe ist bereits beendet.", + "cw_home_err_load_storage": "Die Laufwerke konnten nicht gelesen werden.", + "cw_home_err_load_tasks": "Die Aufgabenliste konnte nicht gelesen werden.", + "cw_home_err_offline": "Die Konsole hat nicht geantwortet. Versuche es erneut.", + "cw_home_free_of": "{free} frei von {total}", + "cw_home_keep_task": "Weiterlaufen lassen", + "cw_home_kind_copy": "Kopieren", + "cw_home_kind_download": "Herunterladen", + "cw_home_kind_op": "Dateivorgang", + "cw_home_kind_other": "Aufgabe", + "cw_home_kind_upload": "Hochladen", + "cw_home_loading": "Wird geladen…", + "cw_home_no_game": "Es läuft kein Spiel.", + "cw_home_no_tasks": "Gerade keine Aufgaben.", + "cw_home_now_running": "Läuft gerade", + "cw_home_percent": "{n} %", + "cw_home_progress_bytes": "{done} von {total}", + "cw_home_progress_files": "{done} von {total} Dateien", + "cw_home_quick": "Schnellaktionen", + "cw_home_rest": "Ruhemodus", + "cw_home_rest_sent": "Die Konsole wechselt in den Ruhemodus.", + "cw_home_restart": "Neu starten", + "cw_home_restart_sent": "Die Konsole startet neu. Lade diese Seite neu, sobald sie wieder da ist.", + "cw_home_state_done": "Fertig", + "cw_home_state_failed": "Fehlgeschlagen", + "cw_home_state_running": "Läuft", + "cw_home_storage": "Speicher", + "cw_home_tasks": "Aufgaben", + "cw_home_vol_ext": "Erweiterungsspeicher", + "cw_home_vol_internal": "Interner Speicher", + "cw_home_vol_m2": "M.2-Speicher", + "cw_home_vol_readonly": "Schreibgeschützt", + "cw_home_vol_usb": "USB-Laufwerk", + "cw_home_vol_usb_ext": "USB-Erweiterungsspeicher", "cw_nav_files": "Dateien", "cw_nav_home": "Start", "cw_nav_sections": "Bereiche", @@ -51,15 +205,67 @@ "cw_reload_title": "Der ps5upload-Helfer wurde neu gestartet", "cw_select": "Auswählen", "cw_status_connecting": "Verbinde…", - "cw_status_offline": "Nicht verbunden" + "cw_status_offline": "Nicht verbunden", + "cw_task_from_console": "Von dieser Konsole", + "cw_task_from_pc": "Von einem PC" }, "en": { "cw_actions": "Actions", + "cw_dialog_cancel": "Cancel", "cw_hint_back": "Back", "cw_hint_filter": "Filter", "cw_hint_open": "Open", "cw_hint_switch_section": "Switch section", "cw_hints_label": "Controller buttons", + "cw_home_browse_usb": "Browse USB", + "cw_home_cancel_task": "Cancel", + "cw_home_cancel_task_confirm": "Cancel task", + "cw_home_close_game": "Close game", + "cw_home_confirm_cancel_body": "It stops now. This cannot be undone.", + "cw_home_confirm_cancel_body_pc": "A PC started this task. It stops on the PC too.", + "cw_home_confirm_cancel_title": "Cancel this task?", + "cw_home_confirm_close_body": "Progress you have not saved in the game is lost.", + "cw_home_confirm_close_title": "Close {name}?", + "cw_home_confirm_rest_body": "This page disconnects until the console wakes up.", + "cw_home_confirm_rest_title": "Put the console in rest mode?", + "cw_home_confirm_restart_body": "Running games and tasks stop. This page disconnects until the console is back.", + "cw_home_confirm_restart_title": "Restart the console?", + "cw_home_err_busy": "The console is busy. Try again in a moment.", + "cw_home_err_failed": "That did not work ({code}).", + "cw_home_err_gone": "That task has already ended.", + "cw_home_err_load_storage": "Could not read the drives.", + "cw_home_err_load_tasks": "Could not read the task list.", + "cw_home_err_offline": "The console did not answer. Try again.", + "cw_home_free_of": "{free} free of {total}", + "cw_home_keep_task": "Keep going", + "cw_home_kind_copy": "Copy", + "cw_home_kind_download": "Download", + "cw_home_kind_op": "File operation", + "cw_home_kind_other": "Task", + "cw_home_kind_upload": "Upload", + "cw_home_loading": "Loading…", + "cw_home_no_game": "No game is running.", + "cw_home_no_tasks": "No tasks right now.", + "cw_home_now_running": "Now running", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} of {total}", + "cw_home_progress_files": "{done} of {total} files", + "cw_home_quick": "Quick actions", + "cw_home_rest": "Rest mode", + "cw_home_rest_sent": "The console is going into rest mode.", + "cw_home_restart": "Restart", + "cw_home_restart_sent": "The console is restarting. Reload this page when it is back.", + "cw_home_state_done": "Done", + "cw_home_state_failed": "Failed", + "cw_home_state_running": "Running", + "cw_home_storage": "Storage", + "cw_home_tasks": "Tasks", + "cw_home_vol_ext": "Extended storage", + "cw_home_vol_internal": "Internal storage", + "cw_home_vol_m2": "M.2 storage", + "cw_home_vol_readonly": "Read-only", + "cw_home_vol_usb": "USB drive", + "cw_home_vol_usb_ext": "USB extended storage", "cw_nav_files": "Files", "cw_nav_home": "Home", "cw_nav_sections": "Sections", @@ -69,15 +275,67 @@ "cw_reload_title": "The ps5upload helper restarted", "cw_select": "Select", "cw_status_connecting": "Connecting…", - "cw_status_offline": "Not connected" + "cw_status_offline": "Not connected", + "cw_task_from_console": "From this console", + "cw_task_from_pc": "From a PC" }, "es": { "cw_actions": "Acciones", + "cw_dialog_cancel": "Cancelar", "cw_hint_back": "Atrás", "cw_hint_filter": "Filtrar", "cw_hint_open": "Abrir", "cw_hint_switch_section": "Cambiar de sección", "cw_hints_label": "Botones del mando", + "cw_home_browse_usb": "Explorar USB", + "cw_home_cancel_task": "Cancelar", + "cw_home_cancel_task_confirm": "Cancelar tarea", + "cw_home_close_game": "Cerrar juego", + "cw_home_confirm_cancel_body": "Se detiene ahora. No se puede deshacer.", + "cw_home_confirm_cancel_body_pc": "Un PC inició esta tarea. También se detiene en el PC.", + "cw_home_confirm_cancel_title": "¿Cancelar esta tarea?", + "cw_home_confirm_close_body": "Se perderá el progreso no guardado del juego.", + "cw_home_confirm_close_title": "¿Cerrar {name}?", + "cw_home_confirm_rest_body": "Esta página se desconecta hasta que la consola se active.", + "cw_home_confirm_rest_title": "¿Poner la consola en modo de reposo?", + "cw_home_confirm_restart_body": "Los juegos y tareas en curso se detienen. Esta página se desconecta hasta que la consola vuelva.", + "cw_home_confirm_restart_title": "¿Reiniciar la consola?", + "cw_home_err_busy": "La consola está ocupada. Inténtalo de nuevo en un momento.", + "cw_home_err_failed": "No ha funcionado ({code}).", + "cw_home_err_gone": "Esa tarea ya ha terminado.", + "cw_home_err_load_storage": "No se pudieron leer las unidades.", + "cw_home_err_load_tasks": "No se pudo leer la lista de tareas.", + "cw_home_err_offline": "La consola no respondió. Inténtalo de nuevo.", + "cw_home_free_of": "{free} libres de {total}", + "cw_home_keep_task": "Continuar", + "cw_home_kind_copy": "Copia", + "cw_home_kind_download": "Descarga", + "cw_home_kind_op": "Operación de archivos", + "cw_home_kind_other": "Tarea", + "cw_home_kind_upload": "Subida", + "cw_home_loading": "Cargando…", + "cw_home_no_game": "No hay ningún juego en ejecución.", + "cw_home_no_tasks": "No hay tareas ahora mismo.", + "cw_home_now_running": "En ejecución", + "cw_home_percent": "{n} %", + "cw_home_progress_bytes": "{done} de {total}", + "cw_home_progress_files": "{done} de {total} archivos", + "cw_home_quick": "Acciones rápidas", + "cw_home_rest": "Modo de reposo", + "cw_home_rest_sent": "La consola está entrando en modo de reposo.", + "cw_home_restart": "Reiniciar", + "cw_home_restart_sent": "La consola se está reiniciando. Recarga esta página cuando vuelva.", + "cw_home_state_done": "Hecho", + "cw_home_state_failed": "Error", + "cw_home_state_running": "En curso", + "cw_home_storage": "Almacenamiento", + "cw_home_tasks": "Tareas", + "cw_home_vol_ext": "Almacenamiento ampliado", + "cw_home_vol_internal": "Almacenamiento interno", + "cw_home_vol_m2": "Almacenamiento M.2", + "cw_home_vol_readonly": "Solo lectura", + "cw_home_vol_usb": "Unidad USB", + "cw_home_vol_usb_ext": "Almacenamiento ampliado USB", "cw_nav_files": "Archivos", "cw_nav_home": "Inicio", "cw_nav_sections": "Secciones", @@ -87,15 +345,67 @@ "cw_reload_title": "El asistente de ps5upload se reinició", "cw_select": "Seleccionar", "cw_status_connecting": "Conectando…", - "cw_status_offline": "Sin conexión" + "cw_status_offline": "Sin conexión", + "cw_task_from_console": "Desde esta consola", + "cw_task_from_pc": "Desde un PC" }, "fa": { "cw_actions": "کارها", + "cw_dialog_cancel": "لغو", "cw_hint_back": "بازگشت", "cw_hint_filter": "فیلتر", "cw_hint_open": "باز کردن", "cw_hint_switch_section": "تغییر بخش", "cw_hints_label": "دکمه‌های دسته", + "cw_home_browse_usb": "مرور USB", + "cw_home_cancel_task": "لغو", + "cw_home_cancel_task_confirm": "لغو کار", + "cw_home_close_game": "بستن بازی", + "cw_home_confirm_cancel_body": "همین حالا متوقف می‌شود. این کار برگشت‌پذیر نیست.", + "cw_home_confirm_cancel_body_pc": "این کار را یک رایانه شروع کرده است. روی رایانه هم متوقف می‌شود.", + "cw_home_confirm_cancel_title": "این کار لغو شود؟", + "cw_home_confirm_close_body": "پیشرفت ذخیره‌نشده در بازی از بین می‌رود.", + "cw_home_confirm_close_title": "{name} بسته شود؟", + "cw_home_confirm_rest_body": "این صفحه تا بیدار شدن کنسول قطع می‌شود.", + "cw_home_confirm_rest_title": "کنسول به حالت استراحت برود؟", + "cw_home_confirm_restart_body": "بازی‌ها و کارهای در حال اجرا متوقف می‌شوند. این صفحه تا برگشتن کنسول قطع می‌شود.", + "cw_home_confirm_restart_title": "کنسول دوباره راه‌اندازی شود؟", + "cw_home_err_busy": "کنسول مشغول است. کمی بعد دوباره تلاش کنید.", + "cw_home_err_failed": "انجام نشد ({code}).", + "cw_home_err_gone": "این کار قبلاً تمام شده است.", + "cw_home_err_load_storage": "درایوها خوانده نشدند.", + "cw_home_err_load_tasks": "فهرست کارها خوانده نشد.", + "cw_home_err_offline": "کنسول پاسخ نداد. دوباره تلاش کنید.", + "cw_home_free_of": "{free} آزاد از {total}", + "cw_home_keep_task": "ادامه بده", + "cw_home_kind_copy": "کپی", + "cw_home_kind_download": "بارگیری", + "cw_home_kind_op": "عملیات فایل", + "cw_home_kind_other": "کار", + "cw_home_kind_upload": "بارگذاری", + "cw_home_loading": "در حال بارگذاری…", + "cw_home_no_game": "هیچ بازی‌ای در حال اجرا نیست.", + "cw_home_no_tasks": "در حال حاضر کاری نیست.", + "cw_home_now_running": "در حال اجرا", + "cw_home_percent": "{n}٪", + "cw_home_progress_bytes": "{done} از {total}", + "cw_home_progress_files": "{done} از {total} فایل", + "cw_home_quick": "اقدامات سریع", + "cw_home_rest": "حالت استراحت", + "cw_home_rest_sent": "کنسول به حالت استراحت می‌رود.", + "cw_home_restart": "راه‌اندازی مجدد", + "cw_home_restart_sent": "کنسول در حال راه‌اندازی مجدد است. وقتی برگشت این صفحه را دوباره بارگذاری کنید.", + "cw_home_state_done": "انجام شد", + "cw_home_state_failed": "ناموفق", + "cw_home_state_running": "در حال اجرا", + "cw_home_storage": "حافظه", + "cw_home_tasks": "کارها", + "cw_home_vol_ext": "حافظه توسعه‌یافته", + "cw_home_vol_internal": "حافظه داخلی", + "cw_home_vol_m2": "حافظه M.2", + "cw_home_vol_readonly": "فقط‌خواندنی", + "cw_home_vol_usb": "درایو USB", + "cw_home_vol_usb_ext": "حافظه توسعه‌یافته USB", "cw_nav_files": "فایل‌ها", "cw_nav_home": "خانه", "cw_nav_sections": "بخش‌ها", @@ -105,15 +415,67 @@ "cw_reload_title": "راهنمای ps5upload دوباره راه‌اندازی شد", "cw_select": "انتخاب", "cw_status_connecting": "در حال اتصال…", - "cw_status_offline": "متصل نیست" + "cw_status_offline": "متصل نیست", + "cw_task_from_console": "از این کنسول", + "cw_task_from_pc": "از رایانه" }, "fr": { "cw_actions": "Actions", + "cw_dialog_cancel": "Annuler", "cw_hint_back": "Retour", "cw_hint_filter": "Filtrer", "cw_hint_open": "Ouvrir", "cw_hint_switch_section": "Changer de section", "cw_hints_label": "Boutons de la manette", + "cw_home_browse_usb": "Parcourir l'USB", + "cw_home_cancel_task": "Annuler", + "cw_home_cancel_task_confirm": "Annuler la tâche", + "cw_home_close_game": "Fermer le jeu", + "cw_home_confirm_cancel_body": "Elle s'arrête maintenant. Cette action est irréversible.", + "cw_home_confirm_cancel_body_pc": "Un PC a lancé cette tâche. Elle s'arrête aussi sur le PC.", + "cw_home_confirm_cancel_title": "Annuler cette tâche ?", + "cw_home_confirm_close_body": "La progression non sauvegardée du jeu sera perdue.", + "cw_home_confirm_close_title": "Fermer {name} ?", + "cw_home_confirm_rest_body": "Cette page est déconnectée jusqu'au réveil de la console.", + "cw_home_confirm_rest_title": "Mettre la console en mode repos ?", + "cw_home_confirm_restart_body": "Les jeux et tâches en cours s'arrêtent. Cette page est déconnectée jusqu'au retour de la console.", + "cw_home_confirm_restart_title": "Redémarrer la console ?", + "cw_home_err_busy": "La console est occupée. Réessayez dans un instant.", + "cw_home_err_failed": "Cela n'a pas fonctionné ({code}).", + "cw_home_err_gone": "Cette tâche est déjà terminée.", + "cw_home_err_load_storage": "Impossible de lire les disques.", + "cw_home_err_load_tasks": "Impossible de lire la liste des tâches.", + "cw_home_err_offline": "La console n'a pas répondu. Réessayez.", + "cw_home_free_of": "{free} libres sur {total}", + "cw_home_keep_task": "Continuer", + "cw_home_kind_copy": "Copie", + "cw_home_kind_download": "Téléchargement", + "cw_home_kind_op": "Opération sur les fichiers", + "cw_home_kind_other": "Tâche", + "cw_home_kind_upload": "Envoi", + "cw_home_loading": "Chargement…", + "cw_home_no_game": "Aucun jeu en cours.", + "cw_home_no_tasks": "Aucune tâche pour le moment.", + "cw_home_now_running": "En cours d'exécution", + "cw_home_percent": "{n} %", + "cw_home_progress_bytes": "{done} sur {total}", + "cw_home_progress_files": "{done} fichiers sur {total}", + "cw_home_quick": "Actions rapides", + "cw_home_rest": "Mode repos", + "cw_home_rest_sent": "La console passe en mode repos.", + "cw_home_restart": "Redémarrer", + "cw_home_restart_sent": "La console redémarre. Rechargez cette page quand elle sera revenue.", + "cw_home_state_done": "Terminé", + "cw_home_state_failed": "Échec", + "cw_home_state_running": "En cours", + "cw_home_storage": "Stockage", + "cw_home_tasks": "Tâches", + "cw_home_vol_ext": "Stockage étendu", + "cw_home_vol_internal": "Stockage interne", + "cw_home_vol_m2": "Stockage M.2", + "cw_home_vol_readonly": "Lecture seule", + "cw_home_vol_usb": "Clé USB", + "cw_home_vol_usb_ext": "Stockage étendu USB", "cw_nav_files": "Fichiers", "cw_nav_home": "Accueil", "cw_nav_sections": "Sections", @@ -123,15 +485,67 @@ "cw_reload_title": "L'assistant ps5upload a redémarré", "cw_select": "Sélectionner", "cw_status_connecting": "Connexion…", - "cw_status_offline": "Non connecté" + "cw_status_offline": "Non connecté", + "cw_task_from_console": "Depuis cette console", + "cw_task_from_pc": "Depuis un PC" }, "hi": { "cw_actions": "कार्य", + "cw_dialog_cancel": "रद्द करें", "cw_hint_back": "वापस", "cw_hint_filter": "फ़िल्टर", "cw_hint_open": "खोलें", "cw_hint_switch_section": "अनुभाग बदलें", "cw_hints_label": "कंट्रोलर के बटन", + "cw_home_browse_usb": "USB ब्राउज़ करें", + "cw_home_cancel_task": "रद्द करें", + "cw_home_cancel_task_confirm": "कार्य रद्द करें", + "cw_home_close_game": "गेम बंद करें", + "cw_home_confirm_cancel_body": "यह अभी रुक जाएगा। इसे पूर्ववत नहीं किया जा सकता।", + "cw_home_confirm_cancel_body_pc": "यह कार्य एक PC ने शुरू किया था। यह PC पर भी रुक जाएगा।", + "cw_home_confirm_cancel_title": "यह कार्य रद्द करें?", + "cw_home_confirm_close_body": "गेम की बिना सहेजी प्रगति खो जाएगी।", + "cw_home_confirm_close_title": "{name} बंद करें?", + "cw_home_confirm_rest_body": "कंसोल के जागने तक यह पेज डिस्कनेक्ट रहेगा।", + "cw_home_confirm_rest_title": "कंसोल को रेस्ट मोड में डालें?", + "cw_home_confirm_restart_body": "चल रहे गेम और कार्य रुक जाएंगे। कंसोल के वापस आने तक यह पेज डिस्कनेक्ट रहेगा।", + "cw_home_confirm_restart_title": "कंसोल फिर से शुरू करें?", + "cw_home_err_busy": "कंसोल व्यस्त है। थोड़ी देर बाद फिर से कोशिश करें।", + "cw_home_err_failed": "यह काम नहीं किया ({code})।", + "cw_home_err_gone": "वह कार्य पहले ही खत्म हो चुका है।", + "cw_home_err_load_storage": "ड्राइव पढ़ी नहीं जा सकीं।", + "cw_home_err_load_tasks": "कार्य सूची पढ़ी नहीं जा सकी।", + "cw_home_err_offline": "कंसोल ने जवाब नहीं दिया। फिर से कोशिश करें।", + "cw_home_free_of": "{total} में से {free} खाली", + "cw_home_keep_task": "चलने दें", + "cw_home_kind_copy": "कॉपी", + "cw_home_kind_download": "डाउनलोड", + "cw_home_kind_op": "फ़ाइल कार्रवाई", + "cw_home_kind_other": "कार्य", + "cw_home_kind_upload": "अपलोड", + "cw_home_loading": "लोड हो रहा है…", + "cw_home_no_game": "कोई गेम नहीं चल रहा है।", + "cw_home_no_tasks": "अभी कोई कार्य नहीं है।", + "cw_home_now_running": "अभी चल रहा है", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{total} में से {done}", + "cw_home_progress_files": "{total} में से {done} फ़ाइलें", + "cw_home_quick": "त्वरित कार्रवाइयाँ", + "cw_home_rest": "रेस्ट मोड", + "cw_home_rest_sent": "कंसोल रेस्ट मोड में जा रहा है।", + "cw_home_restart": "फिर से शुरू करें", + "cw_home_restart_sent": "कंसोल फिर से शुरू हो रहा है। वापस आने पर यह पेज फिर से लोड करें।", + "cw_home_state_done": "पूरा हुआ", + "cw_home_state_failed": "विफल", + "cw_home_state_running": "चल रहा है", + "cw_home_storage": "स्टोरेज", + "cw_home_tasks": "कार्य", + "cw_home_vol_ext": "विस्तारित स्टोरेज", + "cw_home_vol_internal": "आंतरिक स्टोरेज", + "cw_home_vol_m2": "M.2 स्टोरेज", + "cw_home_vol_readonly": "केवल पढ़ने योग्य", + "cw_home_vol_usb": "USB ड्राइव", + "cw_home_vol_usb_ext": "USB विस्तारित स्टोरेज", "cw_nav_files": "फ़ाइलें", "cw_nav_home": "होम", "cw_nav_sections": "अनुभाग", @@ -141,15 +555,67 @@ "cw_reload_title": "ps5upload हेल्पर फिर से शुरू हुआ", "cw_select": "चुनें", "cw_status_connecting": "कनेक्ट हो रहा है…", - "cw_status_offline": "कनेक्ट नहीं है" + "cw_status_offline": "कनेक्ट नहीं है", + "cw_task_from_console": "इस कंसोल से", + "cw_task_from_pc": "PC से" }, "hu": { "cw_actions": "Műveletek", + "cw_dialog_cancel": "Mégse", "cw_hint_back": "Vissza", "cw_hint_filter": "Szűrés", "cw_hint_open": "Megnyitás", "cw_hint_switch_section": "Rész váltása", "cw_hints_label": "Kontroller gombjai", + "cw_home_browse_usb": "USB tallózása", + "cw_home_cancel_task": "Megszakítás", + "cw_home_cancel_task_confirm": "Feladat megszakítása", + "cw_home_close_game": "Játék bezárása", + "cw_home_confirm_cancel_body": "Azonnal leáll. Ez nem vonható vissza.", + "cw_home_confirm_cancel_body_pc": "Ezt a feladatot egy PC indította. A PC-n is leáll.", + "cw_home_confirm_cancel_title": "Megszakítod ezt a feladatot?", + "cw_home_confirm_close_body": "A játékban el nem mentett haladás elvész.", + "cw_home_confirm_close_title": "Bezárod: {name}?", + "cw_home_confirm_rest_body": "Ez az oldal a konzol felébredéséig nem kapcsolódik.", + "cw_home_confirm_rest_title": "Nyugalmi módba teszed a konzolt?", + "cw_home_confirm_restart_body": "A futó játékok és feladatok leállnak. Ez az oldal a konzol visszatéréséig nem kapcsolódik.", + "cw_home_confirm_restart_title": "Újraindítod a konzolt?", + "cw_home_err_busy": "A konzol foglalt. Próbáld újra egy pillanat múlva.", + "cw_home_err_failed": "Ez nem sikerült ({code}).", + "cw_home_err_gone": "Ez a feladat már befejeződött.", + "cw_home_err_load_storage": "Nem sikerült beolvasni a meghajtókat.", + "cw_home_err_load_tasks": "Nem sikerült beolvasni a feladatlistát.", + "cw_home_err_offline": "A konzol nem válaszolt. Próbáld újra.", + "cw_home_free_of": "{free} szabad / {total}", + "cw_home_keep_task": "Folytatás", + "cw_home_kind_copy": "Másolás", + "cw_home_kind_download": "Letöltés", + "cw_home_kind_op": "Fájlművelet", + "cw_home_kind_other": "Feladat", + "cw_home_kind_upload": "Feltöltés", + "cw_home_loading": "Betöltés…", + "cw_home_no_game": "Nem fut játék.", + "cw_home_no_tasks": "Most nincs feladat.", + "cw_home_now_running": "Most fut", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} fájl", + "cw_home_quick": "Gyorsműveletek", + "cw_home_rest": "Nyugalmi mód", + "cw_home_rest_sent": "A konzol nyugalmi módba lép.", + "cw_home_restart": "Újraindítás", + "cw_home_restart_sent": "A konzol újraindul. Töltsd újra ezt az oldalt, ha újra elérhető.", + "cw_home_state_done": "Kész", + "cw_home_state_failed": "Sikertelen", + "cw_home_state_running": "Folyamatban", + "cw_home_storage": "Tárhely", + "cw_home_tasks": "Feladatok", + "cw_home_vol_ext": "Bővített tárhely", + "cw_home_vol_internal": "Belső tárhely", + "cw_home_vol_m2": "M.2 tárhely", + "cw_home_vol_readonly": "Csak olvasható", + "cw_home_vol_usb": "USB-meghajtó", + "cw_home_vol_usb_ext": "USB bővített tárhely", "cw_nav_files": "Fájlok", "cw_nav_home": "Kezdőlap", "cw_nav_sections": "Részek", @@ -159,15 +625,67 @@ "cw_reload_title": "A ps5upload segédprogram újraindult", "cw_select": "Kijelölés", "cw_status_connecting": "Kapcsolódás…", - "cw_status_offline": "Nincs kapcsolat" + "cw_status_offline": "Nincs kapcsolat", + "cw_task_from_console": "Erről a konzolról", + "cw_task_from_pc": "Egy PC-ről" }, "id": { "cw_actions": "Tindakan", + "cw_dialog_cancel": "Batal", "cw_hint_back": "Kembali", "cw_hint_filter": "Filter", "cw_hint_open": "Buka", "cw_hint_switch_section": "Ganti bagian", "cw_hints_label": "Tombol kontroler", + "cw_home_browse_usb": "Jelajahi USB", + "cw_home_cancel_task": "Batalkan", + "cw_home_cancel_task_confirm": "Batalkan tugas", + "cw_home_close_game": "Tutup game", + "cw_home_confirm_cancel_body": "Tugas berhenti sekarang. Ini tidak bisa dibatalkan.", + "cw_home_confirm_cancel_body_pc": "Tugas ini dimulai dari PC. Tugas juga berhenti di PC.", + "cw_home_confirm_cancel_title": "Batalkan tugas ini?", + "cw_home_confirm_close_body": "Progres game yang belum disimpan akan hilang.", + "cw_home_confirm_close_title": "Tutup {name}?", + "cw_home_confirm_rest_body": "Halaman ini terputus sampai konsol bangun.", + "cw_home_confirm_rest_title": "Masukkan konsol ke mode istirahat?", + "cw_home_confirm_restart_body": "Game dan tugas yang berjalan akan berhenti. Halaman ini terputus sampai konsol kembali.", + "cw_home_confirm_restart_title": "Mulai ulang konsol?", + "cw_home_err_busy": "Konsol sedang sibuk. Coba lagi sebentar lagi.", + "cw_home_err_failed": "Itu tidak berhasil ({code}).", + "cw_home_err_gone": "Tugas itu sudah berakhir.", + "cw_home_err_load_storage": "Tidak dapat membaca drive.", + "cw_home_err_load_tasks": "Tidak dapat membaca daftar tugas.", + "cw_home_err_offline": "Konsol tidak menjawab. Coba lagi.", + "cw_home_free_of": "{free} kosong dari {total}", + "cw_home_keep_task": "Lanjutkan", + "cw_home_kind_copy": "Salin", + "cw_home_kind_download": "Unduh", + "cw_home_kind_op": "Operasi file", + "cw_home_kind_other": "Tugas", + "cw_home_kind_upload": "Unggah", + "cw_home_loading": "Memuat…", + "cw_home_no_game": "Tidak ada game yang berjalan.", + "cw_home_no_tasks": "Tidak ada tugas saat ini.", + "cw_home_now_running": "Sedang berjalan", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} dari {total}", + "cw_home_progress_files": "{done} dari {total} file", + "cw_home_quick": "Tindakan cepat", + "cw_home_rest": "Mode istirahat", + "cw_home_rest_sent": "Konsol masuk ke mode istirahat.", + "cw_home_restart": "Mulai ulang", + "cw_home_restart_sent": "Konsol sedang memulai ulang. Muat ulang halaman ini setelah konsol kembali.", + "cw_home_state_done": "Selesai", + "cw_home_state_failed": "Gagal", + "cw_home_state_running": "Berjalan", + "cw_home_storage": "Penyimpanan", + "cw_home_tasks": "Tugas", + "cw_home_vol_ext": "Penyimpanan tambahan", + "cw_home_vol_internal": "Penyimpanan internal", + "cw_home_vol_m2": "Penyimpanan M.2", + "cw_home_vol_readonly": "Hanya baca", + "cw_home_vol_usb": "Drive USB", + "cw_home_vol_usb_ext": "Penyimpanan tambahan USB", "cw_nav_files": "File", "cw_nav_home": "Beranda", "cw_nav_sections": "Bagian", @@ -177,15 +695,67 @@ "cw_reload_title": "Pembantu ps5upload dimulai ulang", "cw_select": "Pilih", "cw_status_connecting": "Menghubungkan…", - "cw_status_offline": "Tidak terhubung" + "cw_status_offline": "Tidak terhubung", + "cw_task_from_console": "Dari konsol ini", + "cw_task_from_pc": "Dari PC" }, "it": { "cw_actions": "Azioni", + "cw_dialog_cancel": "Annulla", "cw_hint_back": "Indietro", "cw_hint_filter": "Filtra", "cw_hint_open": "Apri", "cw_hint_switch_section": "Cambia sezione", "cw_hints_label": "Tasti del controller", + "cw_home_browse_usb": "Sfoglia USB", + "cw_home_cancel_task": "Annulla", + "cw_home_cancel_task_confirm": "Annulla attività", + "cw_home_close_game": "Chiudi gioco", + "cw_home_confirm_cancel_body": "Si interrompe subito. L'operazione non può essere annullata.", + "cw_home_confirm_cancel_body_pc": "Questa attività è stata avviata da un PC. Si interrompe anche sul PC.", + "cw_home_confirm_cancel_title": "Annullare questa attività?", + "cw_home_confirm_close_body": "I progressi di gioco non salvati andranno persi.", + "cw_home_confirm_close_title": "Chiudere {name}?", + "cw_home_confirm_rest_body": "Questa pagina resta disconnessa finché la console non si riattiva.", + "cw_home_confirm_rest_title": "Mettere la console in modalità riposo?", + "cw_home_confirm_restart_body": "Giochi e attività in corso si interrompono. Questa pagina resta disconnessa finché la console non torna disponibile.", + "cw_home_confirm_restart_title": "Riavviare la console?", + "cw_home_err_busy": "La console è occupata. Riprova tra un momento.", + "cw_home_err_failed": "Non ha funzionato ({code}).", + "cw_home_err_gone": "Quell'attività è già terminata.", + "cw_home_err_load_storage": "Impossibile leggere le unità.", + "cw_home_err_load_tasks": "Impossibile leggere l'elenco delle attività.", + "cw_home_err_offline": "La console non ha risposto. Riprova.", + "cw_home_free_of": "{free} liberi su {total}", + "cw_home_keep_task": "Continua", + "cw_home_kind_copy": "Copia", + "cw_home_kind_download": "Download", + "cw_home_kind_op": "Operazione sui file", + "cw_home_kind_other": "Attività", + "cw_home_kind_upload": "Caricamento", + "cw_home_loading": "Caricamento…", + "cw_home_no_game": "Nessun gioco in esecuzione.", + "cw_home_no_tasks": "Nessuna attività al momento.", + "cw_home_now_running": "In esecuzione", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} di {total}", + "cw_home_progress_files": "{done} di {total} file", + "cw_home_quick": "Azioni rapide", + "cw_home_rest": "Modalità riposo", + "cw_home_rest_sent": "La console sta entrando in modalità riposo.", + "cw_home_restart": "Riavvia", + "cw_home_restart_sent": "La console si sta riavviando. Ricarica questa pagina quando torna disponibile.", + "cw_home_state_done": "Completata", + "cw_home_state_failed": "Non riuscita", + "cw_home_state_running": "In corso", + "cw_home_storage": "Archiviazione", + "cw_home_tasks": "Attività", + "cw_home_vol_ext": "Memoria estesa", + "cw_home_vol_internal": "Memoria interna", + "cw_home_vol_m2": "Memoria M.2", + "cw_home_vol_readonly": "Sola lettura", + "cw_home_vol_usb": "Unità USB", + "cw_home_vol_usb_ext": "Memoria estesa USB", "cw_nav_files": "File", "cw_nav_home": "Home", "cw_nav_sections": "Sezioni", @@ -195,15 +765,67 @@ "cw_reload_title": "L'helper di ps5upload si è riavviato", "cw_select": "Seleziona", "cw_status_connecting": "Connessione…", - "cw_status_offline": "Non connesso" + "cw_status_offline": "Non connesso", + "cw_task_from_console": "Da questa console", + "cw_task_from_pc": "Da un PC" }, "ja": { "cw_actions": "操作", + "cw_dialog_cancel": "キャンセル", "cw_hint_back": "戻る", "cw_hint_filter": "絞り込み", "cw_hint_open": "開く", "cw_hint_switch_section": "セクションを切り替え", "cw_hints_label": "コントローラーのボタン", + "cw_home_browse_usb": "USBを参照", + "cw_home_cancel_task": "キャンセル", + "cw_home_cancel_task_confirm": "タスクをキャンセル", + "cw_home_close_game": "ゲームを終了", + "cw_home_confirm_cancel_body": "すぐに停止します。元に戻せません。", + "cw_home_confirm_cancel_body_pc": "このタスクはPCから開始されました。PC側でも停止します。", + "cw_home_confirm_cancel_title": "このタスクをキャンセルしますか?", + "cw_home_confirm_close_body": "ゲーム内の保存していない進行状況は失われます。", + "cw_home_confirm_close_title": "{name} を終了しますか?", + "cw_home_confirm_rest_body": "コンソールが復帰するまで、このページは切断されます。", + "cw_home_confirm_rest_title": "コンソールをレストモードにしますか?", + "cw_home_confirm_restart_body": "実行中のゲームとタスクは停止します。コンソールが戻るまで、このページは切断されます。", + "cw_home_confirm_restart_title": "コンソールを再起動しますか?", + "cw_home_err_busy": "コンソールが処理中です。少ししてからもう一度お試しください。", + "cw_home_err_failed": "うまくいきませんでした({code})。", + "cw_home_err_gone": "そのタスクはすでに終了しています。", + "cw_home_err_load_storage": "ドライブを読み込めませんでした。", + "cw_home_err_load_tasks": "タスク一覧を読み込めませんでした。", + "cw_home_err_offline": "コンソールが応答しませんでした。もう一度お試しください。", + "cw_home_free_of": "空き {free} / {total}", + "cw_home_keep_task": "続ける", + "cw_home_kind_copy": "コピー", + "cw_home_kind_download": "ダウンロード", + "cw_home_kind_op": "ファイル操作", + "cw_home_kind_other": "タスク", + "cw_home_kind_upload": "アップロード", + "cw_home_loading": "読み込み中…", + "cw_home_no_game": "実行中のゲームはありません。", + "cw_home_no_tasks": "現在タスクはありません。", + "cw_home_now_running": "実行中", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} ファイル", + "cw_home_quick": "クイックアクション", + "cw_home_rest": "レストモード", + "cw_home_rest_sent": "コンソールがレストモードに入ります。", + "cw_home_restart": "再起動", + "cw_home_restart_sent": "コンソールを再起動しています。復帰したらこのページを再読み込みしてください。", + "cw_home_state_done": "完了", + "cw_home_state_failed": "失敗", + "cw_home_state_running": "実行中", + "cw_home_storage": "ストレージ", + "cw_home_tasks": "タスク", + "cw_home_vol_ext": "拡張ストレージ", + "cw_home_vol_internal": "本体ストレージ", + "cw_home_vol_m2": "M.2ストレージ", + "cw_home_vol_readonly": "読み取り専用", + "cw_home_vol_usb": "USBドライブ", + "cw_home_vol_usb_ext": "USB拡張ストレージ", "cw_nav_files": "ファイル", "cw_nav_home": "ホーム", "cw_nav_sections": "セクション", @@ -213,15 +835,67 @@ "cw_reload_title": "ps5upload のヘルパーが再起動しました", "cw_select": "選択", "cw_status_connecting": "接続中…", - "cw_status_offline": "未接続" + "cw_status_offline": "未接続", + "cw_task_from_console": "このコンソールから", + "cw_task_from_pc": "PCから" }, "ko": { "cw_actions": "작업", + "cw_dialog_cancel": "취소", "cw_hint_back": "뒤로", "cw_hint_filter": "필터", "cw_hint_open": "열기", "cw_hint_switch_section": "섹션 전환", "cw_hints_label": "컨트롤러 버튼", + "cw_home_browse_usb": "USB 탐색", + "cw_home_cancel_task": "취소", + "cw_home_cancel_task_confirm": "작업 취소", + "cw_home_close_game": "게임 닫기", + "cw_home_confirm_cancel_body": "지금 바로 멈춥니다. 되돌릴 수 없습니다.", + "cw_home_confirm_cancel_body_pc": "PC에서 시작한 작업입니다. PC에서도 멈춥니다.", + "cw_home_confirm_cancel_title": "이 작업을 취소할까요?", + "cw_home_confirm_close_body": "게임에서 저장하지 않은 진행 상황은 사라집니다.", + "cw_home_confirm_close_title": "{name}을(를) 닫을까요?", + "cw_home_confirm_rest_body": "콘솔이 깨어날 때까지 이 페이지는 연결이 끊깁니다.", + "cw_home_confirm_rest_title": "콘솔을 휴식 모드로 전환할까요?", + "cw_home_confirm_restart_body": "실행 중인 게임과 작업이 멈춥니다. 콘솔이 다시 켜질 때까지 이 페이지는 연결이 끊깁니다.", + "cw_home_confirm_restart_title": "콘솔을 다시 시작할까요?", + "cw_home_err_busy": "콘솔이 사용 중입니다. 잠시 후 다시 시도하세요.", + "cw_home_err_failed": "실패했습니다({code}).", + "cw_home_err_gone": "이 작업은 이미 끝났습니다.", + "cw_home_err_load_storage": "드라이브를 읽을 수 없습니다.", + "cw_home_err_load_tasks": "작업 목록을 읽을 수 없습니다.", + "cw_home_err_offline": "콘솔이 응답하지 않았습니다. 다시 시도하세요.", + "cw_home_free_of": "{total} 중 {free} 남음", + "cw_home_keep_task": "계속 진행", + "cw_home_kind_copy": "복사", + "cw_home_kind_download": "다운로드", + "cw_home_kind_op": "파일 작업", + "cw_home_kind_other": "작업", + "cw_home_kind_upload": "업로드", + "cw_home_loading": "불러오는 중…", + "cw_home_no_game": "실행 중인 게임이 없습니다.", + "cw_home_no_tasks": "현재 작업이 없습니다.", + "cw_home_now_running": "실행 중", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total}개 파일", + "cw_home_quick": "빠른 작업", + "cw_home_rest": "휴식 모드", + "cw_home_rest_sent": "콘솔이 휴식 모드로 전환됩니다.", + "cw_home_restart": "다시 시작", + "cw_home_restart_sent": "콘솔을 다시 시작하는 중입니다. 다시 켜지면 이 페이지를 새로 고치세요.", + "cw_home_state_done": "완료", + "cw_home_state_failed": "실패", + "cw_home_state_running": "진행 중", + "cw_home_storage": "저장소", + "cw_home_tasks": "작업", + "cw_home_vol_ext": "확장 저장소", + "cw_home_vol_internal": "내부 저장소", + "cw_home_vol_m2": "M.2 저장소", + "cw_home_vol_readonly": "읽기 전용", + "cw_home_vol_usb": "USB 드라이브", + "cw_home_vol_usb_ext": "USB 확장 저장소", "cw_nav_files": "파일", "cw_nav_home": "홈", "cw_nav_sections": "섹션", @@ -231,15 +905,67 @@ "cw_reload_title": "ps5upload 헬퍼가 다시 시작되었습니다", "cw_select": "선택", "cw_status_connecting": "연결 중…", - "cw_status_offline": "연결되지 않음" + "cw_status_offline": "연결되지 않음", + "cw_task_from_console": "이 콘솔에서", + "cw_task_from_pc": "PC에서" }, "pl": { "cw_actions": "Działania", + "cw_dialog_cancel": "Anuluj", "cw_hint_back": "Wstecz", "cw_hint_filter": "Filtruj", "cw_hint_open": "Otwórz", "cw_hint_switch_section": "Zmień sekcję", "cw_hints_label": "Przyciski kontrolera", + "cw_home_browse_usb": "Przeglądaj USB", + "cw_home_cancel_task": "Anuluj", + "cw_home_cancel_task_confirm": "Anuluj zadanie", + "cw_home_close_game": "Zamknij grę", + "cw_home_confirm_cancel_body": "Zatrzyma się teraz. Tego nie można cofnąć.", + "cw_home_confirm_cancel_body_pc": "To zadanie uruchomił komputer. Zatrzyma się także na komputerze.", + "cw_home_confirm_cancel_title": "Anulować to zadanie?", + "cw_home_confirm_close_body": "Niezapisane postępy w grze zostaną utracone.", + "cw_home_confirm_close_title": "Zamknąć {name}?", + "cw_home_confirm_rest_body": "Ta strona będzie rozłączona, dopóki konsola się nie wybudzi.", + "cw_home_confirm_rest_title": "Przełączyć konsolę w tryb odpoczynku?", + "cw_home_confirm_restart_body": "Uruchomione gry i zadania zostaną zatrzymane. Ta strona będzie rozłączona, dopóki konsola nie wróci.", + "cw_home_confirm_restart_title": "Uruchomić konsolę ponownie?", + "cw_home_err_busy": "Konsola jest zajęta. Spróbuj ponownie za chwilę.", + "cw_home_err_failed": "Nie udało się ({code}).", + "cw_home_err_gone": "To zadanie już się zakończyło.", + "cw_home_err_load_storage": "Nie udało się odczytać dysków.", + "cw_home_err_load_tasks": "Nie udało się odczytać listy zadań.", + "cw_home_err_offline": "Konsola nie odpowiedziała. Spróbuj ponownie.", + "cw_home_free_of": "{free} wolne z {total}", + "cw_home_keep_task": "Kontynuuj", + "cw_home_kind_copy": "Kopiowanie", + "cw_home_kind_download": "Pobieranie", + "cw_home_kind_op": "Operacja na plikach", + "cw_home_kind_other": "Zadanie", + "cw_home_kind_upload": "Wysyłanie", + "cw_home_loading": "Wczytywanie…", + "cw_home_no_game": "Żadna gra nie jest uruchomiona.", + "cw_home_no_tasks": "Brak zadań.", + "cw_home_now_running": "Teraz uruchomione", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} z {total}", + "cw_home_progress_files": "{done} z {total} plików", + "cw_home_quick": "Szybkie akcje", + "cw_home_rest": "Tryb odpoczynku", + "cw_home_rest_sent": "Konsola przechodzi w tryb odpoczynku.", + "cw_home_restart": "Uruchom ponownie", + "cw_home_restart_sent": "Konsola uruchamia się ponownie. Przeładuj tę stronę, gdy wróci.", + "cw_home_state_done": "Gotowe", + "cw_home_state_failed": "Niepowodzenie", + "cw_home_state_running": "W toku", + "cw_home_storage": "Pamięć", + "cw_home_tasks": "Zadania", + "cw_home_vol_ext": "Rozszerzona pamięć", + "cw_home_vol_internal": "Pamięć wewnętrzna", + "cw_home_vol_m2": "Pamięć M.2", + "cw_home_vol_readonly": "Tylko do odczytu", + "cw_home_vol_usb": "Dysk USB", + "cw_home_vol_usb_ext": "Rozszerzona pamięć USB", "cw_nav_files": "Pliki", "cw_nav_home": "Start", "cw_nav_sections": "Sekcje", @@ -249,15 +975,67 @@ "cw_reload_title": "Helper ps5upload uruchomił się ponownie", "cw_select": "Zaznacz", "cw_status_connecting": "Łączenie…", - "cw_status_offline": "Brak połączenia" + "cw_status_offline": "Brak połączenia", + "cw_task_from_console": "Z tej konsoli", + "cw_task_from_pc": "Z komputera" }, "pt-BR": { "cw_actions": "Ações", + "cw_dialog_cancel": "Cancelar", "cw_hint_back": "Voltar", "cw_hint_filter": "Filtrar", "cw_hint_open": "Abrir", "cw_hint_switch_section": "Trocar de seção", "cw_hints_label": "Botões do controle", + "cw_home_browse_usb": "Navegar no USB", + "cw_home_cancel_task": "Cancelar", + "cw_home_cancel_task_confirm": "Cancelar tarefa", + "cw_home_close_game": "Fechar jogo", + "cw_home_confirm_cancel_body": "Ela para agora. Isso não pode ser desfeito.", + "cw_home_confirm_cancel_body_pc": "Um PC iniciou esta tarefa. Ela também para no PC.", + "cw_home_confirm_cancel_title": "Cancelar esta tarefa?", + "cw_home_confirm_close_body": "O progresso não salvo no jogo será perdido.", + "cw_home_confirm_close_title": "Fechar {name}?", + "cw_home_confirm_rest_body": "Esta página fica desconectada até o console despertar.", + "cw_home_confirm_rest_title": "Colocar o console no modo de descanso?", + "cw_home_confirm_restart_body": "Jogos e tarefas em andamento param. Esta página fica desconectada até o console voltar.", + "cw_home_confirm_restart_title": "Reiniciar o console?", + "cw_home_err_busy": "O console está ocupado. Tente novamente em instantes.", + "cw_home_err_failed": "Não deu certo ({code}).", + "cw_home_err_gone": "Essa tarefa já terminou.", + "cw_home_err_load_storage": "Não foi possível ler as unidades.", + "cw_home_err_load_tasks": "Não foi possível ler a lista de tarefas.", + "cw_home_err_offline": "O console não respondeu. Tente novamente.", + "cw_home_free_of": "{free} livres de {total}", + "cw_home_keep_task": "Continuar", + "cw_home_kind_copy": "Cópia", + "cw_home_kind_download": "Download", + "cw_home_kind_op": "Operação de arquivos", + "cw_home_kind_other": "Tarefa", + "cw_home_kind_upload": "Envio", + "cw_home_loading": "Carregando…", + "cw_home_no_game": "Nenhum jogo em execução.", + "cw_home_no_tasks": "Nenhuma tarefa no momento.", + "cw_home_now_running": "Em execução", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} de {total}", + "cw_home_progress_files": "{done} de {total} arquivos", + "cw_home_quick": "Ações rápidas", + "cw_home_rest": "Modo de descanso", + "cw_home_rest_sent": "O console está entrando no modo de descanso.", + "cw_home_restart": "Reiniciar", + "cw_home_restart_sent": "O console está reiniciando. Recarregue esta página quando ele voltar.", + "cw_home_state_done": "Concluída", + "cw_home_state_failed": "Falhou", + "cw_home_state_running": "Em andamento", + "cw_home_storage": "Armazenamento", + "cw_home_tasks": "Tarefas", + "cw_home_vol_ext": "Armazenamento estendido", + "cw_home_vol_internal": "Armazenamento interno", + "cw_home_vol_m2": "Armazenamento M.2", + "cw_home_vol_readonly": "Somente leitura", + "cw_home_vol_usb": "Unidade USB", + "cw_home_vol_usb_ext": "Armazenamento estendido USB", "cw_nav_files": "Arquivos", "cw_nav_home": "Início", "cw_nav_sections": "Seções", @@ -267,15 +1045,67 @@ "cw_reload_title": "O auxiliar do ps5upload reiniciou", "cw_select": "Selecionar", "cw_status_connecting": "Conectando…", - "cw_status_offline": "Não conectado" + "cw_status_offline": "Não conectado", + "cw_task_from_console": "Deste console", + "cw_task_from_pc": "De um PC" }, "ru": { "cw_actions": "Действия", + "cw_dialog_cancel": "Отмена", "cw_hint_back": "Назад", "cw_hint_filter": "Фильтр", "cw_hint_open": "Открыть", "cw_hint_switch_section": "Сменить раздел", "cw_hints_label": "Кнопки геймпада", + "cw_home_browse_usb": "Открыть USB", + "cw_home_cancel_task": "Отменить", + "cw_home_cancel_task_confirm": "Отменить задачу", + "cw_home_close_game": "Закрыть игру", + "cw_home_confirm_cancel_body": "Она остановится сейчас. Это нельзя отменить.", + "cw_home_confirm_cancel_body_pc": "Эту задачу запустил ПК. На ПК она тоже остановится.", + "cw_home_confirm_cancel_title": "Отменить эту задачу?", + "cw_home_confirm_close_body": "Несохранённый прогресс в игре будет потерян.", + "cw_home_confirm_close_title": "Закрыть {name}?", + "cw_home_confirm_rest_body": "Страница будет отключена, пока консоль не проснётся.", + "cw_home_confirm_rest_title": "Перевести консоль в режим покоя?", + "cw_home_confirm_restart_body": "Запущенные игры и задачи остановятся. Страница будет отключена, пока консоль не вернётся.", + "cw_home_confirm_restart_title": "Перезагрузить консоль?", + "cw_home_err_busy": "Консоль занята. Попробуйте чуть позже.", + "cw_home_err_failed": "Не получилось ({code}).", + "cw_home_err_gone": "Эта задача уже завершилась.", + "cw_home_err_load_storage": "Не удалось прочитать накопители.", + "cw_home_err_load_tasks": "Не удалось прочитать список задач.", + "cw_home_err_offline": "Консоль не ответила. Попробуйте ещё раз.", + "cw_home_free_of": "Свободно {free} из {total}", + "cw_home_keep_task": "Продолжить", + "cw_home_kind_copy": "Копирование", + "cw_home_kind_download": "Скачивание", + "cw_home_kind_op": "Операция с файлами", + "cw_home_kind_other": "Задача", + "cw_home_kind_upload": "Загрузка на консоль", + "cw_home_loading": "Загрузка…", + "cw_home_no_game": "Игра не запущена.", + "cw_home_no_tasks": "Сейчас задач нет.", + "cw_home_now_running": "Сейчас запущено", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} из {total}", + "cw_home_progress_files": "{done} из {total} файлов", + "cw_home_quick": "Быстрые действия", + "cw_home_rest": "Режим покоя", + "cw_home_rest_sent": "Консоль переходит в режим покоя.", + "cw_home_restart": "Перезагрузить", + "cw_home_restart_sent": "Консоль перезагружается. Обновите эту страницу, когда она снова будет доступна.", + "cw_home_state_done": "Готово", + "cw_home_state_failed": "Ошибка", + "cw_home_state_running": "Выполняется", + "cw_home_storage": "Хранилище", + "cw_home_tasks": "Задачи", + "cw_home_vol_ext": "Расширенное хранилище", + "cw_home_vol_internal": "Внутреннее хранилище", + "cw_home_vol_m2": "Хранилище M.2", + "cw_home_vol_readonly": "Только чтение", + "cw_home_vol_usb": "USB-накопитель", + "cw_home_vol_usb_ext": "Расширенное хранилище USB", "cw_nav_files": "Файлы", "cw_nav_home": "Главная", "cw_nav_sections": "Разделы", @@ -285,15 +1115,67 @@ "cw_reload_title": "Помощник ps5upload перезапустился", "cw_select": "Выбрать", "cw_status_connecting": "Подключение…", - "cw_status_offline": "Нет подключения" + "cw_status_offline": "Нет подключения", + "cw_task_from_console": "С этой консоли", + "cw_task_from_pc": "С ПК" }, "th": { "cw_actions": "การทำงาน", + "cw_dialog_cancel": "ยกเลิก", "cw_hint_back": "กลับ", "cw_hint_filter": "ตัวกรอง", "cw_hint_open": "เปิด", "cw_hint_switch_section": "สลับส่วน", "cw_hints_label": "ปุ่มคอนโทรลเลอร์", + "cw_home_browse_usb": "เรียกดู USB", + "cw_home_cancel_task": "ยกเลิก", + "cw_home_cancel_task_confirm": "ยกเลิกงาน", + "cw_home_close_game": "ปิดเกม", + "cw_home_confirm_cancel_body": "งานจะหยุดทันทีและย้อนกลับไม่ได้", + "cw_home_confirm_cancel_body_pc": "งานนี้เริ่มจาก PC และจะหยุดบน PC ด้วย", + "cw_home_confirm_cancel_title": "ยกเลิกงานนี้ไหม", + "cw_home_confirm_close_body": "ความคืบหน้าในเกมที่ยังไม่ได้บันทึกจะหายไป", + "cw_home_confirm_close_title": "ปิด {name} ไหม", + "cw_home_confirm_rest_body": "หน้านี้จะขาดการเชื่อมต่อจนกว่าคอนโซลจะตื่น", + "cw_home_confirm_rest_title": "ให้คอนโซลเข้าสู่โหมดพักไหม", + "cw_home_confirm_restart_body": "เกมและงานที่กำลังทำงานจะหยุด หน้านี้จะขาดการเชื่อมต่อจนกว่าคอนโซลจะกลับมา", + "cw_home_confirm_restart_title": "รีสตาร์ทคอนโซลไหม", + "cw_home_err_busy": "คอนโซลไม่ว่าง ลองอีกครั้งในอีกสักครู่", + "cw_home_err_failed": "ไม่สำเร็จ ({code})", + "cw_home_err_gone": "งานนั้นสิ้นสุดไปแล้ว", + "cw_home_err_load_storage": "อ่านไดรฟ์ไม่ได้", + "cw_home_err_load_tasks": "อ่านรายการงานไม่ได้", + "cw_home_err_offline": "คอนโซลไม่ตอบสนอง ลองอีกครั้ง", + "cw_home_free_of": "ว่าง {free} จาก {total}", + "cw_home_keep_task": "ทำงานต่อ", + "cw_home_kind_copy": "คัดลอก", + "cw_home_kind_download": "ดาวน์โหลด", + "cw_home_kind_op": "การจัดการไฟล์", + "cw_home_kind_other": "งาน", + "cw_home_kind_upload": "อัปโหลด", + "cw_home_loading": "กำลังโหลด…", + "cw_home_no_game": "ไม่มีเกมที่กำลังทำงาน", + "cw_home_no_tasks": "ตอนนี้ไม่มีงาน", + "cw_home_now_running": "กำลังทำงานอยู่", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} จาก {total}", + "cw_home_progress_files": "{done} จาก {total} ไฟล์", + "cw_home_quick": "การทำงานด่วน", + "cw_home_rest": "โหมดพัก", + "cw_home_rest_sent": "คอนโซลกำลังเข้าสู่โหมดพัก", + "cw_home_restart": "รีสตาร์ท", + "cw_home_restart_sent": "คอนโซลกำลังรีสตาร์ท โหลดหน้านี้ใหม่เมื่อกลับมาแล้ว", + "cw_home_state_done": "เสร็จแล้ว", + "cw_home_state_failed": "ล้มเหลว", + "cw_home_state_running": "กำลังทำงาน", + "cw_home_storage": "ที่เก็บข้อมูล", + "cw_home_tasks": "งาน", + "cw_home_vol_ext": "ที่เก็บข้อมูลเสริม", + "cw_home_vol_internal": "ที่เก็บข้อมูลภายใน", + "cw_home_vol_m2": "ที่เก็บข้อมูล M.2", + "cw_home_vol_readonly": "อ่านอย่างเดียว", + "cw_home_vol_usb": "ไดรฟ์ USB", + "cw_home_vol_usb_ext": "ที่เก็บข้อมูลเสริม USB", "cw_nav_files": "ไฟล์", "cw_nav_home": "หน้าหลัก", "cw_nav_sections": "ส่วน", @@ -303,15 +1185,67 @@ "cw_reload_title": "ตัวช่วย ps5upload เริ่มใหม่แล้ว", "cw_select": "เลือก", "cw_status_connecting": "กำลังเชื่อมต่อ…", - "cw_status_offline": "ไม่ได้เชื่อมต่อ" + "cw_status_offline": "ไม่ได้เชื่อมต่อ", + "cw_task_from_console": "จากคอนโซลนี้", + "cw_task_from_pc": "จาก PC" }, "tr": { "cw_actions": "İşlemler", + "cw_dialog_cancel": "İptal", "cw_hint_back": "Geri", "cw_hint_filter": "Filtrele", "cw_hint_open": "Aç", "cw_hint_switch_section": "Bölüm değiştir", "cw_hints_label": "Kumanda düğmeleri", + "cw_home_browse_usb": "USB'ye göz at", + "cw_home_cancel_task": "İptal et", + "cw_home_cancel_task_confirm": "Görevi iptal et", + "cw_home_close_game": "Oyunu kapat", + "cw_home_confirm_cancel_body": "Hemen durur. Bu geri alınamaz.", + "cw_home_confirm_cancel_body_pc": "Bu görevi bir PC başlattı. PC'de de durur.", + "cw_home_confirm_cancel_title": "Bu görev iptal edilsin mi?", + "cw_home_confirm_close_body": "Oyunda kaydedilmemiş ilerleme kaybolur.", + "cw_home_confirm_close_title": "{name} kapatılsın mı?", + "cw_home_confirm_rest_body": "Bu sayfanın bağlantısı konsol uyanana kadar kesilir.", + "cw_home_confirm_rest_title": "Konsol dinlenme moduna alınsın mı?", + "cw_home_confirm_restart_body": "Çalışan oyunlar ve görevler durur. Bu sayfanın bağlantısı konsol geri gelene kadar kesilir.", + "cw_home_confirm_restart_title": "Konsol yeniden başlatılsın mı?", + "cw_home_err_busy": "Konsol meşgul. Birazdan tekrar dene.", + "cw_home_err_failed": "Bu işe yaramadı ({code}).", + "cw_home_err_gone": "Bu görev zaten bitti.", + "cw_home_err_load_storage": "Sürücüler okunamadı.", + "cw_home_err_load_tasks": "Görev listesi okunamadı.", + "cw_home_err_offline": "Konsol yanıt vermedi. Tekrar dene.", + "cw_home_free_of": "{total} alanın {free} kadarı boş", + "cw_home_keep_task": "Devam etsin", + "cw_home_kind_copy": "Kopyalama", + "cw_home_kind_download": "İndirme", + "cw_home_kind_op": "Dosya işlemi", + "cw_home_kind_other": "Görev", + "cw_home_kind_upload": "Yükleme", + "cw_home_loading": "Yükleniyor…", + "cw_home_no_game": "Çalışan oyun yok.", + "cw_home_no_tasks": "Şu anda görev yok.", + "cw_home_now_running": "Şu anda çalışıyor", + "cw_home_percent": "%{n}", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} dosya", + "cw_home_quick": "Hızlı işlemler", + "cw_home_rest": "Dinlenme modu", + "cw_home_rest_sent": "Konsol dinlenme moduna geçiyor.", + "cw_home_restart": "Yeniden başlat", + "cw_home_restart_sent": "Konsol yeniden başlıyor. Geri geldiğinde bu sayfayı yenile.", + "cw_home_state_done": "Bitti", + "cw_home_state_failed": "Başarısız", + "cw_home_state_running": "Çalışıyor", + "cw_home_storage": "Depolama", + "cw_home_tasks": "Görevler", + "cw_home_vol_ext": "Genişletilmiş depolama", + "cw_home_vol_internal": "Dahili depolama", + "cw_home_vol_m2": "M.2 depolama", + "cw_home_vol_readonly": "Salt okunur", + "cw_home_vol_usb": "USB sürücü", + "cw_home_vol_usb_ext": "USB genişletilmiş depolama", "cw_nav_files": "Dosyalar", "cw_nav_home": "Ana sayfa", "cw_nav_sections": "Bölümler", @@ -321,15 +1255,67 @@ "cw_reload_title": "ps5upload yardımcısı yeniden başladı", "cw_select": "Seç", "cw_status_connecting": "Bağlanıyor…", - "cw_status_offline": "Bağlı değil" + "cw_status_offline": "Bağlı değil", + "cw_task_from_console": "Bu konsoldan", + "cw_task_from_pc": "Bir PC'den" }, "vi": { "cw_actions": "Thao tác", + "cw_dialog_cancel": "Hủy", "cw_hint_back": "Quay lại", "cw_hint_filter": "Lọc", "cw_hint_open": "Mở", "cw_hint_switch_section": "Chuyển mục", "cw_hints_label": "Nút tay cầm", + "cw_home_browse_usb": "Duyệt USB", + "cw_home_cancel_task": "Hủy", + "cw_home_cancel_task_confirm": "Hủy tác vụ", + "cw_home_close_game": "Đóng game", + "cw_home_confirm_cancel_body": "Tác vụ dừng ngay. Không thể hoàn tác.", + "cw_home_confirm_cancel_body_pc": "Một PC đã bắt đầu tác vụ này. Tác vụ cũng dừng trên PC.", + "cw_home_confirm_cancel_title": "Hủy tác vụ này?", + "cw_home_confirm_close_body": "Tiến trình chưa lưu trong game sẽ mất.", + "cw_home_confirm_close_title": "Đóng {name}?", + "cw_home_confirm_rest_body": "Trang này mất kết nối cho đến khi máy thức dậy.", + "cw_home_confirm_rest_title": "Đưa máy vào chế độ nghỉ?", + "cw_home_confirm_restart_body": "Các game và tác vụ đang chạy sẽ dừng. Trang này mất kết nối cho đến khi máy hoạt động trở lại.", + "cw_home_confirm_restart_title": "Khởi động lại máy?", + "cw_home_err_busy": "Máy đang bận. Hãy thử lại sau giây lát.", + "cw_home_err_failed": "Không thành công ({code}).", + "cw_home_err_gone": "Tác vụ đó đã kết thúc.", + "cw_home_err_load_storage": "Không đọc được các ổ đĩa.", + "cw_home_err_load_tasks": "Không đọc được danh sách tác vụ.", + "cw_home_err_offline": "Máy không phản hồi. Hãy thử lại.", + "cw_home_free_of": "Còn trống {free} / {total}", + "cw_home_keep_task": "Tiếp tục", + "cw_home_kind_copy": "Sao chép", + "cw_home_kind_download": "Tải xuống", + "cw_home_kind_op": "Thao tác tệp", + "cw_home_kind_other": "Tác vụ", + "cw_home_kind_upload": "Tải lên", + "cw_home_loading": "Đang tải…", + "cw_home_no_game": "Không có game nào đang chạy.", + "cw_home_no_tasks": "Hiện không có tác vụ nào.", + "cw_home_now_running": "Đang chạy", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} tệp", + "cw_home_quick": "Thao tác nhanh", + "cw_home_rest": "Chế độ nghỉ", + "cw_home_rest_sent": "Máy đang chuyển sang chế độ nghỉ.", + "cw_home_restart": "Khởi động lại", + "cw_home_restart_sent": "Máy đang khởi động lại. Hãy tải lại trang này khi máy hoạt động trở lại.", + "cw_home_state_done": "Xong", + "cw_home_state_failed": "Thất bại", + "cw_home_state_running": "Đang chạy", + "cw_home_storage": "Bộ nhớ", + "cw_home_tasks": "Tác vụ", + "cw_home_vol_ext": "Bộ nhớ mở rộng", + "cw_home_vol_internal": "Bộ nhớ trong", + "cw_home_vol_m2": "Bộ nhớ M.2", + "cw_home_vol_readonly": "Chỉ đọc", + "cw_home_vol_usb": "Ổ USB", + "cw_home_vol_usb_ext": "Bộ nhớ mở rộng USB", "cw_nav_files": "Tệp", "cw_nav_home": "Trang chủ", "cw_nav_sections": "Mục", @@ -339,15 +1325,67 @@ "cw_reload_title": "Trình trợ giúp ps5upload đã khởi động lại", "cw_select": "Chọn", "cw_status_connecting": "Đang kết nối…", - "cw_status_offline": "Chưa kết nối" + "cw_status_offline": "Chưa kết nối", + "cw_task_from_console": "Từ máy này", + "cw_task_from_pc": "Từ PC" }, "zh-CN": { "cw_actions": "操作", + "cw_dialog_cancel": "取消", "cw_hint_back": "返回", "cw_hint_filter": "筛选", "cw_hint_open": "打开", "cw_hint_switch_section": "切换分区", "cw_hints_label": "手柄按键", + "cw_home_browse_usb": "浏览 USB", + "cw_home_cancel_task": "取消", + "cw_home_cancel_task_confirm": "取消任务", + "cw_home_close_game": "关闭游戏", + "cw_home_confirm_cancel_body": "任务会立即停止,且无法撤销。", + "cw_home_confirm_cancel_body_pc": "此任务由电脑发起,电脑端也会停止。", + "cw_home_confirm_cancel_title": "取消此任务?", + "cw_home_confirm_close_body": "游戏中未保存的进度将丢失。", + "cw_home_confirm_close_title": "关闭 {name}?", + "cw_home_confirm_rest_body": "主机唤醒前,此页面将断开连接。", + "cw_home_confirm_rest_title": "让主机进入待机模式?", + "cw_home_confirm_restart_body": "正在运行的游戏和任务会停止。主机恢复前,此页面将断开连接。", + "cw_home_confirm_restart_title": "重启主机?", + "cw_home_err_busy": "主机正忙,请稍后重试。", + "cw_home_err_failed": "操作未成功({code})。", + "cw_home_err_gone": "该任务已经结束。", + "cw_home_err_load_storage": "无法读取驱动器。", + "cw_home_err_load_tasks": "无法读取任务列表。", + "cw_home_err_offline": "主机没有响应,请重试。", + "cw_home_free_of": "可用 {free},共 {total}", + "cw_home_keep_task": "继续运行", + "cw_home_kind_copy": "复制", + "cw_home_kind_download": "下载", + "cw_home_kind_op": "文件操作", + "cw_home_kind_other": "任务", + "cw_home_kind_upload": "上传", + "cw_home_loading": "正在加载…", + "cw_home_no_game": "没有正在运行的游戏。", + "cw_home_no_tasks": "当前没有任务。", + "cw_home_now_running": "正在运行", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} 个文件", + "cw_home_quick": "快捷操作", + "cw_home_rest": "待机模式", + "cw_home_rest_sent": "主机正在进入待机模式。", + "cw_home_restart": "重启", + "cw_home_restart_sent": "主机正在重启。恢复后请重新加载此页面。", + "cw_home_state_done": "已完成", + "cw_home_state_failed": "失败", + "cw_home_state_running": "进行中", + "cw_home_storage": "存储", + "cw_home_tasks": "任务", + "cw_home_vol_ext": "扩展存储", + "cw_home_vol_internal": "内置存储", + "cw_home_vol_m2": "M.2 存储", + "cw_home_vol_readonly": "只读", + "cw_home_vol_usb": "USB 驱动器", + "cw_home_vol_usb_ext": "USB 扩展存储", "cw_nav_files": "文件", "cw_nav_home": "主页", "cw_nav_sections": "分区", @@ -357,15 +1395,67 @@ "cw_reload_title": "ps5upload 助手已重启", "cw_select": "选择", "cw_status_connecting": "正在连接…", - "cw_status_offline": "未连接" + "cw_status_offline": "未连接", + "cw_task_from_console": "来自本主机", + "cw_task_from_pc": "来自电脑" }, "zh-TW": { "cw_actions": "操作", + "cw_dialog_cancel": "取消", "cw_hint_back": "返回", "cw_hint_filter": "篩選", "cw_hint_open": "開啟", "cw_hint_switch_section": "切換分區", "cw_hints_label": "控制器按鍵", + "cw_home_browse_usb": "瀏覽 USB", + "cw_home_cancel_task": "取消", + "cw_home_cancel_task_confirm": "取消工作", + "cw_home_close_game": "關閉遊戲", + "cw_home_confirm_cancel_body": "工作會立即停止,且無法復原。", + "cw_home_confirm_cancel_body_pc": "這項工作由電腦啟動,電腦端也會停止。", + "cw_home_confirm_cancel_title": "要取消這項工作嗎?", + "cw_home_confirm_close_body": "遊戲中未儲存的進度將會遺失。", + "cw_home_confirm_close_title": "要關閉 {name} 嗎?", + "cw_home_confirm_rest_body": "主機喚醒前,此頁面會中斷連線。", + "cw_home_confirm_rest_title": "要讓主機進入休眠模式嗎?", + "cw_home_confirm_restart_body": "執行中的遊戲和工作會停止。主機恢復前,此頁面會中斷連線。", + "cw_home_confirm_restart_title": "要重新啟動主機嗎?", + "cw_home_err_busy": "主機忙碌中,請稍後再試。", + "cw_home_err_failed": "操作未成功({code})。", + "cw_home_err_gone": "這項工作已經結束。", + "cw_home_err_load_storage": "無法讀取磁碟機。", + "cw_home_err_load_tasks": "無法讀取工作清單。", + "cw_home_err_offline": "主機沒有回應,請再試一次。", + "cw_home_free_of": "可用 {free},共 {total}", + "cw_home_keep_task": "繼續執行", + "cw_home_kind_copy": "複製", + "cw_home_kind_download": "下載", + "cw_home_kind_op": "檔案操作", + "cw_home_kind_other": "工作", + "cw_home_kind_upload": "上傳", + "cw_home_loading": "載入中…", + "cw_home_no_game": "沒有執行中的遊戲。", + "cw_home_no_tasks": "目前沒有工作。", + "cw_home_now_running": "執行中", + "cw_home_percent": "{n}%", + "cw_home_progress_bytes": "{done} / {total}", + "cw_home_progress_files": "{done} / {total} 個檔案", + "cw_home_quick": "快速動作", + "cw_home_rest": "休眠模式", + "cw_home_rest_sent": "主機正在進入休眠模式。", + "cw_home_restart": "重新啟動", + "cw_home_restart_sent": "主機正在重新啟動。恢復後請重新載入此頁面。", + "cw_home_state_done": "已完成", + "cw_home_state_failed": "失敗", + "cw_home_state_running": "進行中", + "cw_home_storage": "儲存空間", + "cw_home_tasks": "工作", + "cw_home_vol_ext": "延伸儲存空間", + "cw_home_vol_internal": "內建儲存空間", + "cw_home_vol_m2": "M.2 儲存空間", + "cw_home_vol_readonly": "唯讀", + "cw_home_vol_usb": "USB 磁碟機", + "cw_home_vol_usb_ext": "USB 延伸儲存空間", "cw_nav_files": "檔案", "cw_nav_home": "首頁", "cw_nav_sections": "分區", @@ -375,6 +1465,8 @@ "cw_reload_title": "ps5upload 助手已重新啟動", "cw_select": "選取", "cw_status_connecting": "正在連線…", - "cw_status_offline": "未連線" + "cw_status_offline": "未連線", + "cw_task_from_console": "來自本主機", + "cw_task_from_pc": "來自電腦" } } diff --git a/client/src/console/ui/ConfirmDialog.tsx b/client/src/console/ui/ConfirmDialog.tsx new file mode 100644 index 00000000..3dd412c7 --- /dev/null +++ b/client/src/console/ui/ConfirmDialog.tsx @@ -0,0 +1,89 @@ +import { useEffect, useRef } from "react"; +import { focusElement, onNavAction, type NavAction } from "../nav"; +import { t } from "../strings"; + +/** + * The dialog's controller handling: ○ is "no". Every other action is swallowed + * while it is open (the page behind never sees them anyway: nav.ts scopes + * handlers to the open modal). + */ +export function dialogNavHandler(onCancel: () => void): (action: NavAction) => boolean { + return (action) => { + if (action === "back") onCancel(); + return true; + }; +} + +/** + * "Are you sure?" for anything that cannot be undone: close a game, cancel a + * task, rest mode, restart, delete. A nav modal: the D-pad stays inside it, + * focus starts on the safe choice (listed first), ○ closes it, and focus goes + * back where it was when it closes. + */ +export function ConfirmDialog({ + title, + body, + confirmLabel, + cancelLabel, + danger, + busy, + onConfirm, + onCancel, +}: { + title: string; + body?: string; + confirmLabel: string; + /** Default: "Cancel". */ + cancelLabel?: string; + /** The confirm button in the warning colour. */ + danger?: boolean; + /** The action is running: a second ✕ does nothing. */ + busy?: boolean; + onConfirm: () => void; + onCancel: () => void; +}) { + const root = useRef(null); + const safe = useRef(null); + + useEffect(() => { + const before = document.activeElement as HTMLElement | null; + if (safe.current) focusElement(safe.current); + return () => { + if (before && before !== document.body && before.isConnected) focusElement(before); + }; + }, []); + + useEffect(() => onNavAction(dialogNavHandler(onCancel), () => root.current), [onCancel]); + + return ( +
    +
    +

    {title}

    + {body ?

    {body}

    : null} +
    + + +
    +
    +
    + ); +} diff --git a/client/src/i18n/locales/ar.ts b/client/src/i18n/locales/ar.ts index 6dde4599..438bec6e 100644 --- a/client/src/i18n/locales/ar.ts +++ b/client/src/i18n/locales/ar.ts @@ -4046,6 +4046,58 @@ c2c_test_deep_bad: "لم يصل الإرسال التجريبي بحجم 4 KiB: "cw_status_connecting": "جارٍ الاتصال…", "cw_status_offline": "غير متصل", "cw_hints_label": "أزرار وحدة التحكم", +"cw_task_from_console": "من هذا الجهاز", +"cw_task_from_pc": "من حاسوب", +"cw_dialog_cancel": "إلغاء", +"cw_home_kind_upload": "رفع", +"cw_home_kind_download": "تنزيل", +"cw_home_kind_copy": "نسخ", +"cw_home_kind_op": "عملية ملفات", +"cw_home_kind_other": "مهمة", +"cw_home_progress_bytes": "{done} من {total}", +"cw_home_progress_files": "{done} من {total} ملفات", +"cw_home_percent": "{n}%", +"cw_home_state_running": "قيد التشغيل", +"cw_home_state_done": "اكتملت", +"cw_home_state_failed": "فشلت", +"cw_home_cancel_task": "إلغاء", +"cw_home_vol_internal": "التخزين الداخلي", +"cw_home_vol_usb": "محرك USB", +"cw_home_vol_usb_ext": "تخزين موسّع عبر USB", +"cw_home_vol_m2": "تخزين M.2", +"cw_home_vol_ext": "تخزين موسّع", +"cw_home_vol_readonly": "للقراءة فقط", +"cw_home_free_of": "{free} متاحة من {total}", +"cw_home_err_offline": "لم يستجب الجهاز. حاول مرة أخرى.", +"cw_home_err_busy": "الجهاز مشغول. حاول مرة أخرى بعد قليل.", +"cw_home_err_gone": "انتهت هذه المهمة بالفعل.", +"cw_home_err_failed": "لم ينجح ذلك ({code}).", +"cw_home_err_load_tasks": "تعذّرت قراءة قائمة المهام.", +"cw_home_err_load_storage": "تعذّرت قراءة المحركات.", +"cw_home_rest_sent": "ينتقل الجهاز إلى وضع الراحة.", +"cw_home_restart_sent": "يُعاد تشغيل الجهاز. أعد تحميل هذه الصفحة عند عودته.", +"cw_home_confirm_cancel_title": "إلغاء هذه المهمة؟", +"cw_home_confirm_cancel_body": "ستتوقف الآن. لا يمكن التراجع عن ذلك.", +"cw_home_confirm_cancel_body_pc": "بدأ حاسوب هذه المهمة. ستتوقف على الحاسوب أيضًا.", +"cw_home_cancel_task_confirm": "إلغاء المهمة", +"cw_home_keep_task": "متابعة", +"cw_home_confirm_close_title": "إغلاق {name}؟", +"cw_home_confirm_close_body": "سيضيع التقدم غير المحفوظ في اللعبة.", +"cw_home_close_game": "إغلاق اللعبة", +"cw_home_confirm_rest_title": "وضع الجهاز في وضع الراحة؟", +"cw_home_confirm_rest_body": "تنقطع هذه الصفحة حتى يستيقظ الجهاز.", +"cw_home_rest": "وضع الراحة", +"cw_home_confirm_restart_title": "إعادة تشغيل الجهاز؟", +"cw_home_confirm_restart_body": "تتوقف الألعاب والمهام الجارية. تنقطع هذه الصفحة حتى يعود الجهاز.", +"cw_home_restart": "إعادة التشغيل", +"cw_home_loading": "جارٍ التحميل…", +"cw_home_no_tasks": "لا توجد مهام حاليًا.", +"cw_home_quick": "إجراءات سريعة", +"cw_home_browse_usb": "تصفح USB", +"cw_home_now_running": "قيد التشغيل الآن", +"cw_home_no_game": "لا توجد لعبة قيد التشغيل.", +"cw_home_tasks": "المهام", +"cw_home_storage": "التخزين", }; export default ar; diff --git a/client/src/i18n/locales/bn.ts b/client/src/i18n/locales/bn.ts index 705e02df..eab0932a 100644 --- a/client/src/i18n/locales/bn.ts +++ b/client/src/i18n/locales/bn.ts @@ -4046,6 +4046,58 @@ c2c_test_deep_bad: "4 KiB-এর পরীক্ষামূলক পাঠা "cw_status_connecting": "সংযোগ হচ্ছে…", "cw_status_offline": "সংযুক্ত নয়", "cw_hints_label": "কন্ট্রোলারের বোতাম", +"cw_task_from_console": "এই কনসোল থেকে", +"cw_task_from_pc": "PC থেকে", +"cw_dialog_cancel": "বাতিল", +"cw_home_kind_upload": "আপলোড", +"cw_home_kind_download": "ডাউনলোড", +"cw_home_kind_copy": "কপি", +"cw_home_kind_op": "ফাইল অপারেশন", +"cw_home_kind_other": "কাজ", +"cw_home_progress_bytes": "{total}-এর মধ্যে {done}", +"cw_home_progress_files": "{total}টির মধ্যে {done}টি ফাইল", +"cw_home_percent": "{n}%", +"cw_home_state_running": "চলছে", +"cw_home_state_done": "সম্পন্ন", +"cw_home_state_failed": "ব্যর্থ", +"cw_home_cancel_task": "বাতিল", +"cw_home_vol_internal": "অভ্যন্তরীণ স্টোরেজ", +"cw_home_vol_usb": "USB ড্রাইভ", +"cw_home_vol_usb_ext": "USB এক্সটেন্ডেড স্টোরেজ", +"cw_home_vol_m2": "M.2 স্টোরেজ", +"cw_home_vol_ext": "এক্সটেন্ডেড স্টোরেজ", +"cw_home_vol_readonly": "শুধু পড়া যায়", +"cw_home_free_of": "{total}-এর মধ্যে {free} খালি", +"cw_home_err_offline": "কনসোল সাড়া দেয়নি। আবার চেষ্টা করুন।", +"cw_home_err_busy": "কনসোল ব্যস্ত। একটু পরে আবার চেষ্টা করুন।", +"cw_home_err_gone": "সেই কাজটি আগেই শেষ হয়েছে।", +"cw_home_err_failed": "এটি কাজ করেনি ({code})।", +"cw_home_err_load_tasks": "কাজের তালিকা পড়া যায়নি।", +"cw_home_err_load_storage": "ড্রাইভগুলো পড়া যায়নি।", +"cw_home_rest_sent": "কনসোল রেস্ট মোডে যাচ্ছে।", +"cw_home_restart_sent": "কনসোল রিস্টার্ট হচ্ছে। ফিরে এলে এই পেজটি আবার লোড করুন।", +"cw_home_confirm_cancel_title": "এই কাজটি বাতিল করবেন?", +"cw_home_confirm_cancel_body": "এটি এখনই থেমে যাবে। এটি পূর্বাবস্থায় ফেরানো যাবে না।", +"cw_home_confirm_cancel_body_pc": "একটি PC এই কাজটি শুরু করেছিল। এটি PC-তেও থেমে যাবে।", +"cw_home_cancel_task_confirm": "কাজ বাতিল করুন", +"cw_home_keep_task": "চলতে দিন", +"cw_home_confirm_close_title": "{name} বন্ধ করবেন?", +"cw_home_confirm_close_body": "গেমের সেভ না করা অগ্রগতি হারিয়ে যাবে।", +"cw_home_close_game": "গেম বন্ধ করুন", +"cw_home_confirm_rest_title": "কনসোলকে রেস্ট মোডে রাখবেন?", +"cw_home_confirm_rest_body": "কনসোল জেগে না ওঠা পর্যন্ত এই পেজ বিচ্ছিন্ন থাকবে।", +"cw_home_rest": "রেস্ট মোড", +"cw_home_confirm_restart_title": "কনসোল রিস্টার্ট করবেন?", +"cw_home_confirm_restart_body": "চলমান গেম ও কাজ থেমে যাবে। কনসোল ফিরে না আসা পর্যন্ত এই পেজ বিচ্ছিন্ন থাকবে।", +"cw_home_restart": "রিস্টার্ট", +"cw_home_loading": "লোড হচ্ছে…", +"cw_home_no_tasks": "এখন কোনো কাজ নেই।", +"cw_home_quick": "দ্রুত কাজ", +"cw_home_browse_usb": "USB ব্রাউজ করুন", +"cw_home_now_running": "এখন চলছে", +"cw_home_no_game": "কোনো গেম চলছে না।", +"cw_home_tasks": "কাজ", +"cw_home_storage": "স্টোরেজ", }; export default bn; diff --git a/client/src/i18n/locales/de.ts b/client/src/i18n/locales/de.ts index 0a83e07f..80f604bb 100644 --- a/client/src/i18n/locales/de.ts +++ b/client/src/i18n/locales/de.ts @@ -4054,6 +4054,58 @@ c2c_test_deep_bad: "Die 4-KiB-Testsendung ist nicht angekommen: {detail}", "cw_status_connecting": "Verbinde…", "cw_status_offline": "Nicht verbunden", "cw_hints_label": "Controller-Tasten", +"cw_task_from_console": "Von dieser Konsole", +"cw_task_from_pc": "Von einem PC", +"cw_dialog_cancel": "Abbrechen", +"cw_home_kind_upload": "Hochladen", +"cw_home_kind_download": "Herunterladen", +"cw_home_kind_copy": "Kopieren", +"cw_home_kind_op": "Dateivorgang", +"cw_home_kind_other": "Aufgabe", +"cw_home_progress_bytes": "{done} von {total}", +"cw_home_progress_files": "{done} von {total} Dateien", +"cw_home_percent": "{n} %", +"cw_home_state_running": "Läuft", +"cw_home_state_done": "Fertig", +"cw_home_state_failed": "Fehlgeschlagen", +"cw_home_cancel_task": "Abbrechen", +"cw_home_vol_internal": "Interner Speicher", +"cw_home_vol_usb": "USB-Laufwerk", +"cw_home_vol_usb_ext": "USB-Erweiterungsspeicher", +"cw_home_vol_m2": "M.2-Speicher", +"cw_home_vol_ext": "Erweiterungsspeicher", +"cw_home_vol_readonly": "Schreibgeschützt", +"cw_home_free_of": "{free} frei von {total}", +"cw_home_err_offline": "Die Konsole hat nicht geantwortet. Versuche es erneut.", +"cw_home_err_busy": "Die Konsole ist beschäftigt. Versuche es gleich noch einmal.", +"cw_home_err_gone": "Diese Aufgabe ist bereits beendet.", +"cw_home_err_failed": "Das hat nicht funktioniert ({code}).", +"cw_home_err_load_tasks": "Die Aufgabenliste konnte nicht gelesen werden.", +"cw_home_err_load_storage": "Die Laufwerke konnten nicht gelesen werden.", +"cw_home_rest_sent": "Die Konsole wechselt in den Ruhemodus.", +"cw_home_restart_sent": "Die Konsole startet neu. Lade diese Seite neu, sobald sie wieder da ist.", +"cw_home_confirm_cancel_title": "Diese Aufgabe abbrechen?", +"cw_home_confirm_cancel_body": "Sie stoppt sofort. Das lässt sich nicht rückgängig machen.", +"cw_home_confirm_cancel_body_pc": "Ein PC hat diese Aufgabe gestartet. Sie stoppt auch auf dem PC.", +"cw_home_cancel_task_confirm": "Aufgabe abbrechen", +"cw_home_keep_task": "Weiterlaufen lassen", +"cw_home_confirm_close_title": "{name} schließen?", +"cw_home_confirm_close_body": "Nicht gespeicherter Spielfortschritt geht verloren.", +"cw_home_close_game": "Spiel schließen", +"cw_home_confirm_rest_title": "Konsole in den Ruhemodus versetzen?", +"cw_home_confirm_rest_body": "Diese Seite ist getrennt, bis die Konsole aufwacht.", +"cw_home_rest": "Ruhemodus", +"cw_home_confirm_restart_title": "Konsole neu starten?", +"cw_home_confirm_restart_body": "Laufende Spiele und Aufgaben werden beendet. Diese Seite ist getrennt, bis die Konsole wieder da ist.", +"cw_home_restart": "Neu starten", +"cw_home_loading": "Wird geladen…", +"cw_home_no_tasks": "Gerade keine Aufgaben.", +"cw_home_quick": "Schnellaktionen", +"cw_home_browse_usb": "USB durchsuchen", +"cw_home_now_running": "Läuft gerade", +"cw_home_no_game": "Es läuft kein Spiel.", +"cw_home_tasks": "Aufgaben", +"cw_home_storage": "Speicher", }; export default de; diff --git a/client/src/i18n/locales/en.ts b/client/src/i18n/locales/en.ts index f55bb912..e3e8b114 100644 --- a/client/src/i18n/locales/en.ts +++ b/client/src/i18n/locales/en.ts @@ -4369,6 +4369,58 @@ c2c_test_deep_bad: "The 4 KiB test send did not arrive: {detail}", "cw_status_connecting": "Connecting…", "cw_status_offline": "Not connected", "cw_hints_label": "Controller buttons", +"cw_task_from_console": "From this console", +"cw_task_from_pc": "From a PC", +"cw_dialog_cancel": "Cancel", +"cw_home_kind_upload": "Upload", +"cw_home_kind_download": "Download", +"cw_home_kind_copy": "Copy", +"cw_home_kind_op": "File operation", +"cw_home_kind_other": "Task", +"cw_home_progress_bytes": "{done} of {total}", +"cw_home_progress_files": "{done} of {total} files", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Running", +"cw_home_state_done": "Done", +"cw_home_state_failed": "Failed", +"cw_home_cancel_task": "Cancel", +"cw_home_vol_internal": "Internal storage", +"cw_home_vol_usb": "USB drive", +"cw_home_vol_usb_ext": "USB extended storage", +"cw_home_vol_m2": "M.2 storage", +"cw_home_vol_ext": "Extended storage", +"cw_home_vol_readonly": "Read-only", +"cw_home_free_of": "{free} free of {total}", +"cw_home_err_offline": "The console did not answer. Try again.", +"cw_home_err_busy": "The console is busy. Try again in a moment.", +"cw_home_err_gone": "That task has already ended.", +"cw_home_err_failed": "That did not work ({code}).", +"cw_home_err_load_tasks": "Could not read the task list.", +"cw_home_err_load_storage": "Could not read the drives.", +"cw_home_rest_sent": "The console is going into rest mode.", +"cw_home_restart_sent": "The console is restarting. Reload this page when it is back.", +"cw_home_confirm_cancel_title": "Cancel this task?", +"cw_home_confirm_cancel_body": "It stops now. This cannot be undone.", +"cw_home_confirm_cancel_body_pc": "A PC started this task. It stops on the PC too.", +"cw_home_cancel_task_confirm": "Cancel task", +"cw_home_keep_task": "Keep going", +"cw_home_confirm_close_title": "Close {name}?", +"cw_home_confirm_close_body": "Progress you have not saved in the game is lost.", +"cw_home_close_game": "Close game", +"cw_home_confirm_rest_title": "Put the console in rest mode?", +"cw_home_confirm_rest_body": "This page disconnects until the console wakes up.", +"cw_home_rest": "Rest mode", +"cw_home_confirm_restart_title": "Restart the console?", +"cw_home_confirm_restart_body": "Running games and tasks stop. This page disconnects until the console is back.", +"cw_home_restart": "Restart", +"cw_home_loading": "Loading…", +"cw_home_no_tasks": "No tasks right now.", +"cw_home_quick": "Quick actions", +"cw_home_browse_usb": "Browse USB", +"cw_home_now_running": "Now running", +"cw_home_no_game": "No game is running.", +"cw_home_tasks": "Tasks", +"cw_home_storage": "Storage", }; export default en; diff --git a/client/src/i18n/locales/es.ts b/client/src/i18n/locales/es.ts index 496b4a06..8321742e 100644 --- a/client/src/i18n/locales/es.ts +++ b/client/src/i18n/locales/es.ts @@ -3996,6 +3996,58 @@ c2c_test_deep_bad: "El envío de prueba de 4 KiB no llegó: {detail}", "cw_status_connecting": "Conectando…", "cw_status_offline": "Sin conexión", "cw_hints_label": "Botones del mando", +"cw_task_from_console": "Desde esta consola", +"cw_task_from_pc": "Desde un PC", +"cw_dialog_cancel": "Cancelar", +"cw_home_kind_upload": "Subida", +"cw_home_kind_download": "Descarga", +"cw_home_kind_copy": "Copia", +"cw_home_kind_op": "Operación de archivos", +"cw_home_kind_other": "Tarea", +"cw_home_progress_bytes": "{done} de {total}", +"cw_home_progress_files": "{done} de {total} archivos", +"cw_home_percent": "{n} %", +"cw_home_state_running": "En curso", +"cw_home_state_done": "Hecho", +"cw_home_state_failed": "Error", +"cw_home_cancel_task": "Cancelar", +"cw_home_vol_internal": "Almacenamiento interno", +"cw_home_vol_usb": "Unidad USB", +"cw_home_vol_usb_ext": "Almacenamiento ampliado USB", +"cw_home_vol_m2": "Almacenamiento M.2", +"cw_home_vol_ext": "Almacenamiento ampliado", +"cw_home_vol_readonly": "Solo lectura", +"cw_home_free_of": "{free} libres de {total}", +"cw_home_err_offline": "La consola no respondió. Inténtalo de nuevo.", +"cw_home_err_busy": "La consola está ocupada. Inténtalo de nuevo en un momento.", +"cw_home_err_gone": "Esa tarea ya ha terminado.", +"cw_home_err_failed": "No ha funcionado ({code}).", +"cw_home_err_load_tasks": "No se pudo leer la lista de tareas.", +"cw_home_err_load_storage": "No se pudieron leer las unidades.", +"cw_home_rest_sent": "La consola está entrando en modo de reposo.", +"cw_home_restart_sent": "La consola se está reiniciando. Recarga esta página cuando vuelva.", +"cw_home_confirm_cancel_title": "¿Cancelar esta tarea?", +"cw_home_confirm_cancel_body": "Se detiene ahora. No se puede deshacer.", +"cw_home_confirm_cancel_body_pc": "Un PC inició esta tarea. También se detiene en el PC.", +"cw_home_cancel_task_confirm": "Cancelar tarea", +"cw_home_keep_task": "Continuar", +"cw_home_confirm_close_title": "¿Cerrar {name}?", +"cw_home_confirm_close_body": "Se perderá el progreso no guardado del juego.", +"cw_home_close_game": "Cerrar juego", +"cw_home_confirm_rest_title": "¿Poner la consola en modo de reposo?", +"cw_home_confirm_rest_body": "Esta página se desconecta hasta que la consola se active.", +"cw_home_rest": "Modo de reposo", +"cw_home_confirm_restart_title": "¿Reiniciar la consola?", +"cw_home_confirm_restart_body": "Los juegos y tareas en curso se detienen. Esta página se desconecta hasta que la consola vuelva.", +"cw_home_restart": "Reiniciar", +"cw_home_loading": "Cargando…", +"cw_home_no_tasks": "No hay tareas ahora mismo.", +"cw_home_quick": "Acciones rápidas", +"cw_home_browse_usb": "Explorar USB", +"cw_home_now_running": "En ejecución", +"cw_home_no_game": "No hay ningún juego en ejecución.", +"cw_home_tasks": "Tareas", +"cw_home_storage": "Almacenamiento", }; export default es; diff --git a/client/src/i18n/locales/fa.ts b/client/src/i18n/locales/fa.ts index ee2987e7..b0e32c94 100644 --- a/client/src/i18n/locales/fa.ts +++ b/client/src/i18n/locales/fa.ts @@ -4347,6 +4347,58 @@ c2c_test_deep_bad: "ارسال آزمایشی ۴ KiB نرسید: {detail}", "cw_status_connecting": "در حال اتصال…", "cw_status_offline": "متصل نیست", "cw_hints_label": "دکمه‌های دسته", +"cw_task_from_console": "از این کنسول", +"cw_task_from_pc": "از رایانه", +"cw_dialog_cancel": "لغو", +"cw_home_kind_upload": "بارگذاری", +"cw_home_kind_download": "بارگیری", +"cw_home_kind_copy": "کپی", +"cw_home_kind_op": "عملیات فایل", +"cw_home_kind_other": "کار", +"cw_home_progress_bytes": "{done} از {total}", +"cw_home_progress_files": "{done} از {total} فایل", +"cw_home_percent": "{n}٪", +"cw_home_state_running": "در حال اجرا", +"cw_home_state_done": "انجام شد", +"cw_home_state_failed": "ناموفق", +"cw_home_cancel_task": "لغو", +"cw_home_vol_internal": "حافظه داخلی", +"cw_home_vol_usb": "درایو USB", +"cw_home_vol_usb_ext": "حافظه توسعه‌یافته USB", +"cw_home_vol_m2": "حافظه M.2", +"cw_home_vol_ext": "حافظه توسعه‌یافته", +"cw_home_vol_readonly": "فقط‌خواندنی", +"cw_home_free_of": "{free} آزاد از {total}", +"cw_home_err_offline": "کنسول پاسخ نداد. دوباره تلاش کنید.", +"cw_home_err_busy": "کنسول مشغول است. کمی بعد دوباره تلاش کنید.", +"cw_home_err_gone": "این کار قبلاً تمام شده است.", +"cw_home_err_failed": "انجام نشد ({code}).", +"cw_home_err_load_tasks": "فهرست کارها خوانده نشد.", +"cw_home_err_load_storage": "درایوها خوانده نشدند.", +"cw_home_rest_sent": "کنسول به حالت استراحت می‌رود.", +"cw_home_restart_sent": "کنسول در حال راه‌اندازی مجدد است. وقتی برگشت این صفحه را دوباره بارگذاری کنید.", +"cw_home_confirm_cancel_title": "این کار لغو شود؟", +"cw_home_confirm_cancel_body": "همین حالا متوقف می‌شود. این کار برگشت‌پذیر نیست.", +"cw_home_confirm_cancel_body_pc": "این کار را یک رایانه شروع کرده است. روی رایانه هم متوقف می‌شود.", +"cw_home_cancel_task_confirm": "لغو کار", +"cw_home_keep_task": "ادامه بده", +"cw_home_confirm_close_title": "{name} بسته شود؟", +"cw_home_confirm_close_body": "پیشرفت ذخیره‌نشده در بازی از بین می‌رود.", +"cw_home_close_game": "بستن بازی", +"cw_home_confirm_rest_title": "کنسول به حالت استراحت برود؟", +"cw_home_confirm_rest_body": "این صفحه تا بیدار شدن کنسول قطع می‌شود.", +"cw_home_rest": "حالت استراحت", +"cw_home_confirm_restart_title": "کنسول دوباره راه‌اندازی شود؟", +"cw_home_confirm_restart_body": "بازی‌ها و کارهای در حال اجرا متوقف می‌شوند. این صفحه تا برگشتن کنسول قطع می‌شود.", +"cw_home_restart": "راه‌اندازی مجدد", +"cw_home_loading": "در حال بارگذاری…", +"cw_home_no_tasks": "در حال حاضر کاری نیست.", +"cw_home_quick": "اقدامات سریع", +"cw_home_browse_usb": "مرور USB", +"cw_home_now_running": "در حال اجرا", +"cw_home_no_game": "هیچ بازی‌ای در حال اجرا نیست.", +"cw_home_tasks": "کارها", +"cw_home_storage": "حافظه", }; export default fa; diff --git a/client/src/i18n/locales/fr.ts b/client/src/i18n/locales/fr.ts index 05c7917e..b777c882 100644 --- a/client/src/i18n/locales/fr.ts +++ b/client/src/i18n/locales/fr.ts @@ -4064,6 +4064,58 @@ c2c_test_deep_bad: "L’envoi test de 4 Kio n’est pas arrivé : {detail}", "cw_status_connecting": "Connexion…", "cw_status_offline": "Non connecté", "cw_hints_label": "Boutons de la manette", +"cw_task_from_console": "Depuis cette console", +"cw_task_from_pc": "Depuis un PC", +"cw_dialog_cancel": "Annuler", +"cw_home_kind_upload": "Envoi", +"cw_home_kind_download": "Téléchargement", +"cw_home_kind_copy": "Copie", +"cw_home_kind_op": "Opération sur les fichiers", +"cw_home_kind_other": "Tâche", +"cw_home_progress_bytes": "{done} sur {total}", +"cw_home_progress_files": "{done} fichiers sur {total}", +"cw_home_percent": "{n} %", +"cw_home_state_running": "En cours", +"cw_home_state_done": "Terminé", +"cw_home_state_failed": "Échec", +"cw_home_cancel_task": "Annuler", +"cw_home_vol_internal": "Stockage interne", +"cw_home_vol_usb": "Clé USB", +"cw_home_vol_usb_ext": "Stockage étendu USB", +"cw_home_vol_m2": "Stockage M.2", +"cw_home_vol_ext": "Stockage étendu", +"cw_home_vol_readonly": "Lecture seule", +"cw_home_free_of": "{free} libres sur {total}", +"cw_home_err_offline": "La console n'a pas répondu. Réessayez.", +"cw_home_err_busy": "La console est occupée. Réessayez dans un instant.", +"cw_home_err_gone": "Cette tâche est déjà terminée.", +"cw_home_err_failed": "Cela n'a pas fonctionné ({code}).", +"cw_home_err_load_tasks": "Impossible de lire la liste des tâches.", +"cw_home_err_load_storage": "Impossible de lire les disques.", +"cw_home_rest_sent": "La console passe en mode repos.", +"cw_home_restart_sent": "La console redémarre. Rechargez cette page quand elle sera revenue.", +"cw_home_confirm_cancel_title": "Annuler cette tâche ?", +"cw_home_confirm_cancel_body": "Elle s'arrête maintenant. Cette action est irréversible.", +"cw_home_confirm_cancel_body_pc": "Un PC a lancé cette tâche. Elle s'arrête aussi sur le PC.", +"cw_home_cancel_task_confirm": "Annuler la tâche", +"cw_home_keep_task": "Continuer", +"cw_home_confirm_close_title": "Fermer {name} ?", +"cw_home_confirm_close_body": "La progression non sauvegardée du jeu sera perdue.", +"cw_home_close_game": "Fermer le jeu", +"cw_home_confirm_rest_title": "Mettre la console en mode repos ?", +"cw_home_confirm_rest_body": "Cette page est déconnectée jusqu'au réveil de la console.", +"cw_home_rest": "Mode repos", +"cw_home_confirm_restart_title": "Redémarrer la console ?", +"cw_home_confirm_restart_body": "Les jeux et tâches en cours s'arrêtent. Cette page est déconnectée jusqu'au retour de la console.", +"cw_home_restart": "Redémarrer", +"cw_home_loading": "Chargement…", +"cw_home_no_tasks": "Aucune tâche pour le moment.", +"cw_home_quick": "Actions rapides", +"cw_home_browse_usb": "Parcourir l'USB", +"cw_home_now_running": "En cours d'exécution", +"cw_home_no_game": "Aucun jeu en cours.", +"cw_home_tasks": "Tâches", +"cw_home_storage": "Stockage", }; export default fr; diff --git a/client/src/i18n/locales/hi.ts b/client/src/i18n/locales/hi.ts index 3c42479d..3f8fd996 100644 --- a/client/src/i18n/locales/hi.ts +++ b/client/src/i18n/locales/hi.ts @@ -4062,6 +4062,58 @@ c2c_test_deep_bad: "4 KiB का परीक्षण नहीं पहुँ "cw_status_connecting": "कनेक्ट हो रहा है…", "cw_status_offline": "कनेक्ट नहीं है", "cw_hints_label": "कंट्रोलर के बटन", +"cw_task_from_console": "इस कंसोल से", +"cw_task_from_pc": "PC से", +"cw_dialog_cancel": "रद्द करें", +"cw_home_kind_upload": "अपलोड", +"cw_home_kind_download": "डाउनलोड", +"cw_home_kind_copy": "कॉपी", +"cw_home_kind_op": "फ़ाइल कार्रवाई", +"cw_home_kind_other": "कार्य", +"cw_home_progress_bytes": "{total} में से {done}", +"cw_home_progress_files": "{total} में से {done} फ़ाइलें", +"cw_home_percent": "{n}%", +"cw_home_state_running": "चल रहा है", +"cw_home_state_done": "पूरा हुआ", +"cw_home_state_failed": "विफल", +"cw_home_cancel_task": "रद्द करें", +"cw_home_vol_internal": "आंतरिक स्टोरेज", +"cw_home_vol_usb": "USB ड्राइव", +"cw_home_vol_usb_ext": "USB विस्तारित स्टोरेज", +"cw_home_vol_m2": "M.2 स्टोरेज", +"cw_home_vol_ext": "विस्तारित स्टोरेज", +"cw_home_vol_readonly": "केवल पढ़ने योग्य", +"cw_home_free_of": "{total} में से {free} खाली", +"cw_home_err_offline": "कंसोल ने जवाब नहीं दिया। फिर से कोशिश करें।", +"cw_home_err_busy": "कंसोल व्यस्त है। थोड़ी देर बाद फिर से कोशिश करें।", +"cw_home_err_gone": "वह कार्य पहले ही खत्म हो चुका है।", +"cw_home_err_failed": "यह काम नहीं किया ({code})।", +"cw_home_err_load_tasks": "कार्य सूची पढ़ी नहीं जा सकी।", +"cw_home_err_load_storage": "ड्राइव पढ़ी नहीं जा सकीं।", +"cw_home_rest_sent": "कंसोल रेस्ट मोड में जा रहा है।", +"cw_home_restart_sent": "कंसोल फिर से शुरू हो रहा है। वापस आने पर यह पेज फिर से लोड करें।", +"cw_home_confirm_cancel_title": "यह कार्य रद्द करें?", +"cw_home_confirm_cancel_body": "यह अभी रुक जाएगा। इसे पूर्ववत नहीं किया जा सकता।", +"cw_home_confirm_cancel_body_pc": "यह कार्य एक PC ने शुरू किया था। यह PC पर भी रुक जाएगा।", +"cw_home_cancel_task_confirm": "कार्य रद्द करें", +"cw_home_keep_task": "चलने दें", +"cw_home_confirm_close_title": "{name} बंद करें?", +"cw_home_confirm_close_body": "गेम की बिना सहेजी प्रगति खो जाएगी।", +"cw_home_close_game": "गेम बंद करें", +"cw_home_confirm_rest_title": "कंसोल को रेस्ट मोड में डालें?", +"cw_home_confirm_rest_body": "कंसोल के जागने तक यह पेज डिस्कनेक्ट रहेगा।", +"cw_home_rest": "रेस्ट मोड", +"cw_home_confirm_restart_title": "कंसोल फिर से शुरू करें?", +"cw_home_confirm_restart_body": "चल रहे गेम और कार्य रुक जाएंगे। कंसोल के वापस आने तक यह पेज डिस्कनेक्ट रहेगा।", +"cw_home_restart": "फिर से शुरू करें", +"cw_home_loading": "लोड हो रहा है…", +"cw_home_no_tasks": "अभी कोई कार्य नहीं है।", +"cw_home_quick": "त्वरित कार्रवाइयाँ", +"cw_home_browse_usb": "USB ब्राउज़ करें", +"cw_home_now_running": "अभी चल रहा है", +"cw_home_no_game": "कोई गेम नहीं चल रहा है।", +"cw_home_tasks": "कार्य", +"cw_home_storage": "स्टोरेज", }; export default hi; diff --git a/client/src/i18n/locales/hu.ts b/client/src/i18n/locales/hu.ts index 1517c1f9..bdbb380d 100644 --- a/client/src/i18n/locales/hu.ts +++ b/client/src/i18n/locales/hu.ts @@ -4361,6 +4361,58 @@ c2c_test_deep_bad: "A 4 KiB-os tesztküldés nem érkezett meg: {detail}", "cw_status_connecting": "Kapcsolódás…", "cw_status_offline": "Nincs kapcsolat", "cw_hints_label": "Kontroller gombjai", +"cw_task_from_console": "Erről a konzolról", +"cw_task_from_pc": "Egy PC-ről", +"cw_dialog_cancel": "Mégse", +"cw_home_kind_upload": "Feltöltés", +"cw_home_kind_download": "Letöltés", +"cw_home_kind_copy": "Másolás", +"cw_home_kind_op": "Fájlművelet", +"cw_home_kind_other": "Feladat", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} fájl", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Folyamatban", +"cw_home_state_done": "Kész", +"cw_home_state_failed": "Sikertelen", +"cw_home_cancel_task": "Megszakítás", +"cw_home_vol_internal": "Belső tárhely", +"cw_home_vol_usb": "USB-meghajtó", +"cw_home_vol_usb_ext": "USB bővített tárhely", +"cw_home_vol_m2": "M.2 tárhely", +"cw_home_vol_ext": "Bővített tárhely", +"cw_home_vol_readonly": "Csak olvasható", +"cw_home_free_of": "{free} szabad / {total}", +"cw_home_err_offline": "A konzol nem válaszolt. Próbáld újra.", +"cw_home_err_busy": "A konzol foglalt. Próbáld újra egy pillanat múlva.", +"cw_home_err_gone": "Ez a feladat már befejeződött.", +"cw_home_err_failed": "Ez nem sikerült ({code}).", +"cw_home_err_load_tasks": "Nem sikerült beolvasni a feladatlistát.", +"cw_home_err_load_storage": "Nem sikerült beolvasni a meghajtókat.", +"cw_home_rest_sent": "A konzol nyugalmi módba lép.", +"cw_home_restart_sent": "A konzol újraindul. Töltsd újra ezt az oldalt, ha újra elérhető.", +"cw_home_confirm_cancel_title": "Megszakítod ezt a feladatot?", +"cw_home_confirm_cancel_body": "Azonnal leáll. Ez nem vonható vissza.", +"cw_home_confirm_cancel_body_pc": "Ezt a feladatot egy PC indította. A PC-n is leáll.", +"cw_home_cancel_task_confirm": "Feladat megszakítása", +"cw_home_keep_task": "Folytatás", +"cw_home_confirm_close_title": "Bezárod: {name}?", +"cw_home_confirm_close_body": "A játékban el nem mentett haladás elvész.", +"cw_home_close_game": "Játék bezárása", +"cw_home_confirm_rest_title": "Nyugalmi módba teszed a konzolt?", +"cw_home_confirm_rest_body": "Ez az oldal a konzol felébredéséig nem kapcsolódik.", +"cw_home_rest": "Nyugalmi mód", +"cw_home_confirm_restart_title": "Újraindítod a konzolt?", +"cw_home_confirm_restart_body": "A futó játékok és feladatok leállnak. Ez az oldal a konzol visszatéréséig nem kapcsolódik.", +"cw_home_restart": "Újraindítás", +"cw_home_loading": "Betöltés…", +"cw_home_no_tasks": "Most nincs feladat.", +"cw_home_quick": "Gyorsműveletek", +"cw_home_browse_usb": "USB tallózása", +"cw_home_now_running": "Most fut", +"cw_home_no_game": "Nem fut játék.", +"cw_home_tasks": "Feladatok", +"cw_home_storage": "Tárhely", }; export default hu; diff --git a/client/src/i18n/locales/id.ts b/client/src/i18n/locales/id.ts index 2f11fc26..5bab4612 100644 --- a/client/src/i18n/locales/id.ts +++ b/client/src/i18n/locales/id.ts @@ -4055,6 +4055,58 @@ c2c_test_deep_bad: "Kiriman uji 4 KiB tidak tiba: {detail}", "cw_status_connecting": "Menghubungkan…", "cw_status_offline": "Tidak terhubung", "cw_hints_label": "Tombol kontroler", +"cw_task_from_console": "Dari konsol ini", +"cw_task_from_pc": "Dari PC", +"cw_dialog_cancel": "Batal", +"cw_home_kind_upload": "Unggah", +"cw_home_kind_download": "Unduh", +"cw_home_kind_copy": "Salin", +"cw_home_kind_op": "Operasi file", +"cw_home_kind_other": "Tugas", +"cw_home_progress_bytes": "{done} dari {total}", +"cw_home_progress_files": "{done} dari {total} file", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Berjalan", +"cw_home_state_done": "Selesai", +"cw_home_state_failed": "Gagal", +"cw_home_cancel_task": "Batalkan", +"cw_home_vol_internal": "Penyimpanan internal", +"cw_home_vol_usb": "Drive USB", +"cw_home_vol_usb_ext": "Penyimpanan tambahan USB", +"cw_home_vol_m2": "Penyimpanan M.2", +"cw_home_vol_ext": "Penyimpanan tambahan", +"cw_home_vol_readonly": "Hanya baca", +"cw_home_free_of": "{free} kosong dari {total}", +"cw_home_err_offline": "Konsol tidak menjawab. Coba lagi.", +"cw_home_err_busy": "Konsol sedang sibuk. Coba lagi sebentar lagi.", +"cw_home_err_gone": "Tugas itu sudah berakhir.", +"cw_home_err_failed": "Itu tidak berhasil ({code}).", +"cw_home_err_load_tasks": "Tidak dapat membaca daftar tugas.", +"cw_home_err_load_storage": "Tidak dapat membaca drive.", +"cw_home_rest_sent": "Konsol masuk ke mode istirahat.", +"cw_home_restart_sent": "Konsol sedang memulai ulang. Muat ulang halaman ini setelah konsol kembali.", +"cw_home_confirm_cancel_title": "Batalkan tugas ini?", +"cw_home_confirm_cancel_body": "Tugas berhenti sekarang. Ini tidak bisa dibatalkan.", +"cw_home_confirm_cancel_body_pc": "Tugas ini dimulai dari PC. Tugas juga berhenti di PC.", +"cw_home_cancel_task_confirm": "Batalkan tugas", +"cw_home_keep_task": "Lanjutkan", +"cw_home_confirm_close_title": "Tutup {name}?", +"cw_home_confirm_close_body": "Progres game yang belum disimpan akan hilang.", +"cw_home_close_game": "Tutup game", +"cw_home_confirm_rest_title": "Masukkan konsol ke mode istirahat?", +"cw_home_confirm_rest_body": "Halaman ini terputus sampai konsol bangun.", +"cw_home_rest": "Mode istirahat", +"cw_home_confirm_restart_title": "Mulai ulang konsol?", +"cw_home_confirm_restart_body": "Game dan tugas yang berjalan akan berhenti. Halaman ini terputus sampai konsol kembali.", +"cw_home_restart": "Mulai ulang", +"cw_home_loading": "Memuat…", +"cw_home_no_tasks": "Tidak ada tugas saat ini.", +"cw_home_quick": "Tindakan cepat", +"cw_home_browse_usb": "Jelajahi USB", +"cw_home_now_running": "Sedang berjalan", +"cw_home_no_game": "Tidak ada game yang berjalan.", +"cw_home_tasks": "Tugas", +"cw_home_storage": "Penyimpanan", }; export default id; diff --git a/client/src/i18n/locales/it.ts b/client/src/i18n/locales/it.ts index efee2017..d51e0663 100644 --- a/client/src/i18n/locales/it.ts +++ b/client/src/i18n/locales/it.ts @@ -3996,6 +3996,58 @@ c2c_test_deep_bad: "L’invio di prova di 4 KiB non è arrivato: {detail}", "cw_status_connecting": "Connessione…", "cw_status_offline": "Non connesso", "cw_hints_label": "Tasti del controller", +"cw_task_from_console": "Da questa console", +"cw_task_from_pc": "Da un PC", +"cw_dialog_cancel": "Annulla", +"cw_home_kind_upload": "Caricamento", +"cw_home_kind_download": "Download", +"cw_home_kind_copy": "Copia", +"cw_home_kind_op": "Operazione sui file", +"cw_home_kind_other": "Attività", +"cw_home_progress_bytes": "{done} di {total}", +"cw_home_progress_files": "{done} di {total} file", +"cw_home_percent": "{n}%", +"cw_home_state_running": "In corso", +"cw_home_state_done": "Completata", +"cw_home_state_failed": "Non riuscita", +"cw_home_cancel_task": "Annulla", +"cw_home_vol_internal": "Memoria interna", +"cw_home_vol_usb": "Unità USB", +"cw_home_vol_usb_ext": "Memoria estesa USB", +"cw_home_vol_m2": "Memoria M.2", +"cw_home_vol_ext": "Memoria estesa", +"cw_home_vol_readonly": "Sola lettura", +"cw_home_free_of": "{free} liberi su {total}", +"cw_home_err_offline": "La console non ha risposto. Riprova.", +"cw_home_err_busy": "La console è occupata. Riprova tra un momento.", +"cw_home_err_gone": "Quell'attività è già terminata.", +"cw_home_err_failed": "Non ha funzionato ({code}).", +"cw_home_err_load_tasks": "Impossibile leggere l'elenco delle attività.", +"cw_home_err_load_storage": "Impossibile leggere le unità.", +"cw_home_rest_sent": "La console sta entrando in modalità riposo.", +"cw_home_restart_sent": "La console si sta riavviando. Ricarica questa pagina quando torna disponibile.", +"cw_home_confirm_cancel_title": "Annullare questa attività?", +"cw_home_confirm_cancel_body": "Si interrompe subito. L'operazione non può essere annullata.", +"cw_home_confirm_cancel_body_pc": "Questa attività è stata avviata da un PC. Si interrompe anche sul PC.", +"cw_home_cancel_task_confirm": "Annulla attività", +"cw_home_keep_task": "Continua", +"cw_home_confirm_close_title": "Chiudere {name}?", +"cw_home_confirm_close_body": "I progressi di gioco non salvati andranno persi.", +"cw_home_close_game": "Chiudi gioco", +"cw_home_confirm_rest_title": "Mettere la console in modalità riposo?", +"cw_home_confirm_rest_body": "Questa pagina resta disconnessa finché la console non si riattiva.", +"cw_home_rest": "Modalità riposo", +"cw_home_confirm_restart_title": "Riavviare la console?", +"cw_home_confirm_restart_body": "Giochi e attività in corso si interrompono. Questa pagina resta disconnessa finché la console non torna disponibile.", +"cw_home_restart": "Riavvia", +"cw_home_loading": "Caricamento…", +"cw_home_no_tasks": "Nessuna attività al momento.", +"cw_home_quick": "Azioni rapide", +"cw_home_browse_usb": "Sfoglia USB", +"cw_home_now_running": "In esecuzione", +"cw_home_no_game": "Nessun gioco in esecuzione.", +"cw_home_tasks": "Attività", +"cw_home_storage": "Archiviazione", }; export default it; diff --git a/client/src/i18n/locales/ja.ts b/client/src/i18n/locales/ja.ts index 15fc2d1f..6f032b81 100644 --- a/client/src/i18n/locales/ja.ts +++ b/client/src/i18n/locales/ja.ts @@ -4067,6 +4067,58 @@ c2c_test_deep_bad: "4 KiB のテスト送信が届きませんでした: {detail "cw_status_connecting": "接続中…", "cw_status_offline": "未接続", "cw_hints_label": "コントローラーのボタン", +"cw_task_from_console": "このコンソールから", +"cw_task_from_pc": "PCから", +"cw_dialog_cancel": "キャンセル", +"cw_home_kind_upload": "アップロード", +"cw_home_kind_download": "ダウンロード", +"cw_home_kind_copy": "コピー", +"cw_home_kind_op": "ファイル操作", +"cw_home_kind_other": "タスク", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} ファイル", +"cw_home_percent": "{n}%", +"cw_home_state_running": "実行中", +"cw_home_state_done": "完了", +"cw_home_state_failed": "失敗", +"cw_home_cancel_task": "キャンセル", +"cw_home_vol_internal": "本体ストレージ", +"cw_home_vol_usb": "USBドライブ", +"cw_home_vol_usb_ext": "USB拡張ストレージ", +"cw_home_vol_m2": "M.2ストレージ", +"cw_home_vol_ext": "拡張ストレージ", +"cw_home_vol_readonly": "読み取り専用", +"cw_home_free_of": "空き {free} / {total}", +"cw_home_err_offline": "コンソールが応答しませんでした。もう一度お試しください。", +"cw_home_err_busy": "コンソールが処理中です。少ししてからもう一度お試しください。", +"cw_home_err_gone": "そのタスクはすでに終了しています。", +"cw_home_err_failed": "うまくいきませんでした({code})。", +"cw_home_err_load_tasks": "タスク一覧を読み込めませんでした。", +"cw_home_err_load_storage": "ドライブを読み込めませんでした。", +"cw_home_rest_sent": "コンソールがレストモードに入ります。", +"cw_home_restart_sent": "コンソールを再起動しています。復帰したらこのページを再読み込みしてください。", +"cw_home_confirm_cancel_title": "このタスクをキャンセルしますか?", +"cw_home_confirm_cancel_body": "すぐに停止します。元に戻せません。", +"cw_home_confirm_cancel_body_pc": "このタスクはPCから開始されました。PC側でも停止します。", +"cw_home_cancel_task_confirm": "タスクをキャンセル", +"cw_home_keep_task": "続ける", +"cw_home_confirm_close_title": "{name} を終了しますか?", +"cw_home_confirm_close_body": "ゲーム内の保存していない進行状況は失われます。", +"cw_home_close_game": "ゲームを終了", +"cw_home_confirm_rest_title": "コンソールをレストモードにしますか?", +"cw_home_confirm_rest_body": "コンソールが復帰するまで、このページは切断されます。", +"cw_home_rest": "レストモード", +"cw_home_confirm_restart_title": "コンソールを再起動しますか?", +"cw_home_confirm_restart_body": "実行中のゲームとタスクは停止します。コンソールが戻るまで、このページは切断されます。", +"cw_home_restart": "再起動", +"cw_home_loading": "読み込み中…", +"cw_home_no_tasks": "現在タスクはありません。", +"cw_home_quick": "クイックアクション", +"cw_home_browse_usb": "USBを参照", +"cw_home_now_running": "実行中", +"cw_home_no_game": "実行中のゲームはありません。", +"cw_home_tasks": "タスク", +"cw_home_storage": "ストレージ", }; export default ja; diff --git a/client/src/i18n/locales/ko.ts b/client/src/i18n/locales/ko.ts index e496d38d..2e7adaa9 100644 --- a/client/src/i18n/locales/ko.ts +++ b/client/src/i18n/locales/ko.ts @@ -4065,6 +4065,58 @@ c2c_test_deep_bad: "4 KiB 테스트 전송이 도착하지 않았습니다: {det "cw_status_connecting": "연결 중…", "cw_status_offline": "연결되지 않음", "cw_hints_label": "컨트롤러 버튼", +"cw_task_from_console": "이 콘솔에서", +"cw_task_from_pc": "PC에서", +"cw_dialog_cancel": "취소", +"cw_home_kind_upload": "업로드", +"cw_home_kind_download": "다운로드", +"cw_home_kind_copy": "복사", +"cw_home_kind_op": "파일 작업", +"cw_home_kind_other": "작업", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total}개 파일", +"cw_home_percent": "{n}%", +"cw_home_state_running": "진행 중", +"cw_home_state_done": "완료", +"cw_home_state_failed": "실패", +"cw_home_cancel_task": "취소", +"cw_home_vol_internal": "내부 저장소", +"cw_home_vol_usb": "USB 드라이브", +"cw_home_vol_usb_ext": "USB 확장 저장소", +"cw_home_vol_m2": "M.2 저장소", +"cw_home_vol_ext": "확장 저장소", +"cw_home_vol_readonly": "읽기 전용", +"cw_home_free_of": "{total} 중 {free} 남음", +"cw_home_err_offline": "콘솔이 응답하지 않았습니다. 다시 시도하세요.", +"cw_home_err_busy": "콘솔이 사용 중입니다. 잠시 후 다시 시도하세요.", +"cw_home_err_gone": "이 작업은 이미 끝났습니다.", +"cw_home_err_failed": "실패했습니다({code}).", +"cw_home_err_load_tasks": "작업 목록을 읽을 수 없습니다.", +"cw_home_err_load_storage": "드라이브를 읽을 수 없습니다.", +"cw_home_rest_sent": "콘솔이 휴식 모드로 전환됩니다.", +"cw_home_restart_sent": "콘솔을 다시 시작하는 중입니다. 다시 켜지면 이 페이지를 새로 고치세요.", +"cw_home_confirm_cancel_title": "이 작업을 취소할까요?", +"cw_home_confirm_cancel_body": "지금 바로 멈춥니다. 되돌릴 수 없습니다.", +"cw_home_confirm_cancel_body_pc": "PC에서 시작한 작업입니다. PC에서도 멈춥니다.", +"cw_home_cancel_task_confirm": "작업 취소", +"cw_home_keep_task": "계속 진행", +"cw_home_confirm_close_title": "{name}을(를) 닫을까요?", +"cw_home_confirm_close_body": "게임에서 저장하지 않은 진행 상황은 사라집니다.", +"cw_home_close_game": "게임 닫기", +"cw_home_confirm_rest_title": "콘솔을 휴식 모드로 전환할까요?", +"cw_home_confirm_rest_body": "콘솔이 깨어날 때까지 이 페이지는 연결이 끊깁니다.", +"cw_home_rest": "휴식 모드", +"cw_home_confirm_restart_title": "콘솔을 다시 시작할까요?", +"cw_home_confirm_restart_body": "실행 중인 게임과 작업이 멈춥니다. 콘솔이 다시 켜질 때까지 이 페이지는 연결이 끊깁니다.", +"cw_home_restart": "다시 시작", +"cw_home_loading": "불러오는 중…", +"cw_home_no_tasks": "현재 작업이 없습니다.", +"cw_home_quick": "빠른 작업", +"cw_home_browse_usb": "USB 탐색", +"cw_home_now_running": "실행 중", +"cw_home_no_game": "실행 중인 게임이 없습니다.", +"cw_home_tasks": "작업", +"cw_home_storage": "저장소", }; export default ko; diff --git a/client/src/i18n/locales/pl.ts b/client/src/i18n/locales/pl.ts index cb94e10f..c8d96c40 100644 --- a/client/src/i18n/locales/pl.ts +++ b/client/src/i18n/locales/pl.ts @@ -4301,6 +4301,58 @@ c2c_test_deep_bad: "Testowa wysyłka 4 KiB nie dotarła: {detail}", "cw_status_connecting": "Łączenie…", "cw_status_offline": "Brak połączenia", "cw_hints_label": "Przyciski kontrolera", +"cw_task_from_console": "Z tej konsoli", +"cw_task_from_pc": "Z komputera", +"cw_dialog_cancel": "Anuluj", +"cw_home_kind_upload": "Wysyłanie", +"cw_home_kind_download": "Pobieranie", +"cw_home_kind_copy": "Kopiowanie", +"cw_home_kind_op": "Operacja na plikach", +"cw_home_kind_other": "Zadanie", +"cw_home_progress_bytes": "{done} z {total}", +"cw_home_progress_files": "{done} z {total} plików", +"cw_home_percent": "{n}%", +"cw_home_state_running": "W toku", +"cw_home_state_done": "Gotowe", +"cw_home_state_failed": "Niepowodzenie", +"cw_home_cancel_task": "Anuluj", +"cw_home_vol_internal": "Pamięć wewnętrzna", +"cw_home_vol_usb": "Dysk USB", +"cw_home_vol_usb_ext": "Rozszerzona pamięć USB", +"cw_home_vol_m2": "Pamięć M.2", +"cw_home_vol_ext": "Rozszerzona pamięć", +"cw_home_vol_readonly": "Tylko do odczytu", +"cw_home_free_of": "{free} wolne z {total}", +"cw_home_err_offline": "Konsola nie odpowiedziała. Spróbuj ponownie.", +"cw_home_err_busy": "Konsola jest zajęta. Spróbuj ponownie za chwilę.", +"cw_home_err_gone": "To zadanie już się zakończyło.", +"cw_home_err_failed": "Nie udało się ({code}).", +"cw_home_err_load_tasks": "Nie udało się odczytać listy zadań.", +"cw_home_err_load_storage": "Nie udało się odczytać dysków.", +"cw_home_rest_sent": "Konsola przechodzi w tryb odpoczynku.", +"cw_home_restart_sent": "Konsola uruchamia się ponownie. Przeładuj tę stronę, gdy wróci.", +"cw_home_confirm_cancel_title": "Anulować to zadanie?", +"cw_home_confirm_cancel_body": "Zatrzyma się teraz. Tego nie można cofnąć.", +"cw_home_confirm_cancel_body_pc": "To zadanie uruchomił komputer. Zatrzyma się także na komputerze.", +"cw_home_cancel_task_confirm": "Anuluj zadanie", +"cw_home_keep_task": "Kontynuuj", +"cw_home_confirm_close_title": "Zamknąć {name}?", +"cw_home_confirm_close_body": "Niezapisane postępy w grze zostaną utracone.", +"cw_home_close_game": "Zamknij grę", +"cw_home_confirm_rest_title": "Przełączyć konsolę w tryb odpoczynku?", +"cw_home_confirm_rest_body": "Ta strona będzie rozłączona, dopóki konsola się nie wybudzi.", +"cw_home_rest": "Tryb odpoczynku", +"cw_home_confirm_restart_title": "Uruchomić konsolę ponownie?", +"cw_home_confirm_restart_body": "Uruchomione gry i zadania zostaną zatrzymane. Ta strona będzie rozłączona, dopóki konsola nie wróci.", +"cw_home_restart": "Uruchom ponownie", +"cw_home_loading": "Wczytywanie…", +"cw_home_no_tasks": "Brak zadań.", +"cw_home_quick": "Szybkie akcje", +"cw_home_browse_usb": "Przeglądaj USB", +"cw_home_now_running": "Teraz uruchomione", +"cw_home_no_game": "Żadna gra nie jest uruchomiona.", +"cw_home_tasks": "Zadania", +"cw_home_storage": "Pamięć", }; export default pl; diff --git a/client/src/i18n/locales/pt-BR.ts b/client/src/i18n/locales/pt-BR.ts index ee698d2b..ae863edf 100644 --- a/client/src/i18n/locales/pt-BR.ts +++ b/client/src/i18n/locales/pt-BR.ts @@ -4063,6 +4063,58 @@ c2c_test_deep_bad: "O envio de teste de 4 KiB não chegou: {detail}", "cw_status_connecting": "Conectando…", "cw_status_offline": "Não conectado", "cw_hints_label": "Botões do controle", +"cw_task_from_console": "Deste console", +"cw_task_from_pc": "De um PC", +"cw_dialog_cancel": "Cancelar", +"cw_home_kind_upload": "Envio", +"cw_home_kind_download": "Download", +"cw_home_kind_copy": "Cópia", +"cw_home_kind_op": "Operação de arquivos", +"cw_home_kind_other": "Tarefa", +"cw_home_progress_bytes": "{done} de {total}", +"cw_home_progress_files": "{done} de {total} arquivos", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Em andamento", +"cw_home_state_done": "Concluída", +"cw_home_state_failed": "Falhou", +"cw_home_cancel_task": "Cancelar", +"cw_home_vol_internal": "Armazenamento interno", +"cw_home_vol_usb": "Unidade USB", +"cw_home_vol_usb_ext": "Armazenamento estendido USB", +"cw_home_vol_m2": "Armazenamento M.2", +"cw_home_vol_ext": "Armazenamento estendido", +"cw_home_vol_readonly": "Somente leitura", +"cw_home_free_of": "{free} livres de {total}", +"cw_home_err_offline": "O console não respondeu. Tente novamente.", +"cw_home_err_busy": "O console está ocupado. Tente novamente em instantes.", +"cw_home_err_gone": "Essa tarefa já terminou.", +"cw_home_err_failed": "Não deu certo ({code}).", +"cw_home_err_load_tasks": "Não foi possível ler a lista de tarefas.", +"cw_home_err_load_storage": "Não foi possível ler as unidades.", +"cw_home_rest_sent": "O console está entrando no modo de descanso.", +"cw_home_restart_sent": "O console está reiniciando. Recarregue esta página quando ele voltar.", +"cw_home_confirm_cancel_title": "Cancelar esta tarefa?", +"cw_home_confirm_cancel_body": "Ela para agora. Isso não pode ser desfeito.", +"cw_home_confirm_cancel_body_pc": "Um PC iniciou esta tarefa. Ela também para no PC.", +"cw_home_cancel_task_confirm": "Cancelar tarefa", +"cw_home_keep_task": "Continuar", +"cw_home_confirm_close_title": "Fechar {name}?", +"cw_home_confirm_close_body": "O progresso não salvo no jogo será perdido.", +"cw_home_close_game": "Fechar jogo", +"cw_home_confirm_rest_title": "Colocar o console no modo de descanso?", +"cw_home_confirm_rest_body": "Esta página fica desconectada até o console despertar.", +"cw_home_rest": "Modo de descanso", +"cw_home_confirm_restart_title": "Reiniciar o console?", +"cw_home_confirm_restart_body": "Jogos e tarefas em andamento param. Esta página fica desconectada até o console voltar.", +"cw_home_restart": "Reiniciar", +"cw_home_loading": "Carregando…", +"cw_home_no_tasks": "Nenhuma tarefa no momento.", +"cw_home_quick": "Ações rápidas", +"cw_home_browse_usb": "Navegar no USB", +"cw_home_now_running": "Em execução", +"cw_home_no_game": "Nenhum jogo em execução.", +"cw_home_tasks": "Tarefas", +"cw_home_storage": "Armazenamento", }; export default pt_BR; diff --git a/client/src/i18n/locales/ru.ts b/client/src/i18n/locales/ru.ts index 44480a33..1adbe3ee 100644 --- a/client/src/i18n/locales/ru.ts +++ b/client/src/i18n/locales/ru.ts @@ -3996,6 +3996,58 @@ c2c_test_deep_bad: "Тестовая отправка 4 КиБ не дошла: "cw_status_connecting": "Подключение…", "cw_status_offline": "Нет подключения", "cw_hints_label": "Кнопки геймпада", +"cw_task_from_console": "С этой консоли", +"cw_task_from_pc": "С ПК", +"cw_dialog_cancel": "Отмена", +"cw_home_kind_upload": "Загрузка на консоль", +"cw_home_kind_download": "Скачивание", +"cw_home_kind_copy": "Копирование", +"cw_home_kind_op": "Операция с файлами", +"cw_home_kind_other": "Задача", +"cw_home_progress_bytes": "{done} из {total}", +"cw_home_progress_files": "{done} из {total} файлов", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Выполняется", +"cw_home_state_done": "Готово", +"cw_home_state_failed": "Ошибка", +"cw_home_cancel_task": "Отменить", +"cw_home_vol_internal": "Внутреннее хранилище", +"cw_home_vol_usb": "USB-накопитель", +"cw_home_vol_usb_ext": "Расширенное хранилище USB", +"cw_home_vol_m2": "Хранилище M.2", +"cw_home_vol_ext": "Расширенное хранилище", +"cw_home_vol_readonly": "Только чтение", +"cw_home_free_of": "Свободно {free} из {total}", +"cw_home_err_offline": "Консоль не ответила. Попробуйте ещё раз.", +"cw_home_err_busy": "Консоль занята. Попробуйте чуть позже.", +"cw_home_err_gone": "Эта задача уже завершилась.", +"cw_home_err_failed": "Не получилось ({code}).", +"cw_home_err_load_tasks": "Не удалось прочитать список задач.", +"cw_home_err_load_storage": "Не удалось прочитать накопители.", +"cw_home_rest_sent": "Консоль переходит в режим покоя.", +"cw_home_restart_sent": "Консоль перезагружается. Обновите эту страницу, когда она снова будет доступна.", +"cw_home_confirm_cancel_title": "Отменить эту задачу?", +"cw_home_confirm_cancel_body": "Она остановится сейчас. Это нельзя отменить.", +"cw_home_confirm_cancel_body_pc": "Эту задачу запустил ПК. На ПК она тоже остановится.", +"cw_home_cancel_task_confirm": "Отменить задачу", +"cw_home_keep_task": "Продолжить", +"cw_home_confirm_close_title": "Закрыть {name}?", +"cw_home_confirm_close_body": "Несохранённый прогресс в игре будет потерян.", +"cw_home_close_game": "Закрыть игру", +"cw_home_confirm_rest_title": "Перевести консоль в режим покоя?", +"cw_home_confirm_rest_body": "Страница будет отключена, пока консоль не проснётся.", +"cw_home_rest": "Режим покоя", +"cw_home_confirm_restart_title": "Перезагрузить консоль?", +"cw_home_confirm_restart_body": "Запущенные игры и задачи остановятся. Страница будет отключена, пока консоль не вернётся.", +"cw_home_restart": "Перезагрузить", +"cw_home_loading": "Загрузка…", +"cw_home_no_tasks": "Сейчас задач нет.", +"cw_home_quick": "Быстрые действия", +"cw_home_browse_usb": "Открыть USB", +"cw_home_now_running": "Сейчас запущено", +"cw_home_no_game": "Игра не запущена.", +"cw_home_tasks": "Задачи", +"cw_home_storage": "Хранилище", }; export default ru; diff --git a/client/src/i18n/locales/th.ts b/client/src/i18n/locales/th.ts index 589ce64c..b20daf69 100644 --- a/client/src/i18n/locales/th.ts +++ b/client/src/i18n/locales/th.ts @@ -4055,6 +4055,58 @@ c2c_test_deep_bad: "การส่งทดสอบ 4 KiB ไปไม่ถ "cw_status_connecting": "กำลังเชื่อมต่อ…", "cw_status_offline": "ไม่ได้เชื่อมต่อ", "cw_hints_label": "ปุ่มคอนโทรลเลอร์", +"cw_task_from_console": "จากคอนโซลนี้", +"cw_task_from_pc": "จาก PC", +"cw_dialog_cancel": "ยกเลิก", +"cw_home_kind_upload": "อัปโหลด", +"cw_home_kind_download": "ดาวน์โหลด", +"cw_home_kind_copy": "คัดลอก", +"cw_home_kind_op": "การจัดการไฟล์", +"cw_home_kind_other": "งาน", +"cw_home_progress_bytes": "{done} จาก {total}", +"cw_home_progress_files": "{done} จาก {total} ไฟล์", +"cw_home_percent": "{n}%", +"cw_home_state_running": "กำลังทำงาน", +"cw_home_state_done": "เสร็จแล้ว", +"cw_home_state_failed": "ล้มเหลว", +"cw_home_cancel_task": "ยกเลิก", +"cw_home_vol_internal": "ที่เก็บข้อมูลภายใน", +"cw_home_vol_usb": "ไดรฟ์ USB", +"cw_home_vol_usb_ext": "ที่เก็บข้อมูลเสริม USB", +"cw_home_vol_m2": "ที่เก็บข้อมูล M.2", +"cw_home_vol_ext": "ที่เก็บข้อมูลเสริม", +"cw_home_vol_readonly": "อ่านอย่างเดียว", +"cw_home_free_of": "ว่าง {free} จาก {total}", +"cw_home_err_offline": "คอนโซลไม่ตอบสนอง ลองอีกครั้ง", +"cw_home_err_busy": "คอนโซลไม่ว่าง ลองอีกครั้งในอีกสักครู่", +"cw_home_err_gone": "งานนั้นสิ้นสุดไปแล้ว", +"cw_home_err_failed": "ไม่สำเร็จ ({code})", +"cw_home_err_load_tasks": "อ่านรายการงานไม่ได้", +"cw_home_err_load_storage": "อ่านไดรฟ์ไม่ได้", +"cw_home_rest_sent": "คอนโซลกำลังเข้าสู่โหมดพัก", +"cw_home_restart_sent": "คอนโซลกำลังรีสตาร์ท โหลดหน้านี้ใหม่เมื่อกลับมาแล้ว", +"cw_home_confirm_cancel_title": "ยกเลิกงานนี้ไหม", +"cw_home_confirm_cancel_body": "งานจะหยุดทันทีและย้อนกลับไม่ได้", +"cw_home_confirm_cancel_body_pc": "งานนี้เริ่มจาก PC และจะหยุดบน PC ด้วย", +"cw_home_cancel_task_confirm": "ยกเลิกงาน", +"cw_home_keep_task": "ทำงานต่อ", +"cw_home_confirm_close_title": "ปิด {name} ไหม", +"cw_home_confirm_close_body": "ความคืบหน้าในเกมที่ยังไม่ได้บันทึกจะหายไป", +"cw_home_close_game": "ปิดเกม", +"cw_home_confirm_rest_title": "ให้คอนโซลเข้าสู่โหมดพักไหม", +"cw_home_confirm_rest_body": "หน้านี้จะขาดการเชื่อมต่อจนกว่าคอนโซลจะตื่น", +"cw_home_rest": "โหมดพัก", +"cw_home_confirm_restart_title": "รีสตาร์ทคอนโซลไหม", +"cw_home_confirm_restart_body": "เกมและงานที่กำลังทำงานจะหยุด หน้านี้จะขาดการเชื่อมต่อจนกว่าคอนโซลจะกลับมา", +"cw_home_restart": "รีสตาร์ท", +"cw_home_loading": "กำลังโหลด…", +"cw_home_no_tasks": "ตอนนี้ไม่มีงาน", +"cw_home_quick": "การทำงานด่วน", +"cw_home_browse_usb": "เรียกดู USB", +"cw_home_now_running": "กำลังทำงานอยู่", +"cw_home_no_game": "ไม่มีเกมที่กำลังทำงาน", +"cw_home_tasks": "งาน", +"cw_home_storage": "ที่เก็บข้อมูล", }; export default th; diff --git a/client/src/i18n/locales/tr.ts b/client/src/i18n/locales/tr.ts index 699d213c..20575174 100644 --- a/client/src/i18n/locales/tr.ts +++ b/client/src/i18n/locales/tr.ts @@ -4053,6 +4053,58 @@ c2c_test_deep_bad: "4 KiB'lik test gönderimi ulaşmadı: {detail}", "cw_status_connecting": "Bağlanıyor…", "cw_status_offline": "Bağlı değil", "cw_hints_label": "Kumanda düğmeleri", +"cw_task_from_console": "Bu konsoldan", +"cw_task_from_pc": "Bir PC'den", +"cw_dialog_cancel": "İptal", +"cw_home_kind_upload": "Yükleme", +"cw_home_kind_download": "İndirme", +"cw_home_kind_copy": "Kopyalama", +"cw_home_kind_op": "Dosya işlemi", +"cw_home_kind_other": "Görev", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} dosya", +"cw_home_percent": "%{n}", +"cw_home_state_running": "Çalışıyor", +"cw_home_state_done": "Bitti", +"cw_home_state_failed": "Başarısız", +"cw_home_cancel_task": "İptal et", +"cw_home_vol_internal": "Dahili depolama", +"cw_home_vol_usb": "USB sürücü", +"cw_home_vol_usb_ext": "USB genişletilmiş depolama", +"cw_home_vol_m2": "M.2 depolama", +"cw_home_vol_ext": "Genişletilmiş depolama", +"cw_home_vol_readonly": "Salt okunur", +"cw_home_free_of": "{total} alanın {free} kadarı boş", +"cw_home_err_offline": "Konsol yanıt vermedi. Tekrar dene.", +"cw_home_err_busy": "Konsol meşgul. Birazdan tekrar dene.", +"cw_home_err_gone": "Bu görev zaten bitti.", +"cw_home_err_failed": "Bu işe yaramadı ({code}).", +"cw_home_err_load_tasks": "Görev listesi okunamadı.", +"cw_home_err_load_storage": "Sürücüler okunamadı.", +"cw_home_rest_sent": "Konsol dinlenme moduna geçiyor.", +"cw_home_restart_sent": "Konsol yeniden başlıyor. Geri geldiğinde bu sayfayı yenile.", +"cw_home_confirm_cancel_title": "Bu görev iptal edilsin mi?", +"cw_home_confirm_cancel_body": "Hemen durur. Bu geri alınamaz.", +"cw_home_confirm_cancel_body_pc": "Bu görevi bir PC başlattı. PC'de de durur.", +"cw_home_cancel_task_confirm": "Görevi iptal et", +"cw_home_keep_task": "Devam etsin", +"cw_home_confirm_close_title": "{name} kapatılsın mı?", +"cw_home_confirm_close_body": "Oyunda kaydedilmemiş ilerleme kaybolur.", +"cw_home_close_game": "Oyunu kapat", +"cw_home_confirm_rest_title": "Konsol dinlenme moduna alınsın mı?", +"cw_home_confirm_rest_body": "Bu sayfanın bağlantısı konsol uyanana kadar kesilir.", +"cw_home_rest": "Dinlenme modu", +"cw_home_confirm_restart_title": "Konsol yeniden başlatılsın mı?", +"cw_home_confirm_restart_body": "Çalışan oyunlar ve görevler durur. Bu sayfanın bağlantısı konsol geri gelene kadar kesilir.", +"cw_home_restart": "Yeniden başlat", +"cw_home_loading": "Yükleniyor…", +"cw_home_no_tasks": "Şu anda görev yok.", +"cw_home_quick": "Hızlı işlemler", +"cw_home_browse_usb": "USB'ye göz at", +"cw_home_now_running": "Şu anda çalışıyor", +"cw_home_no_game": "Çalışan oyun yok.", +"cw_home_tasks": "Görevler", +"cw_home_storage": "Depolama", }; export default tr; diff --git a/client/src/i18n/locales/vi.ts b/client/src/i18n/locales/vi.ts index 493effa0..24362dd2 100644 --- a/client/src/i18n/locales/vi.ts +++ b/client/src/i18n/locales/vi.ts @@ -4048,6 +4048,58 @@ c2c_test_deep_bad: "Lượt gửi thử 4 KiB không tới: {detail}", "cw_status_connecting": "Đang kết nối…", "cw_status_offline": "Chưa kết nối", "cw_hints_label": "Nút tay cầm", +"cw_task_from_console": "Từ máy này", +"cw_task_from_pc": "Từ PC", +"cw_dialog_cancel": "Hủy", +"cw_home_kind_upload": "Tải lên", +"cw_home_kind_download": "Tải xuống", +"cw_home_kind_copy": "Sao chép", +"cw_home_kind_op": "Thao tác tệp", +"cw_home_kind_other": "Tác vụ", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} tệp", +"cw_home_percent": "{n}%", +"cw_home_state_running": "Đang chạy", +"cw_home_state_done": "Xong", +"cw_home_state_failed": "Thất bại", +"cw_home_cancel_task": "Hủy", +"cw_home_vol_internal": "Bộ nhớ trong", +"cw_home_vol_usb": "Ổ USB", +"cw_home_vol_usb_ext": "Bộ nhớ mở rộng USB", +"cw_home_vol_m2": "Bộ nhớ M.2", +"cw_home_vol_ext": "Bộ nhớ mở rộng", +"cw_home_vol_readonly": "Chỉ đọc", +"cw_home_free_of": "Còn trống {free} / {total}", +"cw_home_err_offline": "Máy không phản hồi. Hãy thử lại.", +"cw_home_err_busy": "Máy đang bận. Hãy thử lại sau giây lát.", +"cw_home_err_gone": "Tác vụ đó đã kết thúc.", +"cw_home_err_failed": "Không thành công ({code}).", +"cw_home_err_load_tasks": "Không đọc được danh sách tác vụ.", +"cw_home_err_load_storage": "Không đọc được các ổ đĩa.", +"cw_home_rest_sent": "Máy đang chuyển sang chế độ nghỉ.", +"cw_home_restart_sent": "Máy đang khởi động lại. Hãy tải lại trang này khi máy hoạt động trở lại.", +"cw_home_confirm_cancel_title": "Hủy tác vụ này?", +"cw_home_confirm_cancel_body": "Tác vụ dừng ngay. Không thể hoàn tác.", +"cw_home_confirm_cancel_body_pc": "Một PC đã bắt đầu tác vụ này. Tác vụ cũng dừng trên PC.", +"cw_home_cancel_task_confirm": "Hủy tác vụ", +"cw_home_keep_task": "Tiếp tục", +"cw_home_confirm_close_title": "Đóng {name}?", +"cw_home_confirm_close_body": "Tiến trình chưa lưu trong game sẽ mất.", +"cw_home_close_game": "Đóng game", +"cw_home_confirm_rest_title": "Đưa máy vào chế độ nghỉ?", +"cw_home_confirm_rest_body": "Trang này mất kết nối cho đến khi máy thức dậy.", +"cw_home_rest": "Chế độ nghỉ", +"cw_home_confirm_restart_title": "Khởi động lại máy?", +"cw_home_confirm_restart_body": "Các game và tác vụ đang chạy sẽ dừng. Trang này mất kết nối cho đến khi máy hoạt động trở lại.", +"cw_home_restart": "Khởi động lại", +"cw_home_loading": "Đang tải…", +"cw_home_no_tasks": "Hiện không có tác vụ nào.", +"cw_home_quick": "Thao tác nhanh", +"cw_home_browse_usb": "Duyệt USB", +"cw_home_now_running": "Đang chạy", +"cw_home_no_game": "Không có game nào đang chạy.", +"cw_home_tasks": "Tác vụ", +"cw_home_storage": "Bộ nhớ", }; export default vi; diff --git a/client/src/i18n/locales/zh-CN.ts b/client/src/i18n/locales/zh-CN.ts index 1cafbb2f..aa8386fc 100644 --- a/client/src/i18n/locales/zh-CN.ts +++ b/client/src/i18n/locales/zh-CN.ts @@ -4002,6 +4002,58 @@ c2c_test_deep_bad: "4 KiB 测试发送未到达:{detail}", "cw_status_connecting": "正在连接…", "cw_status_offline": "未连接", "cw_hints_label": "手柄按键", +"cw_task_from_console": "来自本主机", +"cw_task_from_pc": "来自电脑", +"cw_dialog_cancel": "取消", +"cw_home_kind_upload": "上传", +"cw_home_kind_download": "下载", +"cw_home_kind_copy": "复制", +"cw_home_kind_op": "文件操作", +"cw_home_kind_other": "任务", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} 个文件", +"cw_home_percent": "{n}%", +"cw_home_state_running": "进行中", +"cw_home_state_done": "已完成", +"cw_home_state_failed": "失败", +"cw_home_cancel_task": "取消", +"cw_home_vol_internal": "内置存储", +"cw_home_vol_usb": "USB 驱动器", +"cw_home_vol_usb_ext": "USB 扩展存储", +"cw_home_vol_m2": "M.2 存储", +"cw_home_vol_ext": "扩展存储", +"cw_home_vol_readonly": "只读", +"cw_home_free_of": "可用 {free},共 {total}", +"cw_home_err_offline": "主机没有响应,请重试。", +"cw_home_err_busy": "主机正忙,请稍后重试。", +"cw_home_err_gone": "该任务已经结束。", +"cw_home_err_failed": "操作未成功({code})。", +"cw_home_err_load_tasks": "无法读取任务列表。", +"cw_home_err_load_storage": "无法读取驱动器。", +"cw_home_rest_sent": "主机正在进入待机模式。", +"cw_home_restart_sent": "主机正在重启。恢复后请重新加载此页面。", +"cw_home_confirm_cancel_title": "取消此任务?", +"cw_home_confirm_cancel_body": "任务会立即停止,且无法撤销。", +"cw_home_confirm_cancel_body_pc": "此任务由电脑发起,电脑端也会停止。", +"cw_home_cancel_task_confirm": "取消任务", +"cw_home_keep_task": "继续运行", +"cw_home_confirm_close_title": "关闭 {name}?", +"cw_home_confirm_close_body": "游戏中未保存的进度将丢失。", +"cw_home_close_game": "关闭游戏", +"cw_home_confirm_rest_title": "让主机进入待机模式?", +"cw_home_confirm_rest_body": "主机唤醒前,此页面将断开连接。", +"cw_home_rest": "待机模式", +"cw_home_confirm_restart_title": "重启主机?", +"cw_home_confirm_restart_body": "正在运行的游戏和任务会停止。主机恢复前,此页面将断开连接。", +"cw_home_restart": "重启", +"cw_home_loading": "正在加载…", +"cw_home_no_tasks": "当前没有任务。", +"cw_home_quick": "快捷操作", +"cw_home_browse_usb": "浏览 USB", +"cw_home_now_running": "正在运行", +"cw_home_no_game": "没有正在运行的游戏。", +"cw_home_tasks": "任务", +"cw_home_storage": "存储", }; export default zh_CN; diff --git a/client/src/i18n/locales/zh-TW.ts b/client/src/i18n/locales/zh-TW.ts index f4bf7be7..31946b2f 100644 --- a/client/src/i18n/locales/zh-TW.ts +++ b/client/src/i18n/locales/zh-TW.ts @@ -3996,6 +3996,58 @@ c2c_test_deep_bad: "4 KiB 測試傳送未抵達:{detail}", "cw_status_connecting": "正在連線…", "cw_status_offline": "未連線", "cw_hints_label": "控制器按鍵", +"cw_task_from_console": "來自本主機", +"cw_task_from_pc": "來自電腦", +"cw_dialog_cancel": "取消", +"cw_home_kind_upload": "上傳", +"cw_home_kind_download": "下載", +"cw_home_kind_copy": "複製", +"cw_home_kind_op": "檔案操作", +"cw_home_kind_other": "工作", +"cw_home_progress_bytes": "{done} / {total}", +"cw_home_progress_files": "{done} / {total} 個檔案", +"cw_home_percent": "{n}%", +"cw_home_state_running": "進行中", +"cw_home_state_done": "已完成", +"cw_home_state_failed": "失敗", +"cw_home_cancel_task": "取消", +"cw_home_vol_internal": "內建儲存空間", +"cw_home_vol_usb": "USB 磁碟機", +"cw_home_vol_usb_ext": "USB 延伸儲存空間", +"cw_home_vol_m2": "M.2 儲存空間", +"cw_home_vol_ext": "延伸儲存空間", +"cw_home_vol_readonly": "唯讀", +"cw_home_free_of": "可用 {free},共 {total}", +"cw_home_err_offline": "主機沒有回應,請再試一次。", +"cw_home_err_busy": "主機忙碌中,請稍後再試。", +"cw_home_err_gone": "這項工作已經結束。", +"cw_home_err_failed": "操作未成功({code})。", +"cw_home_err_load_tasks": "無法讀取工作清單。", +"cw_home_err_load_storage": "無法讀取磁碟機。", +"cw_home_rest_sent": "主機正在進入休眠模式。", +"cw_home_restart_sent": "主機正在重新啟動。恢復後請重新載入此頁面。", +"cw_home_confirm_cancel_title": "要取消這項工作嗎?", +"cw_home_confirm_cancel_body": "工作會立即停止,且無法復原。", +"cw_home_confirm_cancel_body_pc": "這項工作由電腦啟動,電腦端也會停止。", +"cw_home_cancel_task_confirm": "取消工作", +"cw_home_keep_task": "繼續執行", +"cw_home_confirm_close_title": "要關閉 {name} 嗎?", +"cw_home_confirm_close_body": "遊戲中未儲存的進度將會遺失。", +"cw_home_close_game": "關閉遊戲", +"cw_home_confirm_rest_title": "要讓主機進入休眠模式嗎?", +"cw_home_confirm_rest_body": "主機喚醒前,此頁面會中斷連線。", +"cw_home_rest": "休眠模式", +"cw_home_confirm_restart_title": "要重新啟動主機嗎?", +"cw_home_confirm_restart_body": "執行中的遊戲和工作會停止。主機恢復前,此頁面會中斷連線。", +"cw_home_restart": "重新啟動", +"cw_home_loading": "載入中…", +"cw_home_no_tasks": "目前沒有工作。", +"cw_home_quick": "快速動作", +"cw_home_browse_usb": "瀏覽 USB", +"cw_home_now_running": "執行中", +"cw_home_no_game": "沒有執行中的遊戲。", +"cw_home_tasks": "工作", +"cw_home_storage": "儲存空間", }; export default zh_TW;