refactor(web): share one import-job flow between import dialogs

Extract the job loop into runImportJob (with tests), hold its UI state in
useImportJob, and move the importing/done steps and stat/option components
into import-dialog-parts. Both dialogs now close when an import continues in
the background or the connection drops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jakeandClaude Opus 5.5 committed 2026-10-05 04:11:48 -04:00
1 parent b63fbce60d
commit d874ae9198
18 files changed
+783 -900

No files matched your search

@@ -12,13 +12,20 @@ import {
IconTrash,
IconX,
} from "@tabler/icons-react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useMutation } from "@tanstack/react-query";
import { useNavigate, useRouter } from "@tanstack/react-router";
import { AnimatePresence, motion } from "motion/react";
import { useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { z } from "zod";
import {
DoneStep,
ImportingStep,
OptionCheckbox,
StatBadge,
} from "@/components/settings/import-dialog-parts";
import { useImportJob } from "@/components/settings/use-import-job";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
@@ -36,15 +43,13 @@ import {
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";
import { Spinner } from "@/components/ui/spinner";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useResetUserState } from "@/hooks/use-reset-user-state";
import { authClient, signOut } from "@/lib/auth/client";
import { getErrorMessage } from "@/lib/error-messages";
import { useAppForm } from "@/lib/form";
import { client, orpc } from "@/lib/orpc/client";
import { invalidateTrackingQueries } from "@/lib/orpc/invalidate";
import { orpc } from "@/lib/orpc/client";
import type { NormalizedImport } from "@sofa/api/schemas";
import { formatDate } from "@sofa/i18n/format";
@@ -370,28 +375,12 @@ interface ImportPreview {
stats: { movies: number; episodes: number; watchlist: number; ratings: number };
}
interface ImportResult {
imported: number;
skipped: number;
failed: number;
errors: string[];
warnings: string[];
}
function SofaImportDialog() {
const { t } = useLingui();
const queryClient = useQueryClient();
const fileInputRef = useRef<HTMLInputElement>(null);
const importAbortRef = useRef<AbortController | null>(null);
const [open, setOpen] = useState(false);
const [step, setStep] = useState<"preview" | "importing" | "done">("preview");
const [preview, setPreview] = useState<ImportPreview | null>(null);
const [result, setResult] = useState<ImportResult | null>(null);
const [progress, setProgress] = useState<{
current: number;
total: number;
message: string;
} | null>(null);
const [options, setOptions] = useState({
importWatches: true,
importWatchlist: true,
@@ -408,109 +397,41 @@ function SofaImportDialog() {
onError: (err) => {
toast.error(getErrorMessage(err, t`Failed to parse file`));
},
onSettled: () => {
if (fileInputRef.current) fileInputRef.current.value = "";
},
}),
);
function handleFileSelect(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
parseMutation.mutate({ source: "sofa", file });
parseMutation.mutate(
{ source: "sofa", file },
{
onSettled: () => {
if (fileInputRef.current) fileInputRef.current.value = "";
},
},
);
}
const job = useImportJob({
successMessage: (importedCount) => t`Imported ${importedCount} items from Sofa export`,
onDetached: handleClose,
});
async function handleImport() {
if (!preview) return;
setStep("importing");
setProgress(null);
const abort = new AbortController();
importAbortRef.current = abort;
try {
const job = await client.imports.createJob({
data: preview.data,
options,
});
const eventSource = await client.imports.jobEvents({ id: job.id }, { signal: abort.signal });
let receivedComplete = false;
for await (const event of eventSource) {
if (abort.signal.aborted) break;
if (event.type === "complete") {
receivedComplete = true;
setResult({
imported: event.job.importedCount,
skipped: event.job.skippedCount,
failed: event.job.failedCount,
errors: event.job.errors,
warnings: event.job.warnings,
});
setStep("done");
void invalidateTrackingQueries(queryClient);
const importedCount = event.job.importedCount;
if (importedCount > 0) {
toast.success(t`Imported ${importedCount} items from Sofa export`);
}
} else if (event.type === "timeout") {
receivedComplete = true;
toast.info(t`Import is still running in the background. Check back later.`);
handleClose();
} else {
setProgress({
current: event.job.processedItems,
total: event.job.totalItems,
message: event.job.currentMessage ?? "",
});
}
}
if (!receivedComplete && !abort.signal.aborted) {
try {
const finalJob = await client.imports.getJob({ id: job.id });
const isTerminal =
finalJob.status === "success" ||
finalJob.status === "error" ||
finalJob.status === "cancelled";
if (isTerminal) {
setResult({
imported: finalJob.importedCount,
skipped: finalJob.skippedCount,
failed: finalJob.failedCount,
errors: finalJob.errors,
warnings: finalJob.warnings,
});
setStep("done");
void invalidateTrackingQueries(queryClient);
} else {
toast.info(t`Import is still running in the background. Check back later.`);
handleClose();
}
} catch {
toast.error(t`Lost connection to import. Check status in settings.`);
handleClose();
}
}
} catch (err) {
if (abort.signal.aborted) return;
toast.error(getErrorMessage(err, t`Import failed`));
setStep("preview");
} finally {
importAbortRef.current = null;
}
const outcome = await job.start({ data: preview.data, options });
if (outcome === "done") setStep("done");
else if (outcome === "failed") setStep("preview");
}
function handleClose() {
importAbortRef.current?.abort();
importAbortRef.current = null;
job.abort();
setOpen(false);
setStep("preview");
setPreview(null);
setResult(null);
setProgress(null);
job.reset();
setOptions({ importWatches: true, importWatchlist: true, importRatings: true });
}
@@ -522,9 +443,6 @@ function SofaImportDialog() {
(options.importRatings ? preview.stats.ratings : 0)
: 0;
const pct =
progress && progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : null;
return (
<>
<input
@@ -583,29 +501,32 @@ function SofaImportDialog() {
<div className="space-y-4 py-2">
<div className="grid grid-cols-2 gap-3">
<ImportStatBadge label={t`Movies`} count={movieCount} />
<ImportStatBadge label={t`Episodes`} count={episodeCount} />
<ImportStatBadge label={t`Library`} count={watchlistCount} />
<ImportStatBadge label={t`Ratings`} count={ratingCount} />
<StatBadge label={t`Movies`} count={movieCount} />
<StatBadge label={t`Episodes`} count={episodeCount} />
<StatBadge label={t`Library`} count={watchlistCount} />
<StatBadge label={t`Ratings`} count={ratingCount} />
</div>
<div className="space-y-2">
<p className="text-sm font-medium">
<Trans>Import options</Trans>
</p>
<ImportOptionCheckbox
<OptionCheckbox
idPrefix="sofa-import"
label={t`Watch history`}
description={t`${movieCount} movies, ${episodeCount} episodes`}
checked={options.importWatches}
onChange={(v) => setOptions({ ...options, importWatches: v })}
/>
<ImportOptionCheckbox
<OptionCheckbox
idPrefix="sofa-import"
label={t`Library statuses`}
description={t`${watchlistCount} items`}
checked={options.importWatchlist}
onChange={(v) => setOptions({ ...options, importWatchlist: v })}
/>
<ImportOptionCheckbox
<OptionCheckbox
idPrefix="sofa-import"
label={t`Ratings`}
description={t`${ratingCount} ratings`}
checked={options.importRatings}
@@ -639,147 +560,17 @@ function SofaImportDialog() {
);
})()}
{step === "importing" && (
<>
<DialogHeader>
<DialogTitle>
<Trans>Importing data</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
This may take a few minutes for large libraries. Please don't close this tab.
</Trans>
</DialogDescription>
</DialogHeader>
<div className="flex flex-col items-center gap-4 py-8">
<Progress value={pct} className="w-full" />
<div className="flex flex-col items-center gap-1 text-center">
{progress ? (
<>
<p className="text-sm font-medium">
{progress.current} / {progress.total}
</p>
<p className="text-muted-foreground max-w-[300px] truncate text-xs">
{progress.message}
</p>
</>
) : (
<div className="flex items-center gap-2">
<Spinner className="size-3" />
<p className="text-muted-foreground text-sm">
<Trans>Starting import...</Trans>
</p>
</div>
)}
</div>
</div>
</>
{step === "importing" && <ImportingStep source="Sofa" progress={job.progress} />}
{step === "done" && job.result && (
<DoneStep source="Sofa" result={job.result} onClose={handleClose} />
)}
{step === "done" &&
result &&
(() => {
const errorCount = result.errors.length;
const warningCount = result.warnings.length;
const remainingErrors = errorCount - 50;
return (
<>
<DialogHeader>
<DialogTitle>
<Trans>Import complete</Trans>
</DialogTitle>
<DialogDescription>
<Trans>Finished importing your Sofa export.</Trans>
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
<div className="grid grid-cols-3 gap-3">
<ImportStatBadge label={t`Imported`} count={result.imported} />
<ImportStatBadge label={t`Skipped`} count={result.skipped} />
<ImportStatBadge label={t`Failed`} count={result.failed} />
</div>
{errorCount > 0 && (
<div className="bg-destructive/10 max-h-40 overflow-y-auto rounded-lg p-3">
<p className="text-destructive mb-1 text-xs font-medium">
<Trans>Errors ({errorCount})</Trans>
</p>
<ul className="text-destructive/80 space-y-0.5 text-xs">
{result.errors.slice(0, 50).map((e, i) => (
<li key={i}>{e}</li>
))}
{errorCount > 50 && (
<li>
<Trans>...and {remainingErrors} more</Trans>
</li>
)}
</ul>
</div>
)}
{warningCount > 0 && (
<div className="max-h-32 overflow-y-auto rounded-lg bg-yellow-500/10 p-3">
<p className="mb-1 text-xs font-medium text-yellow-600">
<Trans>Warnings ({warningCount})</Trans>
</p>
<ul className="space-y-0.5 text-xs text-yellow-600/80">
{result.warnings.slice(0, 20).map((w, i) => (
<li key={i}>{w}</li>
))}
</ul>
</div>
)}
</div>
<DialogFooter>
<Button onClick={handleClose}>
<Trans>Done</Trans>
</Button>
</DialogFooter>
</>
);
})()}
</DialogContent>
</Dialog>
</>
);
}
function ImportStatBadge({ label, count }: { label: string; count: number }) {
return (
<div className="bg-muted/50 rounded-lg p-2.5 text-center">
<p className="text-lg leading-none font-semibold">{count}</p>
<p className="text-muted-foreground mt-1 text-xs">{label}</p>
</div>
);
}
function ImportOptionCheckbox({
label,
description,
checked,
onChange,
}: {
label: string;
description: string;
checked: boolean;
onChange: (v: boolean) => void;
}) {
const id = `sofa-import-${label}`;
return (
<div className="flex items-center gap-3">
<Checkbox id={id} checked={checked} onCheckedChange={onChange} />
<div>
<Label htmlFor={id} className="text-sm">
{label}
</Label>
<p className="text-muted-foreground text-xs">{description}</p>
</div>
</div>
);
}
// ─── Change Password Dialog ─────────────────────────────────
function ChangePasswordDialog() {
@@ -0,0 +1,165 @@
import { Trans, useLingui } from "@lingui/react/macro";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";
import { Spinner } from "@/components/ui/spinner";
import type { ImportProgress, ImportResult } from "@/lib/import-job";
export function ImportingStep({
source,
progress,
}: {
source: string;
progress: ImportProgress | null;
}) {
const pct =
progress && progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : null;
return (
<>
<DialogHeader>
<DialogTitle>
<Trans>Importing from {source}</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
This may take a few minutes for large libraries. Please don't close this tab.
</Trans>
</DialogDescription>
</DialogHeader>
<div className="flex flex-col items-center gap-4 py-8">
<Progress value={pct} className="w-full" />
<div className="flex flex-col items-center gap-1 text-center">
{progress ? (
<>
<p className="text-sm font-medium">
{progress.current} / {progress.total}
</p>
<p className="text-muted-foreground max-w-[300px] truncate text-xs">
{progress.message}
</p>
</>
) : (
<div className="flex items-center gap-2">
<Spinner className="size-3" />
<p className="text-muted-foreground text-sm">
<Trans>Starting import...</Trans>
</p>
</div>
)}
</div>
</div>
</>
);
}
export function DoneStep({
source,
result,
onClose,
}: {
source: string;
result: ImportResult;
onClose: () => void;
}) {
const { t } = useLingui();
const errorCount = result.errors.length;
const warningCount = result.warnings.length;
const remainingErrors = errorCount - 50;
return (
<>
<DialogHeader>
<DialogTitle>
<Trans>Import complete</Trans>
</DialogTitle>
<DialogDescription>
<Trans>Finished importing from {source}.</Trans>
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
<div className="grid grid-cols-3 gap-3">
<StatBadge label={t`Imported`} count={result.imported} />
<StatBadge label={t`Skipped`} count={result.skipped} />
<StatBadge label={t`Failed`} count={result.failed} />
</div>
{errorCount > 0 && (
<div className="bg-destructive/10 max-h-40 overflow-y-auto rounded-lg p-3">
<p className="text-destructive mb-1 text-xs font-medium">
<Trans>Errors ({errorCount})</Trans>
</p>
<ul className="text-destructive/80 space-y-0.5 text-xs">
{result.errors.slice(0, 50).map((e, i) => (
<li key={i}>{e}</li>
))}
{errorCount > 50 && (
<li>
<Trans>...and {remainingErrors} more</Trans>
</li>
)}
</ul>
</div>
)}
{warningCount > 0 && (
<div className="max-h-32 overflow-y-auto rounded-lg bg-yellow-500/10 p-3">
<p className="mb-1 text-xs font-medium text-yellow-600">
<Trans>Warnings ({warningCount})</Trans>
</p>
<ul className="space-y-0.5 text-xs text-yellow-600/80">
{result.warnings.slice(0, 20).map((w, i) => (
<li key={i}>{w}</li>
))}
</ul>
</div>
)}
</div>
<DialogFooter>
<Button onClick={onClose}>
<Trans>Done</Trans>
</Button>
</DialogFooter>
</>
);
}
export function StatBadge({ label, count }: { label: string; count: number }) {
return (
<div className="bg-muted/50 rounded-lg p-2.5 text-center">
<p className="text-lg leading-none font-semibold">{count}</p>
<p className="text-muted-foreground mt-1 text-xs">{label}</p>
</div>
);
}
export function OptionCheckbox({
idPrefix,
label,
description,
checked,
onChange,
}: {
idPrefix: string;
label: string;
description: string;
checked: boolean;
onChange: (v: boolean) => void;
}) {
const id = `${idPrefix}-${label}`;
return (
<div className="flex items-center gap-3">
<Checkbox id={id} checked={checked} onCheckedChange={onChange} />
<div>
<Label htmlFor={id} className="text-sm">
{label}
</Label>
<p className="text-muted-foreground text-xs">{description}</p>
</div>
</div>
);
}
@@ -2,13 +2,19 @@ import type { MessageDescriptor } from "@lingui/core";
import { msg } from "@lingui/core/macro";
import { Trans, useLingui } from "@lingui/react/macro";
import { IconCloudUpload, IconLink } from "@tabler/icons-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import {
ImportingStep,
DoneStep,
OptionCheckbox,
StatBadge,
} from "@/components/settings/import-dialog-parts";
import { useImportJob } from "@/components/settings/use-import-job";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
DialogClose,
@@ -18,13 +24,10 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";
import { Spinner } from "@/components/ui/spinner";
import { startDevicePoll } from "@/lib/device-code-poll";
import { getErrorMessage } from "@/lib/error-messages";
import { client, orpc } from "@/lib/orpc/client";
import { invalidateTrackingQueries } from "@/lib/orpc/invalidate";
import { orpc } from "@/lib/orpc/client";
import type { NormalizedImport } from "@sofa/api/schemas";
import { formatList } from "@sofa/i18n/format";
@@ -154,14 +157,6 @@ interface ImportPreview {
};
}
interface ImportResult {
imported: number;
skipped: number;
failed: number;
errors: string[];
warnings: string[];
}
interface DeviceCodeInfo {
device_code: string;
user_code: string;
@@ -194,14 +189,12 @@ export function ImportsSection() {
function ImportSourceCard({ config }: { config: SourceConfig }) {
const { i18n, t } = useLingui();
const queryClient = useQueryClient();
const { data: systemStatus } = useQuery(orpc.system.status.queryOptions());
const publicApiUrl = systemStatus?.publicApiUrl ?? "https://public-api.sofa.watch";
const fileInputRef = useRef<HTMLInputElement>(null);
const [dialogOpen, setDialogOpen] = useState(false);
const [step, setStep] = useState<DialogStep>(config.supportsOAuth ? "choose" : "preview");
const [preview, setPreview] = useState<ImportPreview | null>(null);
const [result, setResult] = useState<ImportResult | null>(null);
const [options, setOptions] = useState({
importWatches: true,
importWatchlist: true,
@@ -213,7 +206,6 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
const [oauthError, setOauthError] = useState<string | null>(null);
const pollRef = useRef<{ stop: () => void } | null>(null);
const flowIdRef = useRef(0);
const importAbortRef = useRef<AbortController | null>(null);
const parseMutation = useMutation(
orpc.imports.parseFile.mutationOptions({
@@ -241,13 +233,6 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
}),
);
// Progress state
const [progress, setProgress] = useState<{
current: number;
total: number;
message: string;
} | null>(null);
function handleFileSelect(file: File) {
parseMutation.mutate(
{ source: config.source, file },
@@ -259,89 +244,20 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
);
}
const job = useImportJob({
successMessage: (importedCount) => {
const sourceLabel = config.label;
return t`Imported ${importedCount} items from ${sourceLabel}`;
},
onDetached: handleClose,
});
async function handleImport() {
if (!preview) return;
setStep("importing");
setProgress(null);
const abort = new AbortController();
importAbortRef.current = abort;
try {
const job = await client.imports.createJob({
data: preview.data,
options,
});
const eventSource = await client.imports.jobEvents({ id: job.id }, { signal: abort.signal });
let receivedComplete = false;
for await (const event of eventSource) {
if (abort.signal.aborted) break;
if (event.type === "complete") {
receivedComplete = true;
setResult({
imported: event.job.importedCount,
skipped: event.job.skippedCount,
failed: event.job.failedCount,
errors: event.job.errors,
warnings: event.job.warnings,
});
setStep("done");
void invalidateTrackingQueries(queryClient);
const importedCount = event.job.importedCount;
const sourceLabel = config.label;
if (importedCount > 0) {
toast.success(t`Imported ${importedCount} items from ${sourceLabel}`);
}
} else if (event.type === "timeout") {
receivedComplete = true;
toast.info(t`Import is still running in the background. Check back later.`);
setStep("preview");
} else {
setProgress({
current: event.job.processedItems,
total: event.job.totalItems,
message: event.job.currentMessage ?? "",
});
}
}
// Stream ended without a complete/timeout event (e.g. connection dropped)
if (!receivedComplete && !abort.signal.aborted) {
try {
const finalJob = await client.imports.getJob({ id: job.id });
const isTerminal =
finalJob.status === "success" ||
finalJob.status === "error" ||
finalJob.status === "cancelled";
if (isTerminal) {
setResult({
imported: finalJob.importedCount,
skipped: finalJob.skippedCount,
failed: finalJob.failedCount,
errors: finalJob.errors,
warnings: finalJob.warnings,
});
setStep("done");
void invalidateTrackingQueries(queryClient);
} else {
toast.info(t`Import is still running in the background. Check back later.`);
setStep("preview");
}
} catch {
toast.error(t`Lost connection to import. Check status in settings.`);
setStep("preview");
}
}
} catch (err) {
if (abort.signal.aborted) return;
toast.error(getErrorMessage(err, t`Import failed`));
setStep("preview");
} finally {
importAbortRef.current = null;
}
const outcome = await job.start({ data: preview.data, options });
if (outcome === "done") setStep("done");
else if (outcome === "failed") setStep("preview");
}
// Clean up poll timer on unmount or dialog close
@@ -353,12 +269,11 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
function handleClose() {
stopPolling();
flowIdRef.current += 1;
importAbortRef.current?.abort();
importAbortRef.current = null;
job.abort();
setDialogOpen(false);
setStep(config.supportsOAuth ? "choose" : "preview");
setPreview(null);
setResult(null);
job.reset();
setDeviceCode(null);
setOauthError(null);
setOptions({
@@ -538,9 +453,9 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
onCancel={handleClose}
/>
)}
{step === "importing" && <ImportingStep source={config.label} progress={progress} />}
{step === "done" && result && (
<DoneStep source={config.label} result={result} onClose={handleClose} />
{step === "importing" && <ImportingStep source={config.label} progress={job.progress} />}
{step === "done" && job.result && (
<DoneStep source={config.label} result={job.result} onClose={handleClose} />
)}
</DialogContent>
</Dialog>
@@ -788,18 +703,21 @@ function PreviewStep({
<Trans>Import options</Trans>
</p>
<OptionCheckbox
idPrefix="import-opt"
label={t`Watch history`}
description={t`${movieCount} movies, ${episodeCount} episodes`}
checked={options.importWatches}
onChange={(v) => setOptions({ ...options, importWatches: v })}
/>
<OptionCheckbox
idPrefix="import-opt"
label={t`Watchlist`}
description={t`${watchlistCount} items`}
checked={options.importWatchlist}
onChange={(v) => setOptions({ ...options, importWatchlist: v })}
/>
<OptionCheckbox
idPrefix="import-opt"
label={t`Ratings`}
description={t`${ratingCount} ratings`}
checked={options.importRatings}
@@ -832,159 +750,3 @@ function PreviewStep({
</>
);
}
function ImportingStep({
source,
progress,
}: {
source: string;
progress: { current: number; total: number; message: string } | null;
}) {
const pct =
progress && progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : null;
return (
<>
<DialogHeader>
<DialogTitle>
<Trans>Importing from {source}</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
This may take a few minutes for large libraries. Please don't close this tab.
</Trans>
</DialogDescription>
</DialogHeader>
<div className="flex flex-col items-center gap-4 py-8">
<Progress value={pct} className="w-full" />
<div className="flex flex-col items-center gap-1 text-center">
{progress ? (
<>
<p className="text-sm font-medium">
{progress.current} / {progress.total}
</p>
<p className="text-muted-foreground max-w-[300px] truncate text-xs">
{progress.message}
</p>
</>
) : (
<div className="flex items-center gap-2">
<Spinner className="size-3" />
<p className="text-muted-foreground text-sm">
<Trans>Starting import...</Trans>
</p>
</div>
)}
</div>
</div>
</>
);
}
function DoneStep({
source,
result,
onClose,
}: {
source: string;
result: ImportResult;
onClose: () => void;
}) {
const { t } = useLingui();
const errorCount = result.errors.length;
const warningCount = result.warnings.length;
const remainingErrors = errorCount - 50;
return (
<>
<DialogHeader>
<DialogTitle>
<Trans>Import complete</Trans>
</DialogTitle>
<DialogDescription>
<Trans>Finished importing from {source}.</Trans>
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
<div className="grid grid-cols-3 gap-3">
<StatBadge label={t`Imported`} count={result.imported} />
<StatBadge label={t`Skipped`} count={result.skipped} />
<StatBadge label={t`Failed`} count={result.failed} />
</div>
{errorCount > 0 && (
<div className="bg-destructive/10 max-h-40 overflow-y-auto rounded-lg p-3">
<p className="text-destructive mb-1 text-xs font-medium">
<Trans>Errors ({errorCount})</Trans>
</p>
<ul className="text-destructive/80 space-y-0.5 text-xs">
{result.errors.slice(0, 50).map((e, i) => (
<li key={i}>{e}</li>
))}
{errorCount > 50 && (
<li>
<Trans>...and {remainingErrors} more</Trans>
</li>
)}
</ul>
</div>
)}
{warningCount > 0 && (
<div className="max-h-32 overflow-y-auto rounded-lg bg-yellow-500/10 p-3">
<p className="mb-1 text-xs font-medium text-yellow-600">
<Trans>Warnings ({warningCount})</Trans>
</p>
<ul className="space-y-0.5 text-xs text-yellow-600/80">
{result.warnings.slice(0, 20).map((w, i) => (
<li key={i}>{w}</li>
))}
</ul>
</div>
)}
</div>
<DialogFooter>
<Button onClick={onClose}>
<Trans>Done</Trans>
</Button>
</DialogFooter>
</>
);
}
// ─── Helpers ────────────────────────────────────────────────
function StatBadge({ label, count }: { label: string; count: number }) {
return (
<div className="bg-muted/50 rounded-lg p-2.5 text-center">
<p className="text-lg leading-none font-semibold">{count}</p>
<p className="text-muted-foreground mt-1 text-xs">{label}</p>
</div>
);
}
function OptionCheckbox({
label,
description,
checked,
onChange,
}: {
label: string;
description: string;
checked: boolean;
onChange: (v: boolean) => void;
}) {
const id = `import-opt-${label}`;
return (
<div className="flex items-center gap-3">
<Checkbox id={id} checked={checked} onCheckedChange={onChange} />
<div>
<Label htmlFor={id} className="text-sm">
{label}
</Label>
<p className="text-muted-foreground text-xs">{description}</p>
</div>
</div>
);
}
@@ -0,0 +1,79 @@
import { useLingui } from "@lingui/react/macro";
import { useQueryClient } from "@tanstack/react-query";
import { useRef, useState } from "react";
import { toast } from "sonner";
import { getErrorMessage } from "@/lib/error-messages";
import { runImportJob } from "@/lib/import-job";
import type { ImportOptions, ImportProgress, ImportResult } from "@/lib/import-job";
import { client } from "@/lib/orpc/client";
import { invalidateTrackingQueries } from "@/lib/orpc/invalidate";
import type { NormalizedImport } from "@sofa/api/schemas";
export type ImportJobStartResult = "done" | "detached" | "failed" | "aborted";
export function useImportJob({
successMessage,
onDetached,
}: {
/** Toast text for a finished import with N > 0 imported items. */
successMessage: (importedCount: number) => string;
/** Called when the job continues in the background or the connection is lost (close the dialog). */
onDetached: () => void;
}) {
const { t } = useLingui();
const queryClient = useQueryClient();
const abortRef = useRef<AbortController | null>(null);
const [progress, setProgress] = useState<ImportProgress | null>(null);
const [result, setResult] = useState<ImportResult | null>(null);
async function start(input: {
data: NormalizedImport;
options: ImportOptions;
}): Promise<ImportJobStartResult> {
setProgress(null);
const controller = new AbortController();
abortRef.current = controller;
try {
const outcome = await runImportJob(client.imports, input, controller.signal, setProgress);
switch (outcome.kind) {
case "done":
setResult(outcome.result);
void invalidateTrackingQueries(queryClient);
if (outcome.result.imported > 0) {
toast.success(successMessage(outcome.result.imported));
}
return "done";
case "background":
toast.info(t`Import is still running in the background. Check back later.`);
onDetached();
return "detached";
case "lost":
toast.error(t`Lost connection to import. Check status in settings.`);
onDetached();
return "detached";
case "aborted":
return "aborted";
}
} catch (err) {
if (controller.signal.aborted) return "aborted";
toast.error(getErrorMessage(err, t`Import failed`));
return "failed";
} finally {
abortRef.current = null;
}
}
function abort() {
abortRef.current?.abort();
abortRef.current = null;
}
function reset() {
setProgress(null);
setResult(null);
}
return { progress, result, start, abort, reset };
}
+151
View File
@@ -0,0 +1,151 @@
import { describe, expect, test, vi } from "vitest";
import type { NormalizedImport } from "@sofa/api/schemas";
import { runImportJob } from "./import-job";
import type { ImportJobApi, ImportOptions, ImportProgress } from "./import-job";
type Event =
Awaited<ReturnType<ImportJobApi["jobEvents"]>> extends AsyncIterable<infer E> ? E : never;
type Job = Awaited<ReturnType<ImportJobApi["getJob"]>>;
const input = {
data: {} as NormalizedImport,
options: { importWatches: true, importWatchlist: true, importRatings: true } as ImportOptions,
};
function makeJob(overrides: Partial<Job> = {}): Job {
return {
status: "running",
processedItems: 0,
totalItems: 10,
currentMessage: null,
importedCount: 0,
skippedCount: 0,
failedCount: 0,
errors: [],
warnings: [],
...overrides,
};
}
function makeApi(options: {
events?: Event[];
/** Called between events; lets a test abort mid-stream. */
beforeEvent?: (index: number) => void;
getJob?: () => Promise<Job>;
createJob?: () => Promise<{ id: string }>;
}): ImportJobApi {
const { events = [], beforeEvent, getJob, createJob } = options;
return {
createJob: createJob ?? (() => Promise.resolve({ id: "job-1" })),
jobEvents: () =>
Promise.resolve(
(async function* () {
for (const [index, event] of events.entries()) {
beforeEvent?.(index);
yield event;
}
})(),
),
getJob: getJob ?? (() => Promise.resolve(makeJob())),
};
}
describe("runImportJob", () => {
test("reports progress and resolves done on a complete event", async () => {
const api = makeApi({
events: [
{ type: "progress", job: makeJob({ processedItems: 1, currentMessage: "one" }) },
{ type: "progress", job: makeJob({ processedItems: 2 }) },
{
type: "complete",
job: makeJob({
status: "success",
importedCount: 7,
skippedCount: 2,
failedCount: 1,
errors: ["e"],
warnings: ["w"],
}),
},
],
});
const onProgress = vi.fn<(progress: ImportProgress) => void>();
const outcome = await runImportJob(api, input, new AbortController().signal, onProgress);
expect(onProgress).toHaveBeenCalledTimes(2);
expect(onProgress).toHaveBeenNthCalledWith(1, { current: 1, total: 10, message: "one" });
expect(onProgress).toHaveBeenNthCalledWith(2, { current: 2, total: 10, message: "" });
expect(outcome).toEqual({
kind: "done",
result: { imported: 7, skipped: 2, failed: 1, errors: ["e"], warnings: ["w"] },
});
});
test("resolves background on a timeout event", async () => {
const api = makeApi({ events: [{ type: "timeout", job: makeJob() }] });
const outcome = await runImportJob(api, input, new AbortController().signal, () => {});
expect(outcome).toEqual({ kind: "background" });
});
test("falls back to getJob when the stream ends: terminal status is done", async () => {
const api = makeApi({
getJob: () => Promise.resolve(makeJob({ status: "success", importedCount: 3 })),
});
const outcome = await runImportJob(api, input, new AbortController().signal, () => {});
expect(outcome).toEqual({
kind: "done",
result: { imported: 3, skipped: 0, failed: 0, errors: [], warnings: [] },
});
});
test("falls back to getJob when the stream ends: running status is background", async () => {
const api = makeApi({ getJob: () => Promise.resolve(makeJob({ status: "running" })) });
const outcome = await runImportJob(api, input, new AbortController().signal, () => {});
expect(outcome).toEqual({ kind: "background" });
});
test("falls back to getJob when the stream ends: getJob failure is lost", async () => {
const api = makeApi({ getJob: () => Promise.reject(new Error("network")) });
const outcome = await runImportJob(api, input, new AbortController().signal, () => {});
expect(outcome).toEqual({ kind: "lost" });
});
test("resolves aborted when the signal aborts mid-stream", async () => {
const abort = new AbortController();
const api = makeApi({
events: [
{ type: "progress", job: makeJob({ processedItems: 1 }) },
{ type: "progress", job: makeJob({ processedItems: 2 }) },
],
beforeEvent: (index) => {
if (index === 1) abort.abort();
},
});
const onProgress = vi.fn<(progress: ImportProgress) => void>();
const outcome = await runImportJob(api, input, abort.signal, onProgress);
expect(outcome).toEqual({ kind: "aborted" });
expect(onProgress).toHaveBeenCalledTimes(1);
});
test("rejects with the same error when createJob fails", async () => {
const error = new Error("already in progress");
const api = makeApi({ createJob: () => Promise.reject(error) });
await expect(runImportJob(api, input, new AbortController().signal, () => {})).rejects.toBe(
error,
);
});
});
+91
View File
@@ -0,0 +1,91 @@
import type { NormalizedImport } from "@sofa/api/schemas";
export interface ImportProgress {
current: number;
total: number;
message: string;
}
export interface ImportResult {
imported: number;
skipped: number;
failed: number;
errors: string[];
warnings: string[];
}
export interface ImportOptions {
importWatches: boolean;
importWatchlist: boolean;
importRatings: boolean;
}
interface JobSnapshot {
status: string;
processedItems: number;
totalItems: number;
currentMessage: string | null;
importedCount: number;
skippedCount: number;
failedCount: number;
errors: string[];
warnings: string[];
}
/** The subset of `client.imports` the runner needs (injectable for tests). */
export interface ImportJobApi {
createJob(input: { data: NormalizedImport; options: ImportOptions }): Promise<{ id: string }>;
jobEvents(
input: { id: string },
opts: { signal: AbortSignal },
): Promise<AsyncIterable<{ type: "progress" | "complete" | "timeout"; job: JobSnapshot }>>;
getJob(input: { id: string }): Promise<JobSnapshot>;
}
export type ImportJobOutcome =
| { kind: "done"; result: ImportResult }
| { kind: "background" } // still running on the server
| { kind: "lost" } // stream dropped and the job status couldn't be read
| { kind: "aborted" };
const TERMINAL = new Set(["success", "error", "cancelled"]);
function toResult(job: JobSnapshot): ImportResult {
return {
imported: job.importedCount,
skipped: job.skippedCount,
failed: job.failedCount,
errors: job.errors,
warnings: job.warnings,
};
}
/** Create an import job and follow it to completion. Throws if the job can't be created. */
export async function runImportJob(
api: ImportJobApi,
input: { data: NormalizedImport; options: ImportOptions },
signal: AbortSignal,
onProgress: (progress: ImportProgress) => void,
): Promise<ImportJobOutcome> {
const job = await api.createJob(input);
const events = await api.jobEvents({ id: job.id }, { signal });
for await (const event of events) {
if (signal.aborted) return { kind: "aborted" };
if (event.type === "complete") return { kind: "done", result: toResult(event.job) };
if (event.type === "timeout") return { kind: "background" };
onProgress({
current: event.job.processedItems,
total: event.job.totalItems,
message: event.job.currentMessage ?? "",
});
}
if (signal.aborted) return { kind: "aborted" };
try {
const finalJob = await api.getJob({ id: job.id });
return TERMINAL.has(finalJob.status)
? { kind: "done", result: toResult(finalJob) }
: { kind: "background" };
} catch {
return { kind: "lost" };
}
}
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...و{remainingErrors} أخرى"
@@ -1043,8 +1042,7 @@ msgstr "ليس لديك خادم؟"
msgid "Don't have an account?"
msgstr "ليس لديك حساب؟"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "تم"
@@ -1210,8 +1208,7 @@ msgstr "خطأ"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "الأخطاء ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "استكشاف العناوين"
msgid "Export"
msgstr "تصدير"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "فشل"
@@ -1450,13 +1446,13 @@ msgstr "فيلموغرافيا"
msgid "Filters"
msgstr "الفلاتر"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "اكتمل الاستيراد من {source}."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "تم الانتهاء من استيراد ملف تصدير Sofa."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "تم الانتهاء من استيراد ملف تصدير Sofa."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "الاستيراد"
msgid "Import {totalItems} items"
msgstr "استيراد {totalItems} عنصر"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "اكتمل الاستيراد"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "فشل الاستيراد"
@@ -1627,8 +1621,7 @@ msgstr "الاستيراد من {source}"
msgid "Import from {sourceLabel}"
msgstr "الاستيراد من {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "لا يزال الاستيراد قيد التشغيل في الخلفية. تحقق لاحقاً."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "استيراد بيانات Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "تم الاستيراد"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "تم استيراد {importedCount} عناصر من ملف تصدير Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "جارٍ استيراد البيانات"
#~ msgid "Importing data"
#~ msgstr "جارٍ استيراد البيانات"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "جارٍ الاستيراد من {source}"
@@ -1843,8 +1835,7 @@ msgstr "جارٍ التحميل…"
msgid "Login failed"
msgstr "فشل تسجيل الدخول"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "انقطع الاتصال بعملية الاستيراد. تحقق من الحالة في الإعدادات."
@@ -3062,8 +3053,7 @@ msgstr "تسجيل الخروج من الجلسات الأخرى"
msgid "Skip for now"
msgstr "تخطي في الوقت الحالي"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "تم التخطي"
@@ -3148,8 +3138,7 @@ msgstr "ابدأ تتبع مشاهداتك"
msgid "Starting at"
msgstr "بدءاً من"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "جارٍ بدء الاستيراد..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "قد يستغرق هذا بضع دقائق للمكتبات الكبيرة. يرجى عدم إغلاق هذا التبويب."
@@ -3646,8 +3634,7 @@ msgstr "تحذيرات"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "تحذيرات ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...und {remainingErrors} weitere"
@@ -1043,8 +1042,7 @@ msgstr "Noch keinen Server?"
msgid "Don't have an account?"
msgstr "Noch kein Konto?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Fertig"
@@ -1210,8 +1208,7 @@ msgstr "Fehler"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Fehler ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Titel entdecken"
msgid "Export"
msgstr "Exportieren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Fehlgeschlagen"
@@ -1450,13 +1446,13 @@ msgstr "Filmografie"
msgid "Filters"
msgstr "Filter"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Import von {source} abgeschlossen."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Sofa-Export wurde erfolgreich importiert."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Sofa-Export wurde erfolgreich importiert."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importieren"
msgid "Import {totalItems} items"
msgstr "{totalItems} Einträge importieren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Import abgeschlossen"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Import fehlgeschlagen"
@@ -1627,8 +1621,7 @@ msgstr "Von {source} importieren"
msgid "Import from {sourceLabel}"
msgstr "Von {sourceLabel} importieren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "Import läuft noch im Hintergrund. Komm später wieder."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Sofa-Daten importieren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Importiert"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "{importedCount} Einträge aus Sofa-Export importiert"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Daten werden importiert"
#~ msgid "Importing data"
#~ msgstr "Daten werden importiert"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importiere von {source}"
@@ -1843,8 +1835,7 @@ msgstr "Lade..."
msgid "Login failed"
msgstr "Anmeldung fehlgeschlagen"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Verbindung zum Import verloren. Status in den Einstellungen prüfen."
@@ -3062,8 +3053,7 @@ msgstr "Von anderen Sitzungen abmelden"
msgid "Skip for now"
msgstr "Vorerst überspringen"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Übersprungen"
@@ -3148,8 +3138,7 @@ msgstr "Verfolge deine Sehgewohnheiten"
msgid "Starting at"
msgstr "Startzeit"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Import wird gestartet..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "Dies kann bei großen Bibliotheken einige Minuten dauern. Bitte schließe diesen Tab nicht."
@@ -3646,8 +3634,7 @@ msgstr "Warnungen"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Warnungen ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...and {remainingErrors} more"
@@ -1043,8 +1042,7 @@ msgstr ""
msgid "Don't have an account?"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr ""
@@ -1210,8 +1208,7 @@ msgstr ""
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Errors ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr ""
msgid "Export"
msgstr "Export"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr ""
@@ -1450,13 +1446,13 @@ msgstr ""
msgid "Filters"
msgstr "Filters"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Finished importing your Sofa export."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Finished importing your Sofa export."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr ""
msgid "Import {totalItems} items"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr ""
@@ -1627,8 +1621,7 @@ msgstr ""
msgid "Import from {sourceLabel}"
msgstr "Import from {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr ""
@@ -1646,8 +1639,7 @@ msgstr "Import payload is too large"
msgid "Import Sofa data"
msgstr "Import Sofa data"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr ""
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Imported {importedCount} items from Sofa export"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Importing data"
#~ msgid "Importing data"
#~ msgstr "Importing data"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr ""
@@ -1843,8 +1835,7 @@ msgstr ""
msgid "Login failed"
msgstr "Login failed"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr ""
@@ -3062,8 +3053,7 @@ msgstr ""
msgid "Skip for now"
msgstr "Skip for now"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr ""
@@ -3148,8 +3138,7 @@ msgstr ""
msgid "Starting at"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr ""
@@ -3233,8 +3222,7 @@ msgstr "This doesn't appear to be a Sofa server. Double-check the URL."
msgid "This import cannot be cancelled"
msgstr "This import cannot be cancelled"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr ""
@@ -3646,8 +3634,7 @@ msgstr ""
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Warnings ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...y {remainingErrors} más"
@@ -1043,8 +1042,7 @@ msgstr "¿No tienes un servidor?"
msgid "Don't have an account?"
msgstr "¿No tienes una cuenta?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Hecho"
@@ -1210,8 +1208,7 @@ msgstr ""
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Errores ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Explorar títulos"
msgid "Export"
msgstr "Exportar"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Fallido"
@@ -1450,13 +1446,13 @@ msgstr "Filmografía"
msgid "Filters"
msgstr "Filtros"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Importación desde {source} completada."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Importación de tu exportación de Sofa completada."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Importación de tu exportación de Sofa completada."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importar"
msgid "Import {totalItems} items"
msgstr "Importar {totalItems} elementos"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Importación completada"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Error en la importación"
@@ -1627,8 +1621,7 @@ msgstr "Importar desde {source}"
msgid "Import from {sourceLabel}"
msgstr "Importar desde {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "La importación sigue en curso en segundo plano. Vuelve más tarde."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Importar datos de Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Importado"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Se importaron {importedCount} elementos de la exportación de Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Importando datos"
#~ msgid "Importing data"
#~ msgstr "Importando datos"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importando desde {source}"
@@ -1843,8 +1835,7 @@ msgstr "Cargando…"
msgid "Login failed"
msgstr "Error al iniciar sesión"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Se perdió la conexión con la importación. Comprueba el estado en ajustes."
@@ -3062,8 +3053,7 @@ msgstr "Cerrar otras sesiones"
msgid "Skip for now"
msgstr "Omitir por ahora"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Omitido"
@@ -3148,8 +3138,7 @@ msgstr "Empieza a registrar lo que ves"
msgid "Starting at"
msgstr "Comenzando a las"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Iniciando importación..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "Esto puede tardar unos minutos para bibliotecas grandes. Por favor, no cierres esta pestaña."
@@ -3646,8 +3634,7 @@ msgstr "Advertencias"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Advertencias ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...et {remainingErrors} de plus"
@@ -1043,8 +1042,7 @@ msgstr "Pas de serveur ?"
msgid "Don't have an account?"
msgstr "Pas encore de compte ?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Terminé"
@@ -1210,8 +1208,7 @@ msgstr "Erreur"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Erreurs ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Explorer les titres"
msgid "Export"
msgstr "Exporter"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Échoué"
@@ -1450,13 +1446,13 @@ msgstr "Filmographie"
msgid "Filters"
msgstr "Filtres"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Importation depuis {source} terminée."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Importation de votre export Sofa terminée."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Importation de votre export Sofa terminée."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importation"
msgid "Import {totalItems} items"
msgstr "Importer {totalItems} éléments"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Importation terminée"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Importation échouée"
@@ -1627,8 +1621,7 @@ msgstr "Importer depuis {source}"
msgid "Import from {sourceLabel}"
msgstr "Importer depuis {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "L'importation est toujours en cours en arrière-plan. Revenez plus tard."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Importer des données Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Importé"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "{importedCount} éléments importés depuis l'export Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Importation des données"
#~ msgid "Importing data"
#~ msgstr "Importation des données"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importation depuis {source}"
@@ -1843,8 +1835,7 @@ msgstr "Chargement…"
msgid "Login failed"
msgstr "Connexion échouée"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Connexion à l'importation perdue. Vérifiez l'état dans les paramètres."
@@ -3062,8 +3053,7 @@ msgstr "Se déconnecter des autres sessions"
msgid "Skip for now"
msgstr "Passer pour l'instant"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Ignoré"
@@ -3148,8 +3138,7 @@ msgstr "Commencez à suivre vos visionnages"
msgid "Starting at"
msgstr "À partir de"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Démarrage de l'importation..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "Cela peut prendre quelques minutes pour les grandes bibliothèques. Ne fermez pas cet onglet."
@@ -3646,8 +3634,7 @@ msgstr "Avertissements"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Avertissements ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...ועוד {remainingErrors}"
@@ -1043,8 +1042,7 @@ msgstr "אין לך שרת?"
msgid "Don't have an account?"
msgstr "אין לך חשבון?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "סיום"
@@ -1210,8 +1208,7 @@ msgstr "שגיאה"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "שגיאות ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "גלה כותרות"
msgid "Export"
msgstr "ייצוא"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "נכשל"
@@ -1450,13 +1446,13 @@ msgstr "פילמוגרפיה"
msgid "Filters"
msgstr "מסננים"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "הייבוא מ-{source} הסתיים."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "ייבוא הנתונים מ-Sofa שלך הושלם."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "ייבוא הנתונים מ-Sofa שלך הושלם."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "ייבוא"
msgid "Import {totalItems} items"
msgstr "ייבא {totalItems} פריטים"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "הייבוא הושלם"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "הייבוא נכשל"
@@ -1627,8 +1621,7 @@ msgstr "ייבא מ-{source}"
msgid "Import from {sourceLabel}"
msgstr "ייבא מ-{sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "הייבוא עדיין רץ ברקע. בדוק שוב מאוחר יותר."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "ייבא נתוני Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "יובא"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "יובאו {importedCount} פריטים מייצוא Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "מייבא נתונים"
#~ msgid "Importing data"
#~ msgstr "מייבא נתונים"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "מייבא מ-{source}"
@@ -1843,8 +1835,7 @@ msgstr "טוען…"
msgid "Login failed"
msgstr "הכניסה נכשלה"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "אבד החיבור לייבוא. בדוק את הסטטוס בהגדרות."
@@ -3062,8 +3053,7 @@ msgstr "התנתק משאר ההפעלות"
msgid "Skip for now"
msgstr "דלג לעת עתה"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "דולג"
@@ -3148,8 +3138,7 @@ msgstr "התחל לעקוב אחרי הצפיות שלך"
msgid "Starting at"
msgstr "מתחיל ב-"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "מתחיל ייבוא..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "פעולה זו עשויה לקחת מספר דקות עבור ספריות גדולות. אנא אל תסגור לשונית זו."
@@ -3646,8 +3634,7 @@ msgstr "אזהרות"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "אזהרות ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...e altri {remainingErrors}"
@@ -1043,8 +1042,7 @@ msgstr "Non hai un server?"
msgid "Don't have an account?"
msgstr "Non hai un account?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Fatto"
@@ -1210,8 +1208,7 @@ msgstr "Errore"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Errori ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Esplora titoli"
msgid "Export"
msgstr "Esporta"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Non riuscito"
@@ -1450,13 +1446,13 @@ msgstr "Filmografia"
msgid "Filters"
msgstr "Filtri"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Importazione da {source} completata."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Importazione del tuo export Sofa completata."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Importazione del tuo export Sofa completata."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importazione"
msgid "Import {totalItems} items"
msgstr "Importa {totalItems} elementi"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Importazione completata"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Importazione fallita"
@@ -1627,8 +1621,7 @@ msgstr "Importa da {source}"
msgid "Import from {sourceLabel}"
msgstr "Importa da {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "L'importazione è ancora in corso in background. Ricontrolla più tardi."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Importa dati Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Importati"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Importati {importedCount} elementi dall'export Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Importazione dati"
#~ msgid "Importing data"
#~ msgstr "Importazione dati"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importazione da {source} in corso"
@@ -1843,8 +1835,7 @@ msgstr "Caricamento…"
msgid "Login failed"
msgstr "Accesso non riuscito"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Connessione all'importazione persa. Controlla lo stato nelle impostazioni."
@@ -3062,8 +3053,7 @@ msgstr "Esci dalle altre sessioni"
msgid "Skip for now"
msgstr "Salta per ora"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Ignorati"
@@ -3148,8 +3138,7 @@ msgstr "Inizia a tracciare le tue visioni"
msgid "Starting at"
msgstr "Inizia alle"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Avvio importazione..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "L'operazione potrebbe richiedere alcuni minuti per librerie grandi. Non chiudere questa scheda."
@@ -3646,8 +3634,7 @@ msgstr "Avvisi"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Avvertenze ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...他{remainingErrors}件"
@@ -1043,8 +1042,7 @@ msgstr "サーバーをお持ちでないですか?"
msgid "Don't have an account?"
msgstr "アカウントをお持ちでないですか?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "完了"
@@ -1210,8 +1208,7 @@ msgstr "エラー"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "エラー ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "作品を探索"
msgid "Export"
msgstr "エクスポート"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "失敗"
@@ -1450,13 +1446,13 @@ msgstr "フィルモグラフィ"
msgid "Filters"
msgstr "フィルター"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "{source}からのインポートが完了しました。"
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Sofaのエクスポートのインポートが完了しました。"
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Sofaのエクスポートのインポートが完了しました。"
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "インポート"
msgid "Import {totalItems} items"
msgstr "{totalItems}件をインポート"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "インポート完了"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "インポート失敗"
@@ -1627,8 +1621,7 @@ msgstr "{source}からインポート"
msgid "Import from {sourceLabel}"
msgstr "{sourceLabel}からインポート"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "インポートはバックグラウンドで実行中です。後で確認してください。"
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Sofaデータをインポート"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "インポート済み"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Sofaエクスポートから{importedCount}件をインポートしました"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "データをインポート中"
#~ msgid "Importing data"
#~ msgstr "データをインポート中"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "{source}からインポート中"
@@ -1843,8 +1835,7 @@ msgstr "読み込み中…"
msgid "Login failed"
msgstr "ログインに失敗しました"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "インポートへの接続が切断されました。設定でステータスを確認してください。"
@@ -3062,8 +3053,7 @@ msgstr "他のセッションからサインアウト"
msgid "Skip for now"
msgstr "今はスキップ"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "スキップ済み"
@@ -3148,8 +3138,7 @@ msgstr "視聴のトラッキングを開始する"
msgid "Starting at"
msgstr "開始時刻"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "インポートを開始中..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "大規模なライブラリでは数分かかる場合があります。このタブを閉じないでください。"
@@ -3646,8 +3634,7 @@ msgstr "警告"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "警告({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...그 외 {remainingErrors}개 더"
@@ -1043,8 +1042,7 @@ msgstr "서버가 없으신가요?"
msgid "Don't have an account?"
msgstr "계정이 없으신가요?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "완료"
@@ -1210,8 +1208,7 @@ msgstr "오류"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "오류 ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "작품 탐색"
msgid "Export"
msgstr "내보내기"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "실패"
@@ -1450,13 +1446,13 @@ msgstr "필모그래피"
msgid "Filters"
msgstr "필터"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "{source}에서 가져오기가 완료되었습니다."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Sofa 내보내기 가져오기가 완료되었습니다."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Sofa 내보내기 가져오기가 완료되었습니다."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "가져오기"
msgid "Import {totalItems} items"
msgstr "항목 {totalItems}개 가져오기"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "가져오기 완료"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "가져오기 실패"
@@ -1627,8 +1621,7 @@ msgstr "{source}에서 가져오기"
msgid "Import from {sourceLabel}"
msgstr "{sourceLabel}에서 가져오기"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "가져오기가 백그라운드에서 계속 실행 중입니다. 나중에 다시 확인하세요."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Sofa 데이터 가져오기"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "가져옴"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Sofa 내보내기에서 {importedCount}개의 항목을 가져왔습니다"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "데이터 가져오는 중"
#~ msgid "Importing data"
#~ msgstr "데이터 가져오는 중"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "{source}에서 가져오는 중"
@@ -1843,8 +1835,7 @@ msgstr "로딩 중…"
msgid "Login failed"
msgstr "로그인 실패"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "가져오기 연결이 끊어졌습니다. 설정에서 상태를 확인하세요."
@@ -3062,8 +3053,7 @@ msgstr "다른 세션에서 로그아웃"
msgid "Skip for now"
msgstr "지금은 건너뛰기"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "건너뜀"
@@ -3148,8 +3138,7 @@ msgstr "시청 추적을 시작하세요"
msgid "Starting at"
msgstr "시작 시간"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "가져오기 시작 중..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "라이브러리가 크면 몇 분 정도 걸릴 수 있습니다. 이 탭을 닫지 마세요."
@@ -3646,8 +3634,7 @@ msgstr "경고"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "경고 ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...en {remainingErrors} meer"
@@ -1043,8 +1042,7 @@ msgstr "Geen server?"
msgid "Don't have an account?"
msgstr "Nog geen account?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Klaar"
@@ -1210,8 +1208,7 @@ msgstr "Fout"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Fouten ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Titels verkennen"
msgid "Export"
msgstr "Exporteren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Mislukt"
@@ -1450,13 +1446,13 @@ msgstr "Filmografie"
msgid "Filters"
msgstr ""
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Importeren vanuit {source} voltooid."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Importeren van je Sofa-export voltooid."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Importeren van je Sofa-export voltooid."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importeren"
msgid "Import {totalItems} items"
msgstr "{totalItems} items importeren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Importeren voltooid"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Importeren mislukt"
@@ -1627,8 +1621,7 @@ msgstr "Importeren vanuit {source}"
msgid "Import from {sourceLabel}"
msgstr "Importeren vanuit {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "Importeren loopt nog op de achtergrond. Controleer het later."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Sofa-gegevens importeren"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Geïmporteerd"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "{importedCount} items geïmporteerd vanuit Sofa-export"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Gegevens importeren"
#~ msgid "Importing data"
#~ msgstr "Gegevens importeren"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importeren vanuit {source}"
@@ -1843,8 +1835,7 @@ msgstr "Laden…"
msgid "Login failed"
msgstr "Aanmelden mislukt"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Verbinding met de import verbroken. Controleer de status in de instellingen."
@@ -3062,8 +3053,7 @@ msgstr "Andere sessies afmelden"
msgid "Skip for now"
msgstr "Nu overslaan"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Overgeslagen"
@@ -3148,8 +3138,7 @@ msgstr "Begin met het bijhouden van je kijkgeschiedenis"
msgid "Starting at"
msgstr "Starten om"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Import starten..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "Dit kan een paar minuten duren voor grote bibliotheken. Sluit dit tabblad niet."
@@ -3646,8 +3634,7 @@ msgstr "Waarschuwingen"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Waarschuwingen ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...e mais {remainingErrors}"
@@ -1043,8 +1042,7 @@ msgstr "Não tem um servidor?"
msgid "Don't have an account?"
msgstr "Não tem uma conta?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "Concluído"
@@ -1210,8 +1208,7 @@ msgstr "Erro"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "Erros ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "Explorar títulos"
msgid "Export"
msgstr "Exportar"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "Falhou"
@@ -1450,13 +1446,13 @@ msgstr "Filmografia"
msgid "Filters"
msgstr "Filtros"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "Importação de {source} concluída."
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Importação do seu ficheiro Sofa concluída."
#~ msgid "Finished importing your Sofa export."
#~ msgstr "Importação do seu ficheiro Sofa concluída."
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "Importar"
msgid "Import {totalItems} items"
msgstr "Importar {totalItems} itens"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "Importação concluída"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "Importação falhou"
@@ -1627,8 +1621,7 @@ msgstr "Importar de {source}"
msgid "Import from {sourceLabel}"
msgstr "Importar de {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "A importação ainda está em andamento em segundo plano. Verifique mais tarde."
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "Importar dados do Sofa"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "Importado"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "Importados {importedCount} itens do ficheiro Sofa"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "A importar dados"
#~ msgid "Importing data"
#~ msgstr "A importar dados"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "Importando de {source}"
@@ -1843,8 +1835,7 @@ msgstr "Carregando…"
msgid "Login failed"
msgstr "Falha no login"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "Conexão de importação perdida. Verifique o status nas configurações."
@@ -3062,8 +3053,7 @@ msgstr "Sair de outras sessões"
msgid "Skip for now"
msgstr "Ignorar por agora"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "Ignorado"
@@ -3148,8 +3138,7 @@ msgstr "Comece a registrar suas visualizações"
msgid "Starting at"
msgstr "Iniciando às"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "Iniciando importação..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "Isso pode levar alguns minutos para bibliotecas grandes. Por favor, não feche esta aba."
@@ -3646,8 +3634,7 @@ msgstr "Avisos"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "Avisos ({warningCount})"
+19 -32
View File
@@ -22,8 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "...and {remainingErrors} more"
msgstr "...及另外 {remainingErrors} 个"
@@ -1043,8 +1042,7 @@ msgstr "没有服务器?"
msgid "Don't have an account?"
msgstr "没有账户?"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Done"
msgstr "完成"
@@ -1210,8 +1208,7 @@ msgstr "错误"
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Errors ({errorCount})"
msgstr "错误 ({errorCount})"
@@ -1236,8 +1233,7 @@ msgstr "浏览影视"
msgid "Export"
msgstr "导出"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Failed"
msgstr "失败"
@@ -1450,13 +1446,13 @@ msgstr "作品列表"
msgid "Filters"
msgstr "筛选"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Finished importing from {source}."
msgstr "已完成从 {source} 导入。"
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "已完成导入您的 Sofa 导出文件。"
#~ msgid "Finished importing your Sofa export."
#~ msgstr "已完成导入您的 Sofa 导出文件。"
#: apps/web/src/components/titles/title-availability.tsx
#~ msgid "Free"
@@ -1605,13 +1601,11 @@ msgstr "导入"
msgid "Import {totalItems} items"
msgstr "导入 {totalItems} 个项目"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Import complete"
msgstr "导入完成"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import failed"
msgstr "导入失败"
@@ -1627,8 +1621,7 @@ msgstr "从 {source} 导入"
msgid "Import from {sourceLabel}"
msgstr "从 {sourceLabel} 导入"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Import is still running in the background. Check back later."
msgstr "导入仍在后台运行,请稍后再来查看。"
@@ -1646,8 +1639,7 @@ msgstr ""
msgid "Import Sofa data"
msgstr "导入 Sofa 数据"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Imported"
msgstr "已导入"
@@ -1664,10 +1656,10 @@ msgid "Imported {importedCount} items from Sofa export"
msgstr "已从 Sofa 导出文件导入 {importedCount} 个条目"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "正在导入数据"
#~ msgid "Importing data"
#~ msgstr "正在导入数据"
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Importing from {source}"
msgstr "正在从 {source} 导入"
@@ -1843,8 +1835,7 @@ msgstr "加载中…"
msgid "Login failed"
msgstr "登录失败"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/use-import-job.ts
msgid "Lost connection to import. Check status in settings."
msgstr "导入连接已断开,请在设置中查看状态。"
@@ -3062,8 +3053,7 @@ msgstr "退出其他会话"
msgid "Skip for now"
msgstr "暂时跳过"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Skipped"
msgstr "已跳过"
@@ -3148,8 +3138,7 @@ msgstr "开始记录您的观看历史"
msgid "Starting at"
msgstr "开始时间"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Starting import..."
msgstr "正在开始导入..."
@@ -3233,8 +3222,7 @@ msgstr ""
msgid "This import cannot be cancelled"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.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."
msgstr "大型媒体库可能需要几分钟。请勿关闭此标签页。"
@@ -3646,8 +3634,7 @@ msgstr "警告"
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/import-dialog-parts.tsx
msgid "Warnings ({warningCount})"
msgstr "警告({warningCount})"