mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: resolve QA report issues across routing, editor, i18n, and pipeline
- Add /tools/:toolId legacy redirect and catch-all 404 page (P1-12, P1-13) - Add Shift+O dodge/burn/sponge cycle and Ctrl+Y redo shortcut (P1-3, P1-4) - Fix Fit on Screen menu action to properly compute fit zoom (P1-8) - Add filename input to editor export dialog (P1-2) - Fix password validation mismatch: frontend now requires 8 chars (P1-11) - Add license info to Settings About section (P1-9) - Replace hardcoded strings in dropzone, files, pipeline with i18n keys (P1-17 to P1-25) - Add 20+ missing i18n keys to all 21 locale files - Translate Japanese editor.shapes and settings.aiFeatures sections (P1-19, P1-20) - Fix RTL: use logical CSS properties in sidebar, files, app-layout (P2-24 to P2-26) - Add single-file download button to pipeline results (P1-28) - Fix compress step settings restoration on pipeline load (P1-27) - Increase mobile nav touch targets to 44px minimum (P2-29)
This commit is contained in:
+11
-1
@@ -1,6 +1,6 @@
|
||||
import { APP_VERSION, en, shouldShowConsent } from "@snapotter/shared";
|
||||
import { Component, type ErrorInfo, lazy, type ReactNode, Suspense, useEffect } from "react";
|
||||
import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom";
|
||||
import { BrowserRouter, Navigate, Route, Routes, useLocation, useParams } from "react-router-dom";
|
||||
import { Toaster, toast } from "sonner";
|
||||
import { ConnectionMonitor } from "./components/common/connection-monitor";
|
||||
import { KeyboardShortcutProvider } from "./components/common/keyboard-shortcut-provider";
|
||||
@@ -32,6 +32,9 @@ const AnalyticsConsentPage = lazy(() =>
|
||||
const EditorPage = lazy(() =>
|
||||
import("./pages/editor-page").then((m) => ({ default: m.EditorPage })),
|
||||
);
|
||||
const NotFoundPage = lazy(() =>
|
||||
import("./pages/not-found-page").then((m) => ({ default: m.NotFoundPage })),
|
||||
);
|
||||
const ToolPage = lazy(() => import("./pages/tool-page").then((m) => ({ default: m.ToolPage })));
|
||||
|
||||
class ErrorBoundary extends Component<
|
||||
@@ -167,6 +170,11 @@ function AuthGuard({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
function ToolRedirect() {
|
||||
const { toolId } = useParams<{ toolId: string }>();
|
||||
return <Navigate to={`/${toolId}`} replace />;
|
||||
}
|
||||
|
||||
// Single page-level loading fallback — shown while JS for a route downloads.
|
||||
function PageLoader() {
|
||||
return (
|
||||
@@ -242,8 +250,10 @@ export function App() {
|
||||
<Route path="/color-effects" element={<Navigate to="/adjust-colors" replace />} />
|
||||
<Route path="/analytics-consent" element={<AnalyticsConsentPage />} />
|
||||
<Route path="/editor" element={<EditorPage />} />
|
||||
<Route path="/tools/:toolId" element={<ToolRedirect />} />
|
||||
<Route path="/:toolId" element={<ToolPage />} />
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</AuthGuard>
|
||||
|
||||
@@ -264,7 +264,7 @@ export function Dropzone({
|
||||
<>
|
||||
<div className="flex items-center gap-2 w-full max-w-xs">
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
<span className="text-xs text-muted-foreground">or</span>
|
||||
<span className="text-xs text-muted-foreground">{t.dropzone.orSeparator}</span>
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
</div>
|
||||
<div className="flex gap-2 w-full max-w-sm">
|
||||
@@ -295,7 +295,7 @@ export function Dropzone({
|
||||
disabled={urlLoading || !urlInput.trim()}
|
||||
className="rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
|
||||
>
|
||||
{urlLoading ? "..." : "Add"}
|
||||
{urlLoading ? t.dropzone.urlLoadingIndicator : t.dropzone.addUrlButton}
|
||||
</button>
|
||||
</div>
|
||||
{urlError && <p className="text-xs text-destructive">{urlError}</p>}
|
||||
|
||||
@@ -74,6 +74,7 @@ export function ExportDialog({ onClose }: { onClose: () => void }) {
|
||||
lockAspect: true,
|
||||
transparent: true,
|
||||
});
|
||||
const [filename, setFilename] = useState("export");
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||
const [copyStatus, setCopyStatus] = useState<"idle" | "copied">("idle");
|
||||
|
||||
@@ -200,7 +201,7 @@ export function ExportDialog({ onClose }: { onClose: () => void }) {
|
||||
if (json.downloadUrl) {
|
||||
const a = document.createElement("a");
|
||||
a.href = json.downloadUrl;
|
||||
a.download = `export.${settings.format}`;
|
||||
a.download = `${filename || "export"}.${settings.format}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
@@ -265,7 +266,7 @@ export function ExportDialog({ onClose }: { onClose: () => void }) {
|
||||
if (json.downloadUrl) {
|
||||
const a = document.createElement("a");
|
||||
a.href = json.downloadUrl;
|
||||
a.download = `export.${settings.format}`;
|
||||
a.download = `${filename || "export"}.${settings.format}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
@@ -282,7 +283,7 @@ export function ExportDialog({ onClose }: { onClose: () => void }) {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `export.${settings.format}`;
|
||||
a.download = `${filename || "export"}.${settings.format}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
@@ -457,6 +458,18 @@ export function ExportDialog({ onClose }: { onClose: () => void }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Filename */}
|
||||
<div>
|
||||
<span className="block text-xs font-medium text-muted-foreground mb-1.5">Filename</span>
|
||||
<input
|
||||
type="text"
|
||||
value={filename}
|
||||
onChange={(e) => setFilename(e.target.value)}
|
||||
placeholder="export"
|
||||
className="w-full px-2 py-1 text-xs bg-muted rounded border border-border text-foreground outline-none focus:border-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Format */}
|
||||
<div>
|
||||
<span className="block text-xs font-medium text-muted-foreground mb-1.5">Format</span>
|
||||
|
||||
@@ -57,6 +57,7 @@ function useMenuDefinitions(callbacks: MenuBarCallbacks): MenuDef[] {
|
||||
const setSelection = useEditorStore((s) => s.setSelection);
|
||||
const invertSelection = useEditorStore((s) => s.invertSelection);
|
||||
const canvasSize = useEditorStore((s) => s.canvasSize);
|
||||
const setPanOffset = useEditorStore((s) => s.setPanOffset);
|
||||
const rotateCanvas = useEditorStore((s) => s.rotateCanvas);
|
||||
const flipCanvasHorizontal = useEditorStore((s) => s.flipCanvasHorizontal);
|
||||
const flipCanvasVertical = useEditorStore((s) => s.flipCanvasVertical);
|
||||
@@ -327,11 +328,34 @@ function useMenuDefinitions(callbacks: MenuBarCallbacks): MenuDef[] {
|
||||
items: [
|
||||
{ label: "Zoom In", shortcut: mod("Ctrl+="), action: () => setZoom(zoom * 1.25) },
|
||||
{ label: "Zoom Out", shortcut: mod("Ctrl+-"), action: () => setZoom(zoom / 1.25) },
|
||||
{ label: "Fit on Screen", shortcut: mod("Ctrl+0"), action: () => setZoom(1) },
|
||||
{
|
||||
label: "Fit on Screen",
|
||||
shortcut: mod("Ctrl+0"),
|
||||
action: () => {
|
||||
const editorCanvas = document.querySelector("[data-testid='editor-canvas']");
|
||||
if (!editorCanvas) return;
|
||||
const { width: vw, height: vh } = editorCanvas.getBoundingClientRect();
|
||||
const scaleX = vw / canvasSize.width;
|
||||
const scaleY = vh / canvasSize.height;
|
||||
const fitZoom = Math.min(scaleX, scaleY) * 0.9;
|
||||
const offsetX = (vw - canvasSize.width * fitZoom) / 2;
|
||||
const offsetY = (vh - canvasSize.height * fitZoom) / 2;
|
||||
setZoom(fitZoom);
|
||||
setPanOffset({ x: offsetX, y: offsetY });
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Actual Pixels",
|
||||
shortcut: mod("Ctrl+1"),
|
||||
action: () => setZoom(1),
|
||||
action: () => {
|
||||
const editorCanvas = document.querySelector("[data-testid='editor-canvas']");
|
||||
if (!editorCanvas) return;
|
||||
const { width: vw, height: vh } = editorCanvas.getBoundingClientRect();
|
||||
const offsetX = (vw - canvasSize.width) / 2;
|
||||
const offsetY = (vh - canvasSize.height) / 2;
|
||||
setZoom(1);
|
||||
setPanOffset({ x: offsetX, y: offsetY });
|
||||
},
|
||||
dividerAfter: true,
|
||||
},
|
||||
{ label: "Rulers", checked: rulersVisible, action: toggleRulers },
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TOOLS } from "@snapotter/shared";
|
||||
import { FileImage, ImageIcon, Workflow } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
import {
|
||||
apiGetFileDetails,
|
||||
formatHeaders,
|
||||
@@ -74,6 +75,7 @@ interface FileDetailsProps {
|
||||
}
|
||||
|
||||
export function FileDetails({ mobile = false }: FileDetailsProps) {
|
||||
const { t } = useTranslation();
|
||||
const { selectedFileId } = useFilesPageStore();
|
||||
const setFiles = useFileStore((s) => s.setFiles);
|
||||
const navigate = useNavigate();
|
||||
@@ -139,11 +141,11 @@ export function FileDetails({ mobile = false }: FileDetailsProps) {
|
||||
"flex flex-col items-center justify-center text-muted-foreground",
|
||||
mobile
|
||||
? "flex flex-col gap-4"
|
||||
: "w-60 border-l border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
: "w-60 border-s border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
)}
|
||||
>
|
||||
<FileImage className="h-12 w-12 mb-3 opacity-30" />
|
||||
<p className="text-sm">Select a file to view details</p>
|
||||
<p className="text-sm">{t.files.selectFilePrompt}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -155,7 +157,7 @@ export function FileDetails({ mobile = false }: FileDetailsProps) {
|
||||
"flex items-center justify-center",
|
||||
mobile
|
||||
? "flex flex-col gap-4"
|
||||
: "w-60 border-l border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
: "w-60 border-s border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
)}
|
||||
>
|
||||
<div className="h-6 w-6 border-2 border-primary border-t-transparent rounded-full animate-spin" />
|
||||
@@ -171,7 +173,7 @@ export function FileDetails({ mobile = false }: FileDetailsProps) {
|
||||
"overflow-y-auto",
|
||||
mobile
|
||||
? "flex flex-col gap-4"
|
||||
: "w-60 border-l border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
: "w-60 border-s border-border p-4 shrink-0 hidden lg:flex flex-col",
|
||||
)}
|
||||
>
|
||||
{/* Thumbnail */}
|
||||
@@ -187,24 +189,28 @@ export function FileDetails({ mobile = false }: FileDetailsProps) {
|
||||
<div className="flex-1">
|
||||
<div className="rounded-lg border border-border overflow-hidden">
|
||||
<div className="bg-blue-500/10 border-b border-border px-3 py-2">
|
||||
<h4 className="text-sm font-semibold text-blue-600 dark:text-blue-400">File Details</h4>
|
||||
<h4 className="text-sm font-semibold text-blue-600 dark:text-blue-400">
|
||||
{t.files.fileDetailsHeading}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="divide-y divide-border">
|
||||
<DetailRow label="Name" value={details.originalName} />
|
||||
<DetailRow label={t.files.name} value={details.originalName} />
|
||||
<DetailRow
|
||||
label="Format"
|
||||
label={t.files.format}
|
||||
value={details.mimeType.replace("image/", "").toUpperCase()}
|
||||
/>
|
||||
<DetailRow label="Size" value={formatSize(details.size)} />
|
||||
<DetailRow label={t.files.size} value={formatSize(details.size)} />
|
||||
<DetailRow
|
||||
label="Dimensions"
|
||||
label={t.files.dimensions}
|
||||
value={details.width && details.height ? `${details.width} × ${details.height}` : "—"}
|
||||
/>
|
||||
<DetailRow label="Version" value={`V${details.version}`} />
|
||||
<DetailRow label={t.files.version} value={`V${details.version}`} />
|
||||
<DetailRow
|
||||
label="Tools Used"
|
||||
label={t.files.toolsUsed}
|
||||
value={
|
||||
details.toolChain.length > 0 ? details.toolChain.map(toolName).join(", ") : "None"
|
||||
details.toolChain.length > 0
|
||||
? details.toolChain.map(toolName).join(", ")
|
||||
: t.files.none
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { Download, Search, Trash2, Workflow } from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
import { getFileDownloadUrl } from "@/lib/api";
|
||||
import { format } from "@/lib/format";
|
||||
import { useFilesPageStore } from "@/stores/files-page-store";
|
||||
import { FileListItem } from "./file-list-item";
|
||||
|
||||
export function FileList() {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
files,
|
||||
checkedIds,
|
||||
@@ -61,7 +64,7 @@ export function FileList() {
|
||||
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search files..."
|
||||
placeholder={t.files.searchPlaceholder}
|
||||
value={inputValue}
|
||||
onChange={handleSearchChange}
|
||||
className="w-full ps-8 pe-3 py-1.5 text-sm bg-muted rounded-lg border border-border focus:outline-none focus:ring-2 focus:ring-primary/50 text-foreground placeholder:text-muted-foreground"
|
||||
@@ -78,7 +81,9 @@ export function FileList() {
|
||||
className="h-4 w-4 accent-primary"
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground flex-1">
|
||||
{someChecked ? `${checkedIds.size} selected` : `${files.length} files`}
|
||||
{someChecked
|
||||
? format(t.files.selectedCount, { count: checkedIds.size })
|
||||
: format(t.files.fileCount, { count: files.length })}
|
||||
</span>
|
||||
{someChecked && (
|
||||
<>
|
||||
@@ -88,7 +93,7 @@ export function FileList() {
|
||||
className="flex items-center gap-1 px-2 py-1 text-xs text-destructive hover:bg-destructive/10 rounded-lg transition-colors"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
Delete
|
||||
{t.files.delete}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -96,7 +101,7 @@ export function FileList() {
|
||||
className="flex items-center gap-1 px-2 py-1 text-xs text-primary hover:bg-primary/10 rounded-lg transition-colors"
|
||||
>
|
||||
<Workflow className="h-3.5 w-3.5" />
|
||||
Pipeline
|
||||
{t.files.pipeline}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -104,7 +109,7 @@ export function FileList() {
|
||||
className="flex items-center gap-1 px-2 py-1 text-xs text-foreground hover:bg-muted rounded-lg transition-colors"
|
||||
>
|
||||
<Download className="h-3.5 w-3.5" />
|
||||
Download
|
||||
{t.files.download}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
@@ -124,7 +129,7 @@ export function FileList() {
|
||||
)}
|
||||
{!loading && !error && files.length === 0 && (
|
||||
<div className="flex items-center justify-center h-32">
|
||||
<p className="text-sm text-muted-foreground">No files found</p>
|
||||
<p className="text-sm text-muted-foreground">{t.files.noFilesFound}</p>
|
||||
</div>
|
||||
)}
|
||||
{!loading && !error && files.map((file) => <FileListItem key={file.id} file={file} />)}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { Clock, Upload } from "lucide-react";
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useFilesPageStore } from "@/stores/files-page-store";
|
||||
|
||||
export function FilesNav() {
|
||||
const { t } = useTranslation();
|
||||
const { activeTab, setActiveTab } = useFilesPageStore();
|
||||
const items = [
|
||||
{ id: "recent" as const, label: "Recent", icon: Clock },
|
||||
{ id: "upload" as const, label: "Upload Files", icon: Upload },
|
||||
{ id: "recent" as const, label: t.files.recentTab, icon: Clock },
|
||||
{ id: "upload" as const, label: t.files.uploadTab, icon: Upload },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="w-48 border-r border-border p-4 shrink-0 hidden md:block">
|
||||
<h3 className="text-sm font-semibold text-foreground mb-3">My Files</h3>
|
||||
<div className="w-48 border-e border-border p-4 shrink-0 hidden md:block">
|
||||
<h3 className="text-sm font-semibold text-foreground mb-3">{t.files.myFiles}</h3>
|
||||
<div className="space-y-1">
|
||||
{items.map((item) => (
|
||||
<button
|
||||
|
||||
@@ -67,7 +67,7 @@ export function AppLayout({
|
||||
className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm cursor-default"
|
||||
onClick={() => setMobileSidebarOpen(false)}
|
||||
/>
|
||||
<div className="fixed inset-y-0 left-0 z-50 w-64 bg-background border-r border-border shadow-xl animate-in slide-in-from-left">
|
||||
<div className="fixed inset-y-0 start-0 z-50 w-64 bg-background border-e border-border shadow-xl animate-in slide-in-from-left">
|
||||
<div className="flex items-center justify-between p-3 border-b border-border">
|
||||
<div className="flex items-center gap-2">
|
||||
<OtterLogo className="h-5 w-5 text-primary" />
|
||||
|
||||
@@ -110,7 +110,7 @@ export function Sidebar({
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="flex flex-col items-center w-16 bg-sidebar border-r border-border py-3 gap-1 shrink-0">
|
||||
<aside className="flex flex-col items-center w-16 bg-sidebar border-e border-border py-3 gap-1 shrink-0">
|
||||
<div className="mb-2 flex items-center justify-center">
|
||||
<OtterLogo className="h-7 w-7 text-primary" />
|
||||
</div>
|
||||
|
||||
@@ -21,10 +21,12 @@ export function CompressControls({ settings: initialSettings, onChange }: Compre
|
||||
const [targetSizeValue, setTargetSizeValue] = useState("");
|
||||
const [sizeUnit, setSizeUnit] = useState<SizeUnit>("KB");
|
||||
|
||||
const initializedRef = useRef(false);
|
||||
const prevSettingsKeyRef = useRef<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!initialSettings || initializedRef.current) return;
|
||||
initializedRef.current = true;
|
||||
if (!initialSettings) return;
|
||||
const key = JSON.stringify(initialSettings);
|
||||
if (prevSettingsKeyRef.current === key) return;
|
||||
prevSettingsKeyRef.current = key;
|
||||
if (initialSettings.mode != null) setMode(initialSettings.mode as CompressMode);
|
||||
if (initialSettings.quality != null) setQuality(Number(initialSettings.quality));
|
||||
if (initialSettings.targetSizeKb != null)
|
||||
|
||||
@@ -129,7 +129,7 @@ function SortableStep({
|
||||
e.stopPropagation();
|
||||
onRemove();
|
||||
}}
|
||||
title="Remove"
|
||||
title={t.automate.removeStep}
|
||||
className="p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
@@ -159,6 +159,7 @@ export function PipelineBuilder({
|
||||
onUpdateSettings,
|
||||
onToggleStep,
|
||||
}: PipelineBuilderProps) {
|
||||
const { t } = useTranslation();
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
||||
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
|
||||
@@ -177,10 +178,8 @@ export function PipelineBuilder({
|
||||
<div className="p-4 rounded-full bg-muted/50 mb-4">
|
||||
<FileImage className="h-8 w-8 text-muted-foreground" />
|
||||
</div>
|
||||
<h3 className="text-sm font-medium text-foreground mb-1">No steps yet</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-[240px]">
|
||||
Click tools from the palette to build your pipeline
|
||||
</p>
|
||||
<h3 className="text-sm font-medium text-foreground mb-1">{t.automate.noStepsHeading}</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-[240px]">{t.automate.addToolsPrompt}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,12 +66,16 @@ export function ToolPalette({ onAddStep, className }: ToolPaletteProps) {
|
||||
return (
|
||||
<div className={cn("flex flex-col h-full", className)}>
|
||||
<div className="px-3 pt-3 pb-2 shrink-0">
|
||||
<SearchBar value={search} onChange={setSearch} placeholder="Search tools..." />
|
||||
<SearchBar
|
||||
value={search}
|
||||
onChange={setSearch}
|
||||
placeholder={t.automate.searchToolsPlaceholder}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto px-3 pb-3">
|
||||
{availableTools.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground text-center py-8">No tools found</p>
|
||||
<p className="text-sm text-muted-foreground text-center py-8">{t.common.noToolsFound}</p>
|
||||
) : isSearching ? (
|
||||
<div className="space-y-1">
|
||||
{availableTools.map((tool) => (
|
||||
|
||||
@@ -41,6 +41,8 @@ const SHAPE_CYCLE: ToolType[] = [
|
||||
"shape-polygon",
|
||||
"shape-star",
|
||||
];
|
||||
// Dodge/burn/sponge cycle
|
||||
const DODGE_CYCLE: ToolType[] = ["dodge", "burn", "sponge"];
|
||||
// Fill/gradient cycle
|
||||
const FILL_CYCLE: ToolType[] = ["fill", "gradient"];
|
||||
|
||||
@@ -199,12 +201,29 @@ export function useEditorShortcuts(callbacks?: {
|
||||
{ preventDefault: true },
|
||||
);
|
||||
|
||||
// O - Dodge tool
|
||||
// O - Dodge/Burn/Sponge (cycles)
|
||||
useHotkeys(
|
||||
"o",
|
||||
() => {
|
||||
if (isInputFocused()) return;
|
||||
useEditorStore.getState().setTool("dodge");
|
||||
const current = useEditorStore.getState().activeTool;
|
||||
if (DODGE_CYCLE.includes(current)) {
|
||||
useEditorStore.getState().setTool(cycleSubtool(current, DODGE_CYCLE));
|
||||
} else {
|
||||
useEditorStore.getState().setTool("dodge");
|
||||
}
|
||||
},
|
||||
{ preventDefault: true },
|
||||
);
|
||||
|
||||
// Shift+O - Cycle dodge/burn/sponge subtypes
|
||||
useHotkeys(
|
||||
"shift+o",
|
||||
() => {
|
||||
if (isInputFocused()) return;
|
||||
useEditorStore
|
||||
.getState()
|
||||
.setTool(cycleSubtool(useEditorStore.getState().activeTool, DODGE_CYCLE));
|
||||
},
|
||||
{ preventDefault: true },
|
||||
);
|
||||
@@ -361,6 +380,16 @@ export function useEditorShortcuts(callbacks?: {
|
||||
{ preventDefault: true },
|
||||
);
|
||||
|
||||
// Ctrl+Y / Cmd+Y - Redo (alternative)
|
||||
useHotkeys(
|
||||
"mod+y",
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
useEditorStore.temporal.getState().redo();
|
||||
},
|
||||
{ preventDefault: true },
|
||||
);
|
||||
|
||||
// Ctrl+S / Cmd+S - Save project
|
||||
useHotkeys(
|
||||
"mod+s",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
|
||||
export function NotFoundPage() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center bg-background text-foreground">
|
||||
<div className="text-center space-y-4 max-w-md px-6">
|
||||
<h1 className="text-6xl font-bold text-primary">404</h1>
|
||||
<h2 className="text-xl font-semibold">{t.common.pageNotFound}</h2>
|
||||
<p className="text-sm text-muted-foreground">{t.common.pageNotFoundDescription}</p>
|
||||
<Link
|
||||
to="/"
|
||||
className="inline-block px-4 py-2 rounded-lg bg-primary text-primary-foreground text-sm font-medium"
|
||||
>
|
||||
{t.common.goHome}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -36,6 +36,9 @@ export const ar: TranslationKeys = {
|
||||
unexpectedError: "حدث خطأ غير متوقع.",
|
||||
retry: "إعادة المحاولة",
|
||||
privacyPolicy: "سياسة الخصوصية",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "الأساسيات",
|
||||
@@ -1679,6 +1682,8 @@ export const ar: TranslationKeys = {
|
||||
githubLink: "مستودع GitHub",
|
||||
docsLink: "التوثيق",
|
||||
apiRefLink: "مرجع API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1819,6 +1824,8 @@ export const ar: TranslationKeys = {
|
||||
pipelineName: "اسم Pipeline",
|
||||
pipelineDescription: "الوصف (اختياري)",
|
||||
noStepsPrompt: "أضف خطوات لبناء أتمتتك",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "خطوة",
|
||||
},
|
||||
nav: {
|
||||
@@ -1836,6 +1843,25 @@ export const ar: TranslationKeys = {
|
||||
uploadTab: "رفع",
|
||||
fileDetailsAriaLabel: "تفاصيل الملف",
|
||||
fileDetailsHeading: "تفاصيل الملف",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "نوع الملف هذا غير مدعوم بهذه الأداة",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const de: TranslationKeys = {
|
||||
unexpectedError: "Ein unerwarteter Fehler ist aufgetreten.",
|
||||
retry: "Erneut versuchen",
|
||||
privacyPolicy: "Datenschutzerklaerung",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Grundlagen",
|
||||
@@ -1704,6 +1707,8 @@ export const de: TranslationKeys = {
|
||||
githubLink: "GitHub-Repository",
|
||||
docsLink: "Dokumentation",
|
||||
apiRefLink: "API-Referenz (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1848,6 +1853,8 @@ export const de: TranslationKeys = {
|
||||
pipelineName: "Pipeline-Name",
|
||||
pipelineDescription: "Beschreibung (optional)",
|
||||
noStepsPrompt: "Fuegen Sie Schritte hinzu, um Ihre Automatisierung zu erstellen",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Schritt",
|
||||
},
|
||||
nav: {
|
||||
@@ -1865,6 +1872,25 @@ export const de: TranslationKeys = {
|
||||
uploadTab: "Hochladen",
|
||||
fileDetailsAriaLabel: "Dateidetails",
|
||||
fileDetailsHeading: "Dateidetails",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Dieser Dateityp wird von diesem Werkzeug nicht unterstuetzt",
|
||||
|
||||
@@ -34,6 +34,9 @@ export const en = {
|
||||
somethingWentWrong: "Something went wrong",
|
||||
unexpectedError: "An unexpected error occurred.",
|
||||
privacyPolicy: "Privacy Policy",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Essentials",
|
||||
@@ -1638,6 +1641,8 @@ export const en = {
|
||||
githubLink: "GitHub Repository",
|
||||
docsLink: "Documentation",
|
||||
apiRefLink: "API Reference (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1779,6 +1784,8 @@ export const en = {
|
||||
pipelineName: "Pipeline Name",
|
||||
pipelineDescription: "Description (optional)",
|
||||
noStepsPrompt: "Add steps to build your automation",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Step",
|
||||
},
|
||||
nav: {
|
||||
@@ -1796,6 +1803,25 @@ export const en = {
|
||||
uploadTab: "Upload",
|
||||
fileDetailsAriaLabel: "File Details",
|
||||
fileDetailsHeading: "File Details",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "This file type is not supported by this tool",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const es: TranslationKeys = {
|
||||
unexpectedError: "Ocurrio un error inesperado.",
|
||||
retry: "Reintentar",
|
||||
privacyPolicy: "Politica de privacidad",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Esenciales",
|
||||
@@ -1683,6 +1686,8 @@ export const es: TranslationKeys = {
|
||||
githubLink: "Repositorio en GitHub",
|
||||
docsLink: "Documentacion",
|
||||
apiRefLink: "Referencia API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1825,6 +1830,8 @@ export const es: TranslationKeys = {
|
||||
pipelineName: "Nombre del Pipeline",
|
||||
pipelineDescription: "Descripcion (opcional)",
|
||||
noStepsPrompt: "Agrega pasos para construir tu automatizacion",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Paso",
|
||||
},
|
||||
nav: {
|
||||
@@ -1842,6 +1849,25 @@ export const es: TranslationKeys = {
|
||||
uploadTab: "Subir",
|
||||
fileDetailsAriaLabel: "Detalles del archivo",
|
||||
fileDetailsHeading: "Detalles del archivo",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Este tipo de archivo no es compatible con esta herramienta",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const fr: TranslationKeys = {
|
||||
unexpectedError: "Une erreur inattendue est survenue.",
|
||||
retry: "Réessayer",
|
||||
privacyPolicy: "Politique de confidentialite",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Essentiels",
|
||||
@@ -1702,6 +1705,8 @@ export const fr: TranslationKeys = {
|
||||
githubLink: "Depot GitHub",
|
||||
docsLink: "Documentation",
|
||||
apiRefLink: "Reference API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1846,6 +1851,8 @@ export const fr: TranslationKeys = {
|
||||
pipelineName: "Nom du Pipeline",
|
||||
pipelineDescription: "Description (optionnel)",
|
||||
noStepsPrompt: "Ajoutez des etapes pour construire votre automatisation",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Etape",
|
||||
},
|
||||
nav: {
|
||||
@@ -1863,6 +1870,25 @@ export const fr: TranslationKeys = {
|
||||
uploadTab: "Importer",
|
||||
fileDetailsAriaLabel: "Details du fichier",
|
||||
fileDetailsHeading: "Details du fichier",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Ce type de fichier n'est pas pris en charge par cet outil",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const hi: TranslationKeys = {
|
||||
unexpectedError: "एक अप्रत्याशित त्रुटि हुई।",
|
||||
retry: "पुनः प्रयास करें",
|
||||
privacyPolicy: "गोपनीयता नीति",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "आवश्यक टूल्स",
|
||||
@@ -1675,6 +1678,8 @@ export const hi: TranslationKeys = {
|
||||
githubLink: "GitHub रिपॉज़िटरी",
|
||||
docsLink: "डॉक्यूमेंटेशन",
|
||||
apiRefLink: "API रेफरेंस (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1816,6 +1821,8 @@ export const hi: TranslationKeys = {
|
||||
pipelineName: "Pipeline का नाम",
|
||||
pipelineDescription: "विवरण (वैकल्पिक)",
|
||||
noStepsPrompt: "अपना ऑटोमेशन बनाने के लिए स्टेप्स जोड़ें",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "स्टेप",
|
||||
},
|
||||
nav: {
|
||||
@@ -1833,6 +1840,25 @@ export const hi: TranslationKeys = {
|
||||
uploadTab: "अपलोड",
|
||||
fileDetailsAriaLabel: "फाइल विवरण",
|
||||
fileDetailsHeading: "फाइल विवरण",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "इस फाइल प्रकार को यह टूल सपोर्ट नहीं करता",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const id: TranslationKeys = {
|
||||
unexpectedError: "Terjadi kesalahan yang tidak terduga.",
|
||||
retry: "Coba lagi",
|
||||
privacyPolicy: "Kebijakan Privasi",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Dasar",
|
||||
@@ -1691,6 +1694,8 @@ export const id: TranslationKeys = {
|
||||
githubLink: "Repositori GitHub",
|
||||
docsLink: "Dokumentasi",
|
||||
apiRefLink: "Referensi API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1833,6 +1838,8 @@ export const id: TranslationKeys = {
|
||||
pipelineName: "Nama Pipeline",
|
||||
pipelineDescription: "Deskripsi (opsional)",
|
||||
noStepsPrompt: "Tambahkan langkah untuk membangun otomasi Anda",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Langkah",
|
||||
},
|
||||
nav: {
|
||||
@@ -1850,6 +1857,25 @@ export const id: TranslationKeys = {
|
||||
uploadTab: "Unggah",
|
||||
fileDetailsAriaLabel: "Detail File",
|
||||
fileDetailsHeading: "Detail File",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Jenis file ini tidak didukung oleh alat ini",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const it: TranslationKeys = {
|
||||
unexpectedError: "Si e verificato un errore imprevisto.",
|
||||
retry: "Riprova",
|
||||
privacyPolicy: "Informativa sulla privacy",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Essenziali",
|
||||
@@ -1697,6 +1700,8 @@ export const it: TranslationKeys = {
|
||||
githubLink: "Repository GitHub",
|
||||
docsLink: "Documentazione",
|
||||
apiRefLink: "Riferimento API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1840,6 +1845,8 @@ export const it: TranslationKeys = {
|
||||
pipelineName: "Nome del Pipeline",
|
||||
pipelineDescription: "Descrizione (opzionale)",
|
||||
noStepsPrompt: "Aggiungi passaggi per costruire la tua automazione",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Passaggio",
|
||||
},
|
||||
nav: {
|
||||
@@ -1857,6 +1864,25 @@ export const it: TranslationKeys = {
|
||||
uploadTab: "Carica",
|
||||
fileDetailsAriaLabel: "Dettagli file",
|
||||
fileDetailsHeading: "Dettagli file",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Questo tipo di file non e supportato da questo strumento",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const ja: TranslationKeys = {
|
||||
unexpectedError: "予期しないエラーが発生しました。",
|
||||
retry: "再試行",
|
||||
privacyPolicy: "プライバシーポリシー",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "基本ツール",
|
||||
@@ -1648,6 +1651,8 @@ export const ja: TranslationKeys = {
|
||||
githubLink: "GitHubリポジトリ",
|
||||
docsLink: "ドキュメント",
|
||||
apiRefLink: "APIリファレンス(Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1789,6 +1794,8 @@ export const ja: TranslationKeys = {
|
||||
pipelineName: "Pipeline名",
|
||||
pipelineDescription: "説明(任意)",
|
||||
noStepsPrompt: "ステップを追加して自動化を構築",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "ステップ",
|
||||
},
|
||||
nav: {
|
||||
@@ -1806,6 +1813,25 @@ export const ja: TranslationKeys = {
|
||||
uploadTab: "アップロード",
|
||||
fileDetailsAriaLabel: "ファイル詳細",
|
||||
fileDetailsHeading: "ファイル詳細",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "このツールではサポートされていないファイルタイプです",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const ko: TranslationKeys = {
|
||||
unexpectedError: "예기치 않은 오류가 발생했습니다.",
|
||||
retry: "재시도",
|
||||
privacyPolicy: "개인정보 처리방침",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "기본 도구",
|
||||
@@ -1633,6 +1636,8 @@ export const ko: TranslationKeys = {
|
||||
githubLink: "GitHub 저장소",
|
||||
docsLink: "문서",
|
||||
apiRefLink: "API 레퍼런스 (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1774,6 +1779,8 @@ export const ko: TranslationKeys = {
|
||||
pipelineName: "Pipeline 이름",
|
||||
pipelineDescription: "설명 (선택)",
|
||||
noStepsPrompt: "단계를 추가하여 자동화를 구성하세요",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "단계",
|
||||
},
|
||||
nav: {
|
||||
@@ -1791,6 +1798,25 @@ export const ko: TranslationKeys = {
|
||||
uploadTab: "업로드",
|
||||
fileDetailsAriaLabel: "파일 상세",
|
||||
fileDetailsHeading: "파일 상세",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "이 도구에서 지원하지 않는 파일 형식입니다",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const nl: TranslationKeys = {
|
||||
unexpectedError: "Er is een onverwachte fout opgetreden.",
|
||||
retry: "Opnieuw proberen",
|
||||
privacyPolicy: "Privacybeleid",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Basistools",
|
||||
@@ -1694,6 +1697,8 @@ export const nl: TranslationKeys = {
|
||||
githubLink: "GitHub-repository",
|
||||
docsLink: "Documentatie",
|
||||
apiRefLink: "API-referentie (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1836,6 +1841,8 @@ export const nl: TranslationKeys = {
|
||||
pipelineName: "Pipeline-naam",
|
||||
pipelineDescription: "Beschrijving (optioneel)",
|
||||
noStepsPrompt: "Voeg stappen toe om je automatisering te bouwen",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Stap",
|
||||
},
|
||||
nav: {
|
||||
@@ -1853,6 +1860,25 @@ export const nl: TranslationKeys = {
|
||||
uploadTab: "Uploaden",
|
||||
fileDetailsAriaLabel: "Bestandsdetails",
|
||||
fileDetailsHeading: "Bestandsdetails",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Dit bestandstype wordt niet ondersteund door deze tool",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const pl: TranslationKeys = {
|
||||
unexpectedError: "Wystąpił nieoczekiwany błąd.",
|
||||
retry: "Ponów",
|
||||
privacyPolicy: "Polityka prywatności",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Podstawowe",
|
||||
@@ -1700,6 +1703,8 @@ export const pl: TranslationKeys = {
|
||||
githubLink: "Repozytorium GitHub",
|
||||
docsLink: "Dokumentacja",
|
||||
apiRefLink: "Dokumentacja API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1843,6 +1848,8 @@ export const pl: TranslationKeys = {
|
||||
pipelineName: "Nazwa Pipeline",
|
||||
pipelineDescription: "Opis (opcjonalnie)",
|
||||
noStepsPrompt: "Dodaj kroki, aby zbudować automatyzację",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Krok",
|
||||
},
|
||||
nav: {
|
||||
@@ -1860,6 +1867,25 @@ export const pl: TranslationKeys = {
|
||||
uploadTab: "Przesyłanie",
|
||||
fileDetailsAriaLabel: "Szczegóły pliku",
|
||||
fileDetailsHeading: "Szczegóły pliku",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Ten typ pliku nie jest obsługiwany przez to narzędzie",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const ptBR: TranslationKeys = {
|
||||
unexpectedError: "Ocorreu um erro inesperado.",
|
||||
retry: "Tentar novamente",
|
||||
privacyPolicy: "Politica de privacidade",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Essenciais",
|
||||
@@ -1693,6 +1696,8 @@ export const ptBR: TranslationKeys = {
|
||||
githubLink: "Repositorio no GitHub",
|
||||
docsLink: "Documentacao",
|
||||
apiRefLink: "Referencia da API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1836,6 +1841,8 @@ export const ptBR: TranslationKeys = {
|
||||
pipelineName: "Nome do Pipeline",
|
||||
pipelineDescription: "Descricao (opcional)",
|
||||
noStepsPrompt: "Adicione passos para construir sua automacao",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Passo",
|
||||
},
|
||||
nav: {
|
||||
@@ -1853,6 +1860,25 @@ export const ptBR: TranslationKeys = {
|
||||
uploadTab: "Enviar",
|
||||
fileDetailsAriaLabel: "Detalhes do arquivo",
|
||||
fileDetailsHeading: "Detalhes do arquivo",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Este tipo de arquivo nao e suportado por esta ferramenta",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const ru: TranslationKeys = {
|
||||
unexpectedError: "Произошла непредвиденная ошибка.",
|
||||
retry: "Повторить",
|
||||
privacyPolicy: "Политика конфиденциальности",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Основные",
|
||||
@@ -1693,6 +1696,8 @@ export const ru: TranslationKeys = {
|
||||
githubLink: "Репозиторий GitHub",
|
||||
docsLink: "Документация",
|
||||
apiRefLink: "Справочник API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1835,6 +1840,8 @@ export const ru: TranslationKeys = {
|
||||
pipelineName: "Название Pipeline",
|
||||
pipelineDescription: "Описание (необязательно)",
|
||||
noStepsPrompt: "Добавьте шаги для построения автоматизации",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Шаг",
|
||||
},
|
||||
nav: {
|
||||
@@ -1852,6 +1859,25 @@ export const ru: TranslationKeys = {
|
||||
uploadTab: "Загрузка",
|
||||
fileDetailsAriaLabel: "Сведения о файле",
|
||||
fileDetailsHeading: "Сведения о файле",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Этот тип файла не поддерживается данным инструментом",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const sv: TranslationKeys = {
|
||||
unexpectedError: "Ett ovantat fel uppstod.",
|
||||
retry: "Försök igen",
|
||||
privacyPolicy: "Integritetspolicy",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Grundlaggande",
|
||||
@@ -1689,6 +1692,8 @@ export const sv: TranslationKeys = {
|
||||
githubLink: "GitHub-arkiv",
|
||||
docsLink: "Dokumentation",
|
||||
apiRefLink: "API-referens (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1830,6 +1835,8 @@ export const sv: TranslationKeys = {
|
||||
pipelineName: "Pipeline-namn",
|
||||
pipelineDescription: "Beskrivning (valfritt)",
|
||||
noStepsPrompt: "Lagg till steg for att bygga din automatisering",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Steg",
|
||||
},
|
||||
nav: {
|
||||
@@ -1847,6 +1854,25 @@ export const sv: TranslationKeys = {
|
||||
uploadTab: "Ladda upp",
|
||||
fileDetailsAriaLabel: "Fildetaljer",
|
||||
fileDetailsHeading: "Fildetaljer",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Denna filtyp stods inte av detta verktyg",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const th: TranslationKeys = {
|
||||
unexpectedError: "เกิดข้อผิดพลาดที่ไม่คาดคิด",
|
||||
retry: "ลองใหม่",
|
||||
privacyPolicy: "นโยบายความเป็นส่วนตัว",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "พื้นฐาน",
|
||||
@@ -1667,6 +1670,8 @@ export const th: TranslationKeys = {
|
||||
githubLink: "คลังเก็บโค้ด GitHub",
|
||||
docsLink: "เอกสารประกอบ",
|
||||
apiRefLink: "อ้างอิง API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1807,6 +1812,8 @@ export const th: TranslationKeys = {
|
||||
pipelineName: "ชื่อ Pipeline",
|
||||
pipelineDescription: "คำอธิบาย (ไม่บังคับ)",
|
||||
noStepsPrompt: "เพิ่มขั้นตอนเพื่อสร้างการทำงานอัตโนมัติ",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "ขั้นตอน",
|
||||
},
|
||||
nav: {
|
||||
@@ -1824,6 +1831,25 @@ export const th: TranslationKeys = {
|
||||
uploadTab: "อัปโหลด",
|
||||
fileDetailsAriaLabel: "รายละเอียดไฟล์",
|
||||
fileDetailsHeading: "รายละเอียดไฟล์",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "ไฟล์ประเภทนี้ไม่รองรับโดยเครื่องมือนี้",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const tr: TranslationKeys = {
|
||||
unexpectedError: "Beklenmeyen bir hata oluştu.",
|
||||
retry: "Yeniden dene",
|
||||
privacyPolicy: "Gizlilik Politikası",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Temel Araçlar",
|
||||
@@ -1697,6 +1700,8 @@ export const tr: TranslationKeys = {
|
||||
githubLink: "GitHub Deposu",
|
||||
docsLink: "Dokümantasyon",
|
||||
apiRefLink: "API Referansı (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1840,6 +1845,8 @@ export const tr: TranslationKeys = {
|
||||
pipelineName: "Pipeline Adı",
|
||||
pipelineDescription: "Açıklama (isteğe bağlı)",
|
||||
noStepsPrompt: "Otomasyonunuzu oluşturmak için adımlar ekleyin",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Adım",
|
||||
},
|
||||
nav: {
|
||||
@@ -1857,6 +1864,25 @@ export const tr: TranslationKeys = {
|
||||
uploadTab: "Yükle",
|
||||
fileDetailsAriaLabel: "Dosya Ayrıntıları",
|
||||
fileDetailsHeading: "Dosya Ayrıntıları",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Bu dosya türü bu araç tarafından desteklenmiyor",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const uk: TranslationKeys = {
|
||||
unexpectedError: "Сталася неочікувана помилка.",
|
||||
retry: "Повторити",
|
||||
privacyPolicy: "Політика конфіденційності",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Основні",
|
||||
@@ -1693,6 +1696,8 @@ export const uk: TranslationKeys = {
|
||||
githubLink: "Репозиторій GitHub",
|
||||
docsLink: "Документація",
|
||||
apiRefLink: "Довідник API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1836,6 +1841,8 @@ export const uk: TranslationKeys = {
|
||||
pipelineName: "Назва Pipeline",
|
||||
pipelineDescription: "Опис (необов'язково)",
|
||||
noStepsPrompt: "Додайте кроки для побудови автоматизації",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Крок",
|
||||
},
|
||||
nav: {
|
||||
@@ -1853,6 +1860,25 @@ export const uk: TranslationKeys = {
|
||||
uploadTab: "Завантаження",
|
||||
fileDetailsAriaLabel: "Відомості про файл",
|
||||
fileDetailsHeading: "Відомості про файл",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Цей тип файлу не підтримується цим інструментом",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const vi: TranslationKeys = {
|
||||
unexpectedError: "Đã xảy ra lỗi không mong muốn.",
|
||||
retry: "Thử lại",
|
||||
privacyPolicy: "Chính sách bảo mật",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "Cơ bản",
|
||||
@@ -1689,6 +1692,8 @@ export const vi: TranslationKeys = {
|
||||
githubLink: "Kho mã nguồn GitHub",
|
||||
docsLink: "Tài liệu",
|
||||
apiRefLink: "Tham chiếu API (Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1830,6 +1835,8 @@ export const vi: TranslationKeys = {
|
||||
pipelineName: "Tên Pipeline",
|
||||
pipelineDescription: "Mô tả (tùy chọn)",
|
||||
noStepsPrompt: "Thêm các bước để xây dựng tự động hóa",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "Bước",
|
||||
},
|
||||
nav: {
|
||||
@@ -1847,6 +1854,25 @@ export const vi: TranslationKeys = {
|
||||
uploadTab: "Tải lên",
|
||||
fileDetailsAriaLabel: "Chi tiết tệp",
|
||||
fileDetailsHeading: "Chi tiết tệp",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "Loại tệp này không được công cụ này hỗ trợ",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const zhCN: TranslationKeys = {
|
||||
unexpectedError: "发生了意外错误。",
|
||||
retry: "重试",
|
||||
privacyPolicy: "隐私政策",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "基础工具",
|
||||
@@ -1619,6 +1622,8 @@ export const zhCN: TranslationKeys = {
|
||||
githubLink: "GitHub 仓库",
|
||||
docsLink: "文档",
|
||||
apiRefLink: "API 参考(Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1758,6 +1763,8 @@ export const zhCN: TranslationKeys = {
|
||||
pipelineName: "Pipeline 名称",
|
||||
pipelineDescription: "描述(可选)",
|
||||
noStepsPrompt: "添加步骤来构建自动化流程",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "步骤",
|
||||
},
|
||||
nav: {
|
||||
@@ -1775,6 +1782,25 @@ export const zhCN: TranslationKeys = {
|
||||
uploadTab: "上传",
|
||||
fileDetailsAriaLabel: "文件详情",
|
||||
fileDetailsHeading: "文件详情",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "此工具不支持该文件类型",
|
||||
|
||||
@@ -36,6 +36,9 @@ export const zhTW: TranslationKeys = {
|
||||
unexpectedError: "發生了非預期的錯誤。",
|
||||
retry: "重試",
|
||||
privacyPolicy: "隱私權政策",
|
||||
pageNotFound: "Page not found",
|
||||
pageNotFoundDescription: "The page you are looking for does not exist or has been moved.",
|
||||
noToolsFound: "No tools found",
|
||||
},
|
||||
categories: {
|
||||
essentials: "基本工具",
|
||||
@@ -1617,6 +1620,8 @@ export const zhTW: TranslationKeys = {
|
||||
githubLink: "GitHub儲存庫",
|
||||
docsLink: "說明文件",
|
||||
apiRefLink: "API參考(Swagger)",
|
||||
licenseLabel: "License:",
|
||||
licenseDescription: "Dual-licensed under AGPLv3 and a commercial license.",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
@@ -1756,6 +1761,8 @@ export const zhTW: TranslationKeys = {
|
||||
pipelineName: "Pipeline名稱",
|
||||
pipelineDescription: "描述(選填)",
|
||||
noStepsPrompt: "加入步驟來建構自動化",
|
||||
noStepsHeading: "No steps yet",
|
||||
searchToolsPlaceholder: "Search tools...",
|
||||
step: "步驟",
|
||||
},
|
||||
nav: {
|
||||
@@ -1773,6 +1780,25 @@ export const zhTW: TranslationKeys = {
|
||||
uploadTab: "上傳",
|
||||
fileDetailsAriaLabel: "檔案詳情",
|
||||
fileDetailsHeading: "檔案詳情",
|
||||
myFiles: "My Files",
|
||||
searchPlaceholder: "Search files...",
|
||||
selectedCount: "{count} selected",
|
||||
fileCount: "{count} files",
|
||||
fileCountSingular: "{count} file",
|
||||
noFilesFound: "No files found",
|
||||
selectFilePrompt: "Select a file to view details",
|
||||
openFile: "Open File",
|
||||
openInPipeline: "Open in Pipeline",
|
||||
name: "Name",
|
||||
format: "Format",
|
||||
size: "Size",
|
||||
dimensions: "Dimensions",
|
||||
version: "Version",
|
||||
toolsUsed: "Tools Used",
|
||||
none: "None",
|
||||
delete: "Delete",
|
||||
pipeline: "Pipeline",
|
||||
download: "Download",
|
||||
},
|
||||
dropzone: {
|
||||
unsupportedFileType: "此工具不支援該檔案類型",
|
||||
|
||||
Reference in New Issue
Block a user