mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-15 23:55:43 -04:00
fix(cron): start manual jobs in the background and report busy jobs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
24 files changed
+373
-40
No files matched your search
@@ -89,13 +89,14 @@ export function getJobSchedules(): {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Manually trigger a job by name. Returns false if job not found or already running. */
|
/** Start a job by name without waiting for it to finish. */
|
||||||
export async function triggerJob(name: string): Promise<boolean> {
|
export function triggerJob(name: string): "started" | "not_found" | "busy" {
|
||||||
const job = jobs.get(name);
|
const job = jobs.get(name);
|
||||||
if (!job) return false;
|
if (!job) return "not_found";
|
||||||
if (job.isBusy()) return false;
|
if (job.isBusy()) return "busy";
|
||||||
await job.trigger();
|
// The scheduled wrapper records the run and catches its errors; don't hold the request open.
|
||||||
return true;
|
void job.trigger();
|
||||||
|
return "started";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh titles where lastFetchedAt is stale
|
// Refresh titles where lastFetchedAt is stale
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { cors } from "hono/cors";
|
|||||||
|
|
||||||
import { CACHE_DIR } from "@sofa/config";
|
import { CACHE_DIR } from "@sofa/config";
|
||||||
import { ensureBackupDir } from "@sofa/core/backup";
|
import { ensureBackupDir } from "@sofa/core/backup";
|
||||||
|
import { recoverInterruptedCronRuns } from "@sofa/core/cron";
|
||||||
import { ensureImageDirs, imageCacheEnabled } from "@sofa/core/image-cache";
|
import { ensureImageDirs, imageCacheEnabled } from "@sofa/core/image-cache";
|
||||||
import { registerJobScheduleProvider } from "@sofa/core/system-health";
|
import { registerJobScheduleProvider } from "@sofa/core/system-health";
|
||||||
import { closeDatabase, isDatabaseAccessBlocked } from "@sofa/db/client";
|
import { closeDatabase, isDatabaseAccessBlocked } from "@sofa/db/client";
|
||||||
@@ -48,6 +49,12 @@ if (recoveredJobs > 0) {
|
|||||||
log.warn(`Recovered ${recoveredJobs} stale import job(s) from previous shutdown`);
|
log.warn(`Recovered ${recoveredJobs} stale import job(s) from previous shutdown`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background job runs left "running" by a previous crash would otherwise look active forever
|
||||||
|
const interruptedRuns = recoverInterruptedCronRuns();
|
||||||
|
if (interruptedRuns > 0) {
|
||||||
|
log.warn(`Marked ${interruptedRuns} interrupted background job run(s) as failed`);
|
||||||
|
}
|
||||||
|
|
||||||
// Payloads of finished imports are never read again; reclaim the space (and keep backups small).
|
// Payloads of finished imports are never read again; reclaim the space (and keep backups small).
|
||||||
const clearedPayloads = clearFinishedImportPayloads();
|
const clearedPayloads = clearFinishedImportPayloads();
|
||||||
if (clearedPayloads > 0) {
|
if (clearedPayloads > 0) {
|
||||||
|
|||||||
@@ -126,14 +126,20 @@ export const backupsUpdateSchedule = os.admin.backups.updateSchedule
|
|||||||
|
|
||||||
// ─── Jobs ─────────────────────────────────────────────────────
|
// ─── Jobs ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const triggerJob = os.admin.triggerJob.use(admin).handler(async ({ input }) => {
|
export const triggerJob = os.admin.triggerJob.use(admin).handler(({ input }) => {
|
||||||
const triggered = await triggerCronJob(input.name);
|
const outcome = triggerCronJob(input.name);
|
||||||
if (!triggered) {
|
if (outcome === "not_found") {
|
||||||
throw new ORPCError("NOT_FOUND", {
|
throw new ORPCError("NOT_FOUND", {
|
||||||
message: "Job not found",
|
message: "Job not found",
|
||||||
data: { code: AppErrorCode.JOB_NOT_FOUND },
|
data: { code: AppErrorCode.JOB_NOT_FOUND },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (outcome === "busy") {
|
||||||
|
throw new ORPCError("CONFLICT", {
|
||||||
|
message: "Job is already running",
|
||||||
|
data: { code: AppErrorCode.JOB_ALREADY_RUNNING },
|
||||||
|
});
|
||||||
|
}
|
||||||
return { ok: true as const };
|
return { ok: true as const };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ import { i18n } from "@sofa/i18n";
|
|||||||
|
|
||||||
const DIGITS_ONLY_RE = /^\d+$/;
|
const DIGITS_ONLY_RE = /^\d+$/;
|
||||||
|
|
||||||
|
/** Scheduled jobs the API does not allow triggering manually. */
|
||||||
|
const NOT_TRIGGERABLE = new Set(["optimizeDb"]);
|
||||||
|
|
||||||
/** Convert a cron pattern to a short human-readable string */
|
/** Convert a cron pattern to a short human-readable string */
|
||||||
function cronToHuman(pattern: string): string {
|
function cronToHuman(pattern: string): string {
|
||||||
const parts = pattern.split(" ");
|
const parts = pattern.split(" ");
|
||||||
@@ -316,6 +319,9 @@ function BackgroundJobsCard({
|
|||||||
cacheImages: t`Image cache`,
|
cacheImages: t`Image cache`,
|
||||||
scheduledBackup: t`Backup`,
|
scheduledBackup: t`Backup`,
|
||||||
updateCheck: t`Update check`,
|
updateCheck: t`Update check`,
|
||||||
|
refreshCredits: t`Cast & crew`,
|
||||||
|
telemetryReport: t`Telemetry`,
|
||||||
|
optimizeDb: t`Database maintenance`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const triggerJobMutation = useMutation(
|
const triggerJobMutation = useMutation(
|
||||||
@@ -483,36 +489,38 @@ function BackgroundJobsCard({
|
|||||||
|
|
||||||
{/* Trigger button */}
|
{/* Trigger button */}
|
||||||
<TableCell className="pe-5 text-end">
|
<TableCell className="pe-5 text-end">
|
||||||
<Tooltip>
|
{!NOT_TRIGGERABLE.has(job.jobName) && (
|
||||||
<TooltipTrigger
|
<Tooltip>
|
||||||
render={
|
<TooltipTrigger
|
||||||
<Button
|
render={
|
||||||
variant="ghost"
|
<Button
|
||||||
size="icon"
|
variant="ghost"
|
||||||
aria-label={t`Trigger job`}
|
size="icon"
|
||||||
className="size-6"
|
aria-label={t`Trigger job`}
|
||||||
disabled={isRunning || job.disabled}
|
className="size-6"
|
||||||
onClick={() =>
|
disabled={isRunning || job.disabled}
|
||||||
triggerJobMutation.mutate({
|
onClick={() =>
|
||||||
name: job.jobName as CronJobName,
|
triggerJobMutation.mutate({
|
||||||
})
|
name: job.jobName as CronJobName,
|
||||||
}
|
})
|
||||||
/>
|
}
|
||||||
}
|
/>
|
||||||
>
|
}
|
||||||
{isRunning ? (
|
>
|
||||||
<Spinner className="size-3" />
|
{isRunning ? (
|
||||||
) : (
|
<Spinner className="size-3" />
|
||||||
<IconPlayerPlay
|
) : (
|
||||||
aria-hidden={true}
|
<IconPlayerPlay
|
||||||
className="text-muted-foreground/70 size-3"
|
aria-hidden={true}
|
||||||
/>
|
className="text-muted-foreground/70 size-3"
|
||||||
)}
|
/>
|
||||||
</TooltipTrigger>
|
)}
|
||||||
<TooltipContent>
|
</TooltipTrigger>
|
||||||
<Trans>Run now</Trans>
|
<TooltipContent>
|
||||||
</TooltipContent>
|
<Trans>Run now</Trans>
|
||||||
</Tooltip>
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6635,6 +6635,77 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "409",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"defined": {
|
||||||
|
"const": true
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"const": "CONFLICT"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"const": 409
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Job is already running"
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"const": "JOB_ALREADY_RUNNING"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"defined",
|
||||||
|
"code",
|
||||||
|
"status",
|
||||||
|
"message",
|
||||||
|
"data"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"defined": {
|
||||||
|
"const": false
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"data": {}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"defined",
|
||||||
|
"code",
|
||||||
|
"status",
|
||||||
|
"message"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
|||||||
@@ -669,6 +669,10 @@ export const contract = {
|
|||||||
message: "Job not found",
|
message: "Job not found",
|
||||||
data: appErrorData(AppErrorCode.JOB_NOT_FOUND),
|
data: appErrorData(AppErrorCode.JOB_NOT_FOUND),
|
||||||
},
|
},
|
||||||
|
CONFLICT: {
|
||||||
|
message: "Job is already running",
|
||||||
|
data: appErrorData(AppErrorCode.JOB_ALREADY_RUNNING),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
purgeMetadataCache: oc
|
purgeMetadataCache: oc
|
||||||
.route({
|
.route({
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const AppErrorCode = {
|
|||||||
BACKUP_DELETE_FAILED: "BACKUP_DELETE_FAILED",
|
BACKUP_DELETE_FAILED: "BACKUP_DELETE_FAILED",
|
||||||
BACKUP_RESTORE_FAILED: "BACKUP_RESTORE_FAILED",
|
BACKUP_RESTORE_FAILED: "BACKUP_RESTORE_FAILED",
|
||||||
JOB_NOT_FOUND: "JOB_NOT_FOUND",
|
JOB_NOT_FOUND: "JOB_NOT_FOUND",
|
||||||
|
JOB_ALREADY_RUNNING: "JOB_ALREADY_RUNNING",
|
||||||
TMDB_NOT_CONFIGURED: "TMDB_NOT_CONFIGURED",
|
TMDB_NOT_CONFIGURED: "TMDB_NOT_CONFIGURED",
|
||||||
IMPORT_INVALID_FILE: "IMPORT_INVALID_FILE",
|
IMPORT_INVALID_FILE: "IMPORT_INVALID_FILE",
|
||||||
IMPORT_PAYLOAD_TOO_LARGE: "IMPORT_PAYLOAD_TOO_LARGE",
|
IMPORT_PAYLOAD_TOO_LARGE: "IMPORT_PAYLOAD_TOO_LARGE",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
getTitleIdsCheckedBefore,
|
getTitleIdsCheckedBefore,
|
||||||
getTitleIdsWithStaleSeasons,
|
getTitleIdsWithStaleSeasons,
|
||||||
insertCronRunReturning,
|
insertCronRunReturning,
|
||||||
|
markInterruptedCronRuns,
|
||||||
updateCronRunError,
|
updateCronRunError,
|
||||||
updateCronRunSuccess,
|
updateCronRunSuccess,
|
||||||
} from "@sofa/db/queries/cron";
|
} from "@sofa/db/queries/cron";
|
||||||
@@ -55,6 +56,11 @@ export function failCronRun(runId: string, durationMs: number, error: unknown):
|
|||||||
updateCronRunError(runId, durationMs, errorMessage);
|
updateCronRunError(runId, durationMs, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mark runs left "running" by a previous process as failed. Returns how many were recovered. */
|
||||||
|
export function recoverInterruptedCronRuns(): number {
|
||||||
|
return markInterruptedCronRuns();
|
||||||
|
}
|
||||||
|
|
||||||
export function getLibraryTitleIds(): string[] {
|
export function getLibraryTitleIds(): string[] {
|
||||||
return queryGetLibraryTitleIds();
|
return queryGetLibraryTitleIds();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { tmdbApiUrl } from "@sofa/tmdb/config";
|
|||||||
import { listBackups } from "./backup";
|
import { listBackups } from "./backup";
|
||||||
import { imageCacheEnabled } from "./image-cache";
|
import { imageCacheEnabled } from "./image-cache";
|
||||||
import { getSetting } from "./settings";
|
import { getSetting } from "./settings";
|
||||||
|
import { isTelemetryEnabled } from "./telemetry";
|
||||||
import { isUpdateCheckEnabled } from "./update-check";
|
import { isUpdateCheckEnabled } from "./update-check";
|
||||||
|
|
||||||
export interface SystemHealthData {
|
export interface SystemHealthData {
|
||||||
@@ -64,6 +65,9 @@ const JOB_NAMES = [
|
|||||||
"cacheImages",
|
"cacheImages",
|
||||||
"scheduledBackup",
|
"scheduledBackup",
|
||||||
"updateCheck",
|
"updateCheck",
|
||||||
|
"refreshCredits",
|
||||||
|
"telemetryReport",
|
||||||
|
"optimizeDb",
|
||||||
];
|
];
|
||||||
|
|
||||||
function getDatabaseHealth(): SystemHealthData["database"] {
|
function getDatabaseHealth(): SystemHealthData["database"] {
|
||||||
@@ -168,7 +172,8 @@ function getJobsHealth(): SystemHealthData["jobs"] {
|
|||||||
|
|
||||||
const disabled =
|
const disabled =
|
||||||
(jobName === "scheduledBackup" && getSetting("scheduledBackups") !== "true") ||
|
(jobName === "scheduledBackup" && getSetting("scheduledBackups") !== "true") ||
|
||||||
(jobName === "updateCheck" && !isUpdateCheckEnabled());
|
(jobName === "updateCheck" && !isUpdateCheckEnabled()) ||
|
||||||
|
(jobName === "telemetryReport" && !isTelemetryEnabled());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
jobName,
|
jobName,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
getStaleLibraryTitles,
|
getStaleLibraryTitles,
|
||||||
getTitleIdsWithStaleSeasons,
|
getTitleIdsWithStaleSeasons,
|
||||||
libraryRefreshIntervalMs,
|
libraryRefreshIntervalMs,
|
||||||
|
recoverInterruptedCronRuns,
|
||||||
runIsolated,
|
runIsolated,
|
||||||
startCronRun,
|
startCronRun,
|
||||||
} from "../src/cron";
|
} from "../src/cron";
|
||||||
@@ -61,6 +62,26 @@ describe("failCronRun", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("recoverInterruptedCronRuns", () => {
|
||||||
|
test("marks only still-running runs as interrupted errors", () => {
|
||||||
|
const open = startCronRun("job-a");
|
||||||
|
const done = startCronRun("job-b");
|
||||||
|
completeCronRun(done.id, 100);
|
||||||
|
|
||||||
|
expect(recoverInterruptedCronRuns()).toBe(1);
|
||||||
|
|
||||||
|
const openRow = testDb.select().from(cronRuns).where(eq(cronRuns.id, open.id)).get();
|
||||||
|
expect(openRow?.status).toBe("error");
|
||||||
|
expect(openRow?.errorMessage).toBe("Interrupted by server restart");
|
||||||
|
expect(openRow?.finishedAt).toBeInstanceOf(Date);
|
||||||
|
|
||||||
|
const doneRow = testDb.select().from(cronRuns).where(eq(cronRuns.id, done.id)).get();
|
||||||
|
expect(doneRow?.status).toBe("success");
|
||||||
|
expect(doneRow?.durationMs).toBe(100);
|
||||||
|
expect(doneRow?.errorMessage).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("runIsolated", () => {
|
describe("runIsolated", () => {
|
||||||
test("continues after a failing item", async () => {
|
test("continues after a failing item", async () => {
|
||||||
const fn = vi.fn<(item: number) => Promise<void>>(async (item) => {
|
const fn = vi.fn<(item: number) => Promise<void>>(async (item) => {
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ export function updateCronRunError(id: string, durationMs: number, errorMessage:
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mark runs left "running" by a previous process as errors (called once at startup). */
|
||||||
|
export function markInterruptedCronRuns(): number {
|
||||||
|
return db
|
||||||
|
.update(cronRuns)
|
||||||
|
.set({ status: "error", finishedAt: new Date(), errorMessage: "Interrupted by server restart" })
|
||||||
|
.where(eq(cronRuns.status, "running"))
|
||||||
|
.returning({ id: cronRuns.id })
|
||||||
|
.all().length;
|
||||||
|
}
|
||||||
|
|
||||||
export function getLibraryTitleIds(): string[] {
|
export function getLibraryTitleIds(): string[] {
|
||||||
return db
|
return db
|
||||||
.select({ titleId: userTitleStatus.titleId })
|
.select({ titleId: userTitleStatus.titleId })
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const APP_ERROR_MESSAGES: Record<AppErrorCode, MessageDescriptor> = {
|
|||||||
BACKUP_DELETE_FAILED: msg`Failed to delete backup`,
|
BACKUP_DELETE_FAILED: msg`Failed to delete backup`,
|
||||||
BACKUP_RESTORE_FAILED: msg`Backup restoration failed`,
|
BACKUP_RESTORE_FAILED: msg`Backup restoration failed`,
|
||||||
JOB_NOT_FOUND: msg`Job not found`,
|
JOB_NOT_FOUND: msg`Job not found`,
|
||||||
|
JOB_ALREADY_RUNNING: msg`This job is already running`,
|
||||||
TMDB_NOT_CONFIGURED: msg`TMDB API key is not configured`,
|
TMDB_NOT_CONFIGURED: msg`TMDB API key is not configured`,
|
||||||
IMPORT_INVALID_FILE: msg`Invalid import file`,
|
IMPORT_INVALID_FILE: msg`Invalid import file`,
|
||||||
IMPORT_PAYLOAD_TOO_LARGE: msg`Import payload is too large`,
|
IMPORT_PAYLOAD_TOO_LARGE: msg`Import payload is too large`,
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "إلغاء التعديل"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "طاقم التمثيل"
|
msgstr "طاقم التمثيل"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "اللحاق"
|
msgstr "اللحاق"
|
||||||
@@ -966,6 +970,10 @@ msgstr "قاعدة البيانات"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "نسخ احتياطية لقاعدة البيانات"
|
msgstr "نسخ احتياطية لقاعدة البيانات"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "تم استعادة قاعدة البيانات. جارٍ إعادة التحميل..."
|
msgstr "تم استعادة قاعدة البيانات. جارٍ إعادة التحميل..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "التبديل إلى {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "يسري بعد إعادة تشغيل التطبيق"
|
msgstr "يسري بعد إعادة تشغيل التطبيق"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "قد يستغرق هذا بضع دقائق للمكتبات الكبيرة. يرجى عدم إغلاق هذا التبويب."
|
msgstr "قد يستغرق هذا بضع دقائق للمكتبات الكبيرة. يرجى عدم إغلاق هذا التبويب."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Bearbeitung abbrechen"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "Besetzung"
|
msgstr "Besetzung"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Aufholen"
|
msgstr "Aufholen"
|
||||||
@@ -966,6 +970,10 @@ msgstr "Datenbank"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Datenbank-Backups"
|
msgstr "Datenbank-Backups"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Datenbank wiederhergestellt. Lade neu..."
|
msgstr "Datenbank wiederhergestellt. Lade neu..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Zu {name} wechseln"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Tritt nach einem Neustart der App in Kraft"
|
msgstr "Tritt nach einem Neustart der App in Kraft"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "Dies kann bei großen Bibliotheken einige Minuten dauern. Bitte schließe diesen Tab nicht."
|
msgstr "Dies kann bei großen Bibliotheken einige Minuten dauern. Bitte schließe diesen Tab nicht."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr ""
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr "Cast & crew"
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -966,6 +970,10 @@ msgstr ""
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr "Database maintenance"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Switch to {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Takes effect after restarting the app"
|
msgstr "Takes effect after restarting the app"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr "Telemetry"
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr "That time is in the future"
|
msgstr "That time is in the future"
|
||||||
@@ -3385,6 +3397,10 @@ msgstr "This doesn't appear to be a Sofa server. Double-check the URL."
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr "This import cannot be cancelled"
|
msgstr "This import cannot be cancelled"
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr "This job is already running"
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Cancelar edición"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "Reparto"
|
msgstr "Reparto"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Ponerse al día"
|
msgstr "Ponerse al día"
|
||||||
@@ -966,6 +970,10 @@ msgstr "Base de datos"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Copias de seguridad de la base de datos"
|
msgstr "Copias de seguridad de la base de datos"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Base de datos restaurada. Recargando..."
|
msgstr "Base de datos restaurada. Recargando..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Cambiar a {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Tendrá efecto tras reiniciar la app"
|
msgstr "Tendrá efecto tras reiniciar la app"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "Esto puede tardar unos minutos para bibliotecas grandes. Por favor, no cierres esta pestaña."
|
msgstr "Esto puede tardar unos minutos para bibliotecas grandes. Por favor, no cierres esta pestaña."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Annuler la modification"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "Distribution"
|
msgstr "Distribution"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Rattraper"
|
msgstr "Rattraper"
|
||||||
@@ -966,6 +970,10 @@ msgstr "Base de données"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Sauvegardes de la base de données"
|
msgstr "Sauvegardes de la base de données"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Base de données restaurée. Rechargement..."
|
msgstr "Base de données restaurée. Rechargement..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Passer à {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Prend effet après le redémarrage de l'application"
|
msgstr "Prend effet après le redémarrage de l'application"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "Cela peut prendre quelques minutes pour les grandes bibliothèques. Ne fermez pas cet onglet."
|
msgstr "Cela peut prendre quelques minutes pour les grandes bibliothèques. Ne fermez pas cet onglet."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "ביטול עריכה"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "שחקנים"
|
msgstr "שחקנים"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "השלם צפייה"
|
msgstr "השלם צפייה"
|
||||||
@@ -966,6 +970,10 @@ msgstr "מסד נתונים"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "גיבויי מסד נתונים"
|
msgstr "גיבויי מסד נתונים"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "מסד הנתונים שוחזר. טוען מחדש..."
|
msgstr "מסד הנתונים שוחזר. טוען מחדש..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "עבור ל-{name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "ייכנס לתוקף לאחר הפעלה מחדש של האפליקציה"
|
msgstr "ייכנס לתוקף לאחר הפעלה מחדש של האפליקציה"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "פעולה זו עשויה לקחת מספר דקות עבור ספריות גדולות. אנא אל תסגור לשונית זו."
|
msgstr "פעולה זו עשויה לקחת מספר דקות עבור ספריות גדולות. אנא אל תסגור לשונית זו."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Annulla modifica"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Recupera episodi"
|
msgstr "Recupera episodi"
|
||||||
@@ -966,6 +970,10 @@ msgstr ""
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Backup del database"
|
msgstr "Backup del database"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Database ripristinato. Ricaricamento..."
|
msgstr "Database ripristinato. Ricaricamento..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Passa a {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Avrà effetto dopo il riavvio dell'app"
|
msgstr "Avrà effetto dopo il riavvio dell'app"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "L'operazione potrebbe richiedere alcuni minuti per librerie grandi. Non chiudere questa scheda."
|
msgstr "L'operazione potrebbe richiedere alcuni minuti per librerie grandi. Non chiudere questa scheda."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "編集をキャンセル"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "キャスト"
|
msgstr "キャスト"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "追いつく"
|
msgstr "追いつく"
|
||||||
@@ -966,6 +970,10 @@ msgstr "データベース"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "データベースバックアップ"
|
msgstr "データベースバックアップ"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "データベースを復元しました。再読み込み中..."
|
msgstr "データベースを復元しました。再読み込み中..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "{name}に切り替え"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "アプリを再起動後に反映されます"
|
msgstr "アプリを再起動後に反映されます"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "大規模なライブラリでは数分かかる場合があります。このタブを閉じないでください。"
|
msgstr "大規模なライブラリでは数分かかる場合があります。このタブを閉じないでください。"
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "편집 취소"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "출연진"
|
msgstr "출연진"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "따라잡기"
|
msgstr "따라잡기"
|
||||||
@@ -966,6 +970,10 @@ msgstr "데이터베이스"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "데이터베이스 백업"
|
msgstr "데이터베이스 백업"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "데이터베이스가 복원되었습니다. 다시 로드 중..."
|
msgstr "데이터베이스가 복원되었습니다. 다시 로드 중..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "{name}(으)로 전환"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "앱을 다시 시작하면 적용됩니다"
|
msgstr "앱을 다시 시작하면 적용됩니다"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "라이브러리가 크면 몇 분 정도 걸릴 수 있습니다. 이 탭을 닫지 마세요."
|
msgstr "라이브러리가 크면 몇 분 정도 걸릴 수 있습니다. 이 탭을 닫지 마세요."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Bewerken annuleren"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Inhalen"
|
msgstr "Inhalen"
|
||||||
@@ -966,6 +970,10 @@ msgstr ""
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Database back-ups"
|
msgstr "Database back-ups"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Database hersteld. Opnieuw laden..."
|
msgstr "Database hersteld. Opnieuw laden..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Overschakelen naar {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Van kracht na het herstarten van de app"
|
msgstr "Van kracht na het herstarten van de app"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "Dit kan een paar minuten duren voor grote bibliotheken. Sluit dit tabblad niet."
|
msgstr "Dit kan een paar minuten duren voor grote bibliotheken. Sluit dit tabblad niet."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "Cancelar edição"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "Elenco"
|
msgstr "Elenco"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "Colocar em dia"
|
msgstr "Colocar em dia"
|
||||||
@@ -966,6 +970,10 @@ msgstr "Banco de Dados"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "Backups do banco de dados"
|
msgstr "Backups do banco de dados"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "Banco de dados restaurado. Recarregando..."
|
msgstr "Banco de dados restaurado. Recarregando..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "Mudar para {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "Entra em vigor após reiniciar a aplicação"
|
msgstr "Entra em vigor após reiniciar a aplicação"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "Isso pode levar alguns minutos para bibliotecas grandes. Por favor, não feche esta aba."
|
msgstr "Isso pode levar alguns minutos para bibliotecas grandes. Por favor, não feche esta aba."
|
||||||
|
|||||||
@@ -589,6 +589,10 @@ msgstr "取消编辑"
|
|||||||
msgid "Cast"
|
msgid "Cast"
|
||||||
msgstr "演员表"
|
msgstr "演员表"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Cast & crew"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/use-title-actions.ts
|
#: apps/web/src/components/titles/use-title-actions.ts
|
||||||
msgid "Catch up"
|
msgid "Catch up"
|
||||||
msgstr "追上"
|
msgstr "追上"
|
||||||
@@ -966,6 +970,10 @@ msgstr "数据库"
|
|||||||
msgid "Database backups"
|
msgid "Database backups"
|
||||||
msgstr "数据库备份"
|
msgstr "数据库备份"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Database maintenance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/backup-restore-section.tsx
|
#: apps/web/src/components/settings/backup-restore-section.tsx
|
||||||
msgid "Database restored. Reloading..."
|
msgid "Database restored. Reloading..."
|
||||||
msgstr "数据库已还原。正在重新加载..."
|
msgstr "数据库已还原。正在重新加载..."
|
||||||
@@ -3353,6 +3361,10 @@ msgstr "切换到 {name}"
|
|||||||
msgid "Takes effect after restarting the app"
|
msgid "Takes effect after restarting the app"
|
||||||
msgstr "重启应用后生效"
|
msgstr "重启应用后生效"
|
||||||
|
|
||||||
|
#: apps/web/src/components/settings/system-health-section.tsx
|
||||||
|
msgid "Telemetry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
#: apps/web/src/components/titles/log-watch-dialog.tsx
|
||||||
msgid "That time is in the future"
|
msgid "That time is in the future"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3385,6 +3397,10 @@ msgstr ""
|
|||||||
msgid "This import cannot be cancelled"
|
msgid "This import cannot be cancelled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: packages/i18n/src/errors.ts
|
||||||
|
msgid "This job is already running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
#: apps/web/src/components/settings/import-dialog-parts.tsx
|
||||||
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
msgid "This may take a few minutes for large libraries. Please don't close this tab."
|
||||||
msgstr "大型媒体库可能需要几分钟。请勿关闭此标签页。"
|
msgstr "大型媒体库可能需要几分钟。请勿关闭此标签页。"
|
||||||
|
|||||||
Reference in new issue
Block a user