Files
SnapOtter/packages/shared/src/i18n/en.ts
T

3125 lines
103 KiB
TypeScript

export const en = {
common: {
upload: "Upload from computer",
process: "Process",
download: "Download",
cancel: "Cancel",
save: "Save",
delete: "Delete",
settings: "Settings",
search: "Search tools...",
dropFiles: "Drop files here or click the upload button",
loading: "Loading...",
error: "An error occurred",
confirm: "Confirm",
close: "Close",
back: "Back",
next: "Next",
clear: "Clear",
copy: "Copy",
copied: "Copied!",
noResults: "No results found",
showLess: "Show less",
showMore: "Show {count} more",
experimental: "Experimental",
enabled: "Enabled",
disabled: "Disabled",
rename: "Rename",
edit: "Edit",
actions: "Actions",
create: "Create",
retry: "Retry",
or: "or",
goHome: "Go Home",
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.",
},
categories: {
essentials: "Essentials",
optimization: "Optimization",
adjustments: "Adjustments",
watermark: "Watermark & Overlay",
utilities: "Utilities",
layout: "Layout & Composition",
format: "Format & Conversion",
video: "Video",
audio: "Audio",
documents: "PDF & Documents",
data: "Data Files",
ai: "AI Tools",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Resize",
description: "Resize by pixels, percentage, or social media presets",
},
crop: { name: "Crop", description: "Freeform crop, aspect ratio presets, shape crop" },
rotate: { name: "Rotate & Flip", description: "Rotate, flip, and straighten images" },
convert: { name: "Convert", description: "Convert between image formats" },
compress: { name: "Compress", description: "Reduce file size by quality or target size" },
"optimize-for-web": {
name: "Optimize for Web",
description:
"Optimize images for web with format conversion, quality control, and live preview",
},
"strip-metadata": {
name: "Remove Metadata",
description: "Remove EXIF, GPS, and camera info",
},
"edit-metadata": {
name: "Edit Metadata",
description: "Edit EXIF, IPTC, XMP, GPS, keywords, and dates",
},
"bulk-rename": { name: "Bulk Rename", description: "Rename multiple files with patterns" },
"image-to-pdf": {
name: "Image to PDF",
description: "Combine images into a PDF document",
},
"pdf-to-image": { name: "PDF to Image", description: "Convert PDF pages to images" },
favicon: {
name: "Favicon Generator",
description: "Generate all favicon and app icon sizes",
},
"adjust-colors": {
name: "Adjust Colors",
description:
"Brightness, contrast, exposure, saturation, temperature, sharpness, and effects",
},
sharpening: {
name: "Sharpening",
description: "Adaptive, unsharp mask, and high-pass sharpening with presets",
},
"replace-color": {
name: "Replace & Invert Color",
description: "Replace specific colors or invert",
},
"color-blindness": {
name: "Color Blindness Simulation",
description: "Simulate how images appear with different types of color vision deficiency",
},
"remove-background": {
name: "Remove Background",
description: "AI-powered background removal",
},
upscale: { name: "Image Upscaling", description: "AI super-resolution enhancement" },
"erase-object": { name: "Object Eraser", description: "Remove unwanted objects with AI" },
ocr: {
name: "OCR / Text Extraction",
description: "Extract text from images with AI-powered accuracy",
},
"blur-faces": {
name: "Face / PII Blur",
description: "Auto-detect and blur faces and sensitive info",
},
"enhance-faces": {
name: "Face Enhancement",
description: "Restore and enhance faces with AI",
},
"smart-crop": {
name: "Smart Crop",
description: "Smart subject, face, or trim-based cropping",
},
"image-enhancement": {
name: "Image Enhancement",
description:
"One-click auto-improve with smart exposure, contrast, color, and sharpness correction",
},
"noise-removal": {
name: "Noise Removal",
description: "AI-powered noise and grain removal",
},
"red-eye-removal": {
name: "Red Eye Removal",
description: "AI-powered red eye detection and correction for flash photos",
},
"restore-photo": {
name: "Photo Restoration",
description: "Fix scratches, tears, and damage on old photos with AI",
},
"content-aware-resize": {
name: "Content-Aware Resize",
description: "Intelligently resize images while preserving important content",
},
"ai-canvas-expand": {
name: "AI Canvas Expand",
description: "Expand canvas with AI-powered fill",
},
colorize: {
name: "AI Colorization",
description: "Convert black & white photos to full color using AI deep learning models",
},
"passport-photo": {
name: "Passport Photo",
description:
"Create government-compliant passport, visa, and ID photos with auto face detection",
},
"transparency-fixer": {
name: "PNG Transparency Fixer",
description: "Fix fake transparent PNGs in one click",
},
"watermark-text": { name: "Text Watermark", description: "Add text watermark overlay" },
"watermark-image": { name: "Image Watermark", description: "Overlay a logo as watermark" },
"text-overlay": { name: "Text Overlay", description: "Add styled text to images" },
compose: { name: "Image Composition", description: "Layer images with position and opacity" },
"meme-generator": {
name: "Meme Generator",
description:
"Create memes with popular templates or your own images. Classic Impact-style text with customizable fonts, colors, and positioning.",
},
info: { name: "Image Info", description: "View all metadata and image properties" },
compare: { name: "Image Compare", description: "Side-by-side comparison of two images" },
"find-duplicates": {
name: "Find Duplicates",
description: "Detect duplicate and near-duplicate images",
},
"color-palette": {
name: "Color Palette",
description: "Extract dominant colors from image",
},
"qr-generate": {
name: "QR Code Generator",
description: "Generate styled QR codes with custom colors, patterns, and logos",
},
"html-to-image": {
name: "HTML to Image",
description: "Capture webpages as high-quality images",
},
"barcode-read": {
name: "Barcode Reader",
description: "Scan images for QR codes, barcodes, and 2D codes",
},
collage: {
name: "Collage / Grid",
description: "Combine images into beautiful grid collages with 25+ templates",
},
stitch: {
name: "Stitch / Combine",
description: "Join images side by side, stacked, or in a grid",
},
split: {
name: "Image Splitting",
description: "Split images into grid tiles or by pixel size with live preview",
},
border: {
name: "Border & Frame",
description: "Add borders, padding, rounded corners, and shadows with one-click presets",
},
beautify: {
name: "Beautify Screenshot",
description:
"Add gradient backgrounds, device frames, shadows, and social media sizing to screenshots",
},
"svg-to-raster": {
name: "SVG to Raster",
description:
"Convert SVG to PNG, JPEG, WebP, AVIF, TIFF, GIF, or HEIF at custom scale and DPI",
},
vectorize: {
name: "Image to SVG",
description: "Convert images to scalable vector graphics",
},
"gif-tools": {
name: "GIF Tools",
description:
"Resize, optimize, change speed, reverse, extract frames, and rotate animated GIFs",
},
"image-to-base64": {
name: "Image to Base64",
description: "Convert images to base64 strings for embedding in HTML, CSS, and more",
},
"convert-video": {
name: "Convert Video",
description: "Convert videos between MP4, MOV, and WebM",
},
"compress-video": {
name: "Compress Video",
description: "Shrink video file size with quality control",
},
"trim-video": {
name: "Trim Video",
description: "Cut a clip out of a video",
},
"mute-video": {
name: "Mute Video",
description: "Remove the audio track from a video",
},
"video-to-gif": {
name: "Video to GIF",
description: "Turn a video clip into an animated GIF",
},
"resize-video": {
name: "Resize Video",
description: "Scale a video to a new resolution or preset size",
},
"crop-video": {
name: "Crop Video",
description: "Crop a region out of a video",
},
"rotate-video": {
name: "Rotate Video",
description: "Rotate or flip a video",
},
"change-fps": {
name: "Change FPS",
description: "Change the frame rate of a video",
},
"video-color": {
name: "Video Color",
description: "Adjust brightness, contrast, saturation, and gamma",
},
"video-speed": {
name: "Video Speed",
description: "Speed up or slow down a video",
},
"reverse-video": {
name: "Reverse Video",
description: "Play a video clip backwards",
},
"video-loudnorm": {
name: "Normalize Audio",
description: "Normalize video audio volume to broadcast standard",
},
"aspect-pad": {
name: "Aspect Pad",
description: "Add solid-color bars to fit a target aspect ratio",
},
"blur-pad": {
name: "Blur Pad",
description: "Fill bars with a blurred copy of the video",
},
"watermark-video": {
name: "Watermark Video",
description: "Burn a text watermark onto video frames",
},
"stabilize-video": {
name: "Stabilize Video",
description: "Reduce camera shake with two-pass stabilization",
},
"gif-to-video": {
name: "GIF to Video",
description: "Convert an animated GIF into an MP4 or WebM video",
},
"video-to-webp": {
name: "Video to WebP",
description: "Convert a video clip into an animated WebP image",
},
"video-to-frames": {
name: "Video to Frames",
description: "Extract frames from a video as a ZIP of images",
},
"merge-videos": {
name: "Merge Videos",
description: "Join multiple video clips into one file",
},
"replace-audio": {
name: "Replace Audio",
description: "Swap the audio track of a video with another file",
},
"burn-subtitles": {
name: "Burn Subtitles",
description: "Permanently render subtitles onto video frames",
},
"embed-subtitles": {
name: "Embed Subtitles",
description: "Mux a subtitle track into the video container",
},
"extract-subtitles": {
name: "Extract Subtitles",
description: "Pull the subtitle track out of a video as an SRT file",
},
"images-to-video": {
name: "Images to Video",
description: "Turn a set of images into a slideshow video",
},
"video-metadata": {
name: "Clean Video Metadata",
description: "Strip metadata from a video and report what was found",
},
"convert-audio": {
name: "Convert Audio",
description: "Convert audio between MP3, WAV, OGG, and more",
},
"trim-audio": {
name: "Trim Audio",
description: "Cut a section out of an audio file",
},
"extract-audio": {
name: "Extract Audio",
description: "Pull the audio track out of a video",
},
"volume-adjust": {
name: "Volume Adjust",
description: "Increase or decrease audio volume by a fixed gain",
},
"normalize-audio": {
name: "Normalize Audio",
description: "Even out loudness to broadcast standard levels",
},
"fade-audio": {
name: "Fade Audio",
description: "Add fade-in and fade-out effects to audio",
},
"reverse-audio": {
name: "Reverse Audio",
description: "Play audio backwards",
},
"audio-speed": {
name: "Audio Speed",
description: "Speed up or slow down audio playback",
},
"pitch-shift": {
name: "Pitch Shift",
description: "Raise or lower pitch by semitones without changing speed",
},
"audio-channels": {
name: "Audio Channels",
description: "Convert between mono, stereo, or swap left and right channels",
},
"silence-removal": {
name: "Silence Removal",
description: "Strip silent sections from audio",
},
"noise-reduction": {
name: "Noise Reduction",
description: "Reduce background noise with FFT-based denoising",
},
"merge-audio": {
name: "Merge Audio",
description: "Combine multiple audio files into one",
},
"split-audio": {
name: "Split Audio",
description: "Split audio by time, equal parts, or silence detection",
},
"ringtone-maker": {
name: "Ringtone Maker",
description: "Create a ringtone clip from any audio file",
},
"waveform-image": {
name: "Waveform Image",
description: "Generate a waveform visualization as a PNG image",
},
"audio-metadata": {
name: "Audio Metadata",
description: "View, edit, or strip audio tags (ID3)",
},
"merge-pdf": {
name: "Merge PDFs",
description: "Combine multiple PDFs into one",
},
"split-pdf": {
name: "Split PDF",
description: "Extract pages or split into parts",
},
"compress-pdf": {
name: "Compress PDF",
description: "Shrink PDF file size",
},
"rotate-pdf": {
name: "Rotate PDF",
description: "Rotate pages in a PDF",
},
"convert-document": {
name: "Convert Document",
description: "Convert between Word, OpenDocument, RTF, and plain text formats",
},
"convert-presentation": {
name: "Convert Presentation",
description: "Convert between PowerPoint and OpenDocument presentation formats",
},
"convert-spreadsheet": {
name: "Convert Spreadsheet",
description:
"Convert between Excel, OpenDocument, and CSV formats. Multi-sheet workbooks export the first sheet to CSV.",
},
"excel-to-pdf": {
name: "Excel to PDF",
description: "Convert spreadsheets to PDF. Wide sheets may paginate across multiple pages.",
},
"word-to-pdf": {
name: "Word to PDF",
description: "Convert Word documents to PDF",
},
"extract-pages": {
name: "Extract Pages",
description: "Pull selected pages into a new PDF",
},
"remove-pages": {
name: "Remove Pages",
description: "Delete specific pages from a PDF",
},
"organize-pdf": {
name: "Organize PDF",
description: "Reorder pages with an explicit page order",
},
"protect-pdf": {
name: "Protect PDF",
description: "Add password protection (AES-256 encryption)",
},
"unlock-pdf": {
name: "Unlock PDF",
description: "Remove password protection from a PDF",
},
"repair-pdf": {
name: "Repair PDF",
description: "Attempt to repair a damaged or corrupted PDF",
},
"linearize-pdf": {
name: "Web-Optimize PDF",
description: "Linearize a PDF for fast web viewing",
},
"grayscale-pdf": {
name: "Grayscale PDF",
description: "Convert all colors to grayscale",
},
"pdfa-convert": {
name: "PDF/A Convert",
description: "Convert to archival PDF/A-2",
},
"crop-pdf": {
name: "Crop PDF",
description: "Crop all pages with a uniform margin",
},
"nup-pdf": {
name: "N-up PDF",
description: "Arrange multiple pages per sheet",
},
"booklet-pdf": {
name: "Booklet PDF",
description: "Arrange pages for folding into a booklet",
},
"watermark-pdf": {
name: "Watermark PDF",
description: "Add a text watermark to every page",
},
"pdf-page-numbers": {
name: "PDF Page Numbers",
description: "Add page numbers to every page",
},
"flatten-pdf": {
name: "Flatten PDF",
description: "Bake forms and annotations into page content",
},
"redact-pdf": {
name: "Redact PDF",
description: "Permanently remove text occurrences (verified true redaction)",
},
"pdf-to-text": {
name: "PDF to Text",
description: "Extract plain text from a PDF",
},
"pdf-to-word": {
name: "PDF to Word",
description: "Best for text-based PDFs; scanned pages need OCR",
},
"pdf-metadata": {
name: "PDF Metadata",
description: "Read and write PDF document metadata",
},
"powerpoint-to-pdf": {
name: "PowerPoint to PDF",
description: "Convert presentations to PDF",
},
"html-to-pdf": {
name: "HTML to PDF",
description: "Convert an HTML file to PDF. Remote resources are disabled for privacy.",
},
"markdown-to-docx": {
name: "Markdown to Word",
description: "Convert a Markdown file to a Word document (DOCX)",
},
"markdown-to-html": {
name: "Markdown to HTML",
description:
"Convert a Markdown file to a standalone HTML page. Remote images in the source are left as-is in the output.",
},
"markdown-to-pdf": {
name: "Markdown to PDF",
description:
"Convert a Markdown file to a styled PDF. Remote resources are disabled for privacy.",
},
"epub-convert": {
name: "Convert EPUB",
description:
"Convert an EPUB to PDF, DOCX, HTML, or Markdown. Remote resources inside the book are not fetched.",
},
"to-epub": {
name: "Convert to EPUB",
description: "Convert Word, Markdown, HTML, or plain text files to EPUB",
},
"csv-excel": {
name: "CSV to Excel",
description: "Convert between CSV and Excel (XLSX), both directions",
},
"csv-json": {
name: "CSV to JSON",
description: "Convert between CSV and JSON, both directions",
},
"json-xml": {
name: "JSON to XML",
description: "Convert between JSON and XML, both directions",
},
"split-csv": {
name: "Split CSV",
description: "Split a CSV into smaller files by row count",
},
"merge-csvs": {
name: "Merge CSVs",
description: "Combine multiple CSV or TSV files with matching columns into one",
},
"yaml-json": {
name: "YAML / JSON",
description: "Convert between YAML and JSON, both directions",
},
"xml-to-csv": {
name: "XML to CSV",
description: "Extract repeating elements from XML into a CSV table",
},
"create-zip": {
name: "Create ZIP",
description: "Bundle multiple files into a single ZIP archive",
},
"extract-zip": {
name: "Extract ZIP",
description:
"Safely extract files from a ZIP archive with bomb protection. Single-file archives return the file directly.",
},
pipeline: { name: "Pipeline Builder", description: "Chain multiple tools into a workflow" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
compressionMode: "Compression Mode",
targetSize: "Target Size",
quality: "Quality",
smallestFile: "Smallest file",
bestQuality: "Best quality",
submit: "Compress",
submitBatch: "Compress ({count} files)",
progressLabel: "Compressing",
original: "Original: {size} KB",
processed: "Processed: {size} KB",
saved: "Saved: {percent}%",
},
resize: {
customSize: "Custom Size",
scale: "Scale",
presets: "Presets",
contentAware: "Content-Aware",
widthPx: "Width (px)",
heightPx: "Height (px)",
fitMode: "Fit Mode",
cropToFit: "Crop to fit",
fitInside: "Fit inside",
stretch: "Stretch",
limitToOriginalSize: "Limit to original size",
limitToOriginalSizeHint:
"If your image is already smaller than the target, keep it as-is instead of scaling it up",
scalePercent: "Scale (%)",
resizeToSquare: "Resize to square",
protectFaces: "Protect faces",
smoothing: "Smoothing",
edgeSensitivity: "Edge sensitivity",
submit: "Resize",
submitBatch: "Resize ({count} files)",
progressLabel: "Resizing",
},
crop: {
aspectRatio: "Aspect Ratio",
custom: "Custom",
positionAndSize: "Position & Size",
ruleOfThirds: "Rule of Thirds",
leftOffsetPx: "Left offset (px)",
topOffsetPx: "Top offset (px)",
submit: "Crop",
submitBatch: "Crop ({count} files)",
progressLabel: "Cropping",
},
rotate: {
rotate: "Rotate",
angle: "Angle",
straighten: "Straighten",
flip: "Flip",
horizontal: "Horizontal",
vertical: "Vertical",
resetAllChanges: "Reset all changes",
submit: "Apply",
submitBatch: "Apply ({count} files)",
progressLabel: "Applying",
},
convert: {
targetFormat: "Target Format",
sourceFormat: "Source Format",
quality: "Quality",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"optimize-for-web": {
outputFormat: "Output Format",
quality: "Quality",
smallestFile: "Smallest file",
bestQuality: "Best quality",
maxDimensions: "Max Dimensions",
maxWidth: "Max Width",
maxHeight: "Max Height",
stripMetadata: "Strip Metadata",
sizeComparison: "Size Comparison",
optimized: "Optimized:",
smaller: "{percent}% smaller",
larger: "{percent}% larger",
submit: "Process & Download",
submitBatch: "Process & Download ({count} files)",
progressLabel: "Optimizing",
},
"strip-metadata": {
currentMetadata: "Current Metadata",
readingMetadata: "Reading metadata...",
noMetadataFound: "No metadata found in this image.",
removeAllMetadata: "Remove All Metadata",
selectSpecific: "Or select specific metadata:",
stripExif: "Strip EXIF (camera info, date, exposure)",
stripGps: "Strip GPS (location data)",
stripIcc: "Strip ICC (color profile)",
stripXmp: "Strip XMP (extensible metadata)",
locationFound: "location found",
locationWarning:
"This image contains your precise location. Consider removing GPS data before sharing.",
metadataSections: "{count} metadata section found",
metadataSectionsPlural: "{count} metadata sections found",
metadataRemoved: "Metadata removed: {size} KB",
submit: "Remove Metadata",
progressLabel: "Removing metadata",
},
"edit-metadata": {
readingMetadata: "Reading metadata...",
couldNotReadMetadata: "Could not read metadata - fields will start empty.",
basicInfo: "Basic Info",
description: "Description",
artist: "Artist",
copyright: "Copyright",
software: "Software",
iptc: "IPTC",
title: "Title",
headline: "Headline",
city: "City",
stateProvince: "State/Province",
country: "Country",
dateAndTime: "Date & Time",
editDates: "Edit Dates",
shiftAllDates: "Shift All Dates",
dateModified: "Date Modified",
dateTaken: "Date Taken",
shiftHint: "Shift all date fields by an offset (useful for timezone corrections)",
direction: "Direction",
forward: "+ Forward",
backward: "- Backward",
hoursMinutes: "Hours:Minutes",
locationGps: "Location (GPS)",
locationDataFound: "Location data found",
noGpsData: "No GPS data. Add coordinates below.",
latitude: "Latitude",
longitude: "Longitude",
altitudeMeters: "Altitude (meters)",
removeAllGpsData: "Remove all GPS data",
keywords: "Keywords",
addKeywordPlaceholder: "Add keyword and press Enter",
addToExisting: "Add to existing",
replaceAll: "Replace all",
allMetadata: "All Metadata",
templates: "Templates",
templateNamePlaceholder: "Template name",
uploadPrompt: "Upload an image to edit its metadata.",
changes: "{count} changes:",
modified: "{count} modified",
removed: "{count} removed",
gpsCleared: "GPS cleared",
gpsAdded: "GPS added",
datesShifted: "dates shifted",
submit: "Apply Metadata",
progressLabel: "Writing metadata",
},
"bulk-rename": {
pattern: "Pattern",
patternHint: "Variables: {{index}}, {{padded}}, {{original}}",
startIndex: "Start Index",
preview: "Preview",
andMore: "... and {count} more",
renaming: "Renaming...",
submit: "Rename {count} Files",
zipDownloaded: "ZIP downloaded successfully",
},
"image-to-pdf": {
imageCount: "{count} image will be converted to {mode}",
imageCountPlural: "{count} images will be converted to {mode}",
singlePdfMode: "a single PDF, one image per page",
separatePdfMode: "separate PDFs, one per image",
combineAllImages: "Combine all images into one PDF",
pageSize: "Page Size",
orientation: "Orientation",
portrait: "Portrait",
landscape: "Landscape",
margin: "Margin",
targetSizeLabel: "Target file size (optional)",
targetSizePlaceholder: "e.g. 2",
targetSizeHint: "Leave empty for maximum quality",
targetSizeMet: "Target met",
targetSizeNotMet: "Could not reach target. File compressed to minimum quality.",
targetSizeTooSmall: "Target must be at least 50KB",
jpegQualityLabel: "JPEG quality used",
noImage: "No image",
submitCollate: "Create PDF ({count} pages)",
submitSeparate: "Create {count} PDFs",
downloadPdf: "Download PDF",
downloadZip: "Download ZIP",
progressLabel: "Creating PDF",
uploadingImages: "Uploading images...",
processingPages: "Processing {count} pages...",
},
"pdf-to-image": {
dropPdf: "Drop a PDF here or click to select",
readingPdf: "Reading PDF...",
pageCount: "{count} page",
pageCountPlural: "{count} pages",
outputFormat: "Output Format",
quality: "Quality",
resolutionDpi: "Resolution (DPI)",
dpiScreen: "Screen",
dpiStandard: "Standard",
dpiPrint: "Print",
dpiHighQuality: "High Quality",
colorMode: "Color Mode",
colorModeColor: "Color",
colorModeGrayscale: "Grayscale",
colorModeBw: "B&W",
pages: "Pages",
allPages: "All pages",
pagesHint: "e.g. 1-3, 5, 8-10 (document has {count} pages)",
converting: "Converting...",
submit: "Convert {count} page",
submitPlural: "Convert {count} pages",
downloadAllZip: "Download All (ZIP)",
},
favicon: {
uploadHint:
"Upload square images (recommended 512x512 or larger) to generate all favicon and app icon sizes.",
multipleHint: "Each of the {count} images gets its own folder in the ZIP.",
generatedSizes: "Generated Sizes (per image)",
plusManifest: "+ manifest.json + HTML snippet",
submit: "Generate Favicons ({count} image)",
submitPlural: "Generate Favicons ({count} images)",
downloadZip: "Download Favicons ZIP",
progressLabel: "Generating Favicons",
},
"adjust-colors": {
light: "Light",
brightness: "Brightness",
contrast: "Contrast",
exposure: "Exposure",
color: "Color",
saturation: "Saturation",
temperature: "Temperature",
temperatureHint: "cool / warm",
tint: "Tint",
tintHint: "green / magenta",
hue: "Hue",
detail: "Detail",
sharpness: "Sharpness",
effects: "Effects",
none: "none",
grayscale: "grayscale",
sepia: "sepia",
invert: "invert",
colorChannels: "Color Channels",
channelModified: "modified",
red: "Red",
green: "Green",
blue: "Blue",
resetAll: "Reset All",
submit: "Apply",
submitBatch: "Apply ({count} files)",
progressLabel: "Adjusting colors",
},
sharpening: {
method: "Method",
adaptive: "Adaptive",
unsharpMask: "Unsharp Mask",
highPass: "High-Pass",
presets: "Presets",
textureAmount: "Texture Amount",
amount: "Amount",
strength: "Strength",
noiseReduction: "Noise Reduction",
off: "off",
lightDenoise: "light",
mediumDenoise: "medium",
strongDenoise: "strong",
advancedControls: "Advanced Controls",
radius: "Radius",
flatProtection: "Flat Protection",
detailThreshold: "Detail Threshold",
haloLimitLight: "Halo Limit (Light)",
haloLimitDark: "Halo Limit (Dark)",
threshold: "Threshold",
kernelSize: "Kernel Size",
submit: "Sharpen",
submitBatch: "Sharpen ({count} files)",
progressLabel: "Sharpening",
},
"replace-color": {
sourceColor: "Source Color (to replace)",
targetColor: "Target Color (replacement)",
makeTransparent: "Make transparent instead",
tolerance: "Tolerance",
exactMatch: "Exact match",
wideRange: "Wide range",
submit: "Replace Color",
submitBatch: "Replace Color ({count} files)",
progressLabel: "Replacing color",
},
"color-blindness": {
simulationType: "Simulation Type",
redGreen: "Red-Green",
blueYellow: "Blue-Yellow",
monochromatic: "Monochromatic",
submit: "Simulate",
submitBatch: "Simulate ({count} files)",
progressLabel: "Simulating color blindness",
},
"remove-background": {
subject: "Subject",
people: "People",
products: "Products",
general: "General",
passportIdPhoto: "Passport / ID photo",
quality: "Quality",
fast: "Fast",
hd: "HD",
max: "Max",
ultra: "Ultra",
background: "Background",
transparent: "Transparent",
bgColor: "Color",
gradient: "Gradient",
image: "Image",
gradientDirection: "Direction",
chooseBackgroundImage: "Choose background image",
effectsSection: "Effects",
effectsActive: "active",
blurBackground: "Blur Background",
intensity: "Intensity",
addShadow: "Add Shadow",
opacity: "Opacity",
outputFormat: "Output Format",
edgeSmoothing: "Edge Smoothing",
edgeSmoothingOff: "Off",
edgeSmoothingLight: "Light",
edgeSmoothingMedium: "Medium",
edgeSmoothingStrong: "Strong",
colorDecontamination: "Color Decontamination",
rendering: "Rendering...",
submit: "Remove Background",
submitBatch: "Remove Background ({count} files)",
progressLabel: "Removing background",
},
upscale: {
scaleFactor: "Scale Factor",
quality: "Quality",
enhanceFaces: "Enhance faces",
noiseReduction: "Noise Reduction",
noiseReductionHint:
"Smooths out grain and noise. Higher values remove more noise but may soften details.",
outputFormat: "Output Format",
submit: "Upscale {scale}x",
submitBatch: "Upscale {scale}x ({count} files)",
progressLabel: "Upscaling image",
progressLabelBatch: "Upscaling {count} images",
},
"erase-object": {
brushSize: "Brush Size",
fine: "Fine",
wide: "Wide",
undo: "Undo",
clear: "Clear",
outputFormat: "Output Format",
quality: "Quality",
paintHint: "Paint over the objects you want to remove. Use Ctrl+Z to undo.",
submit: "Erase Object",
submitBatch: "Erase All ({count})",
progressLabel: "Erasing object",
},
ocr: {
quality: "Quality",
enhanceBeforeScanning: "Enhance before scanning",
enhanceHint:
"Automatically deskews, enhances contrast, removes noise, and upscales the image before scanning for better accuracy.",
language: "Language",
autoDetect: "Auto-detect",
extractedText: "Extracted Text",
noTextDetected: "No text detected in this image",
characters: "{count} characters",
submit: "Extract Text",
submitBatch: "Extract Text ({count} files)",
progressLabel: "Extracting text",
},
"blur-faces": {
blurRadius: "Blur Radius",
blurLight: "Light",
blurHeavy: "Heavy",
detectionSensitivity: "Detection Sensitivity",
moreFaces: "More faces",
fewerFaces: "Fewer faces",
submit: "Blur Faces",
progressLabel: "Blurring faces",
},
"enhance-faces": {
quality: "Quality",
enhancementStrength: "Enhancement Strength",
onlyCenterFace: "Center face only",
detectionSensitivity: "Detection Sensitivity",
submit: "Enhance Faces",
submitBatch: "Enhance Faces ({count} files)",
progressLabel: "Enhancing faces",
},
"smart-crop": {
subjectFocus: "Subject Focus",
faceFocus: "Face Focus",
autoTrim: "Auto Trim",
customSize: "Custom Size",
socialPresets: "Social Presets",
detectionStrategy: "Detection Strategy",
detectionStrategyHint:
"Attention finds the most visually salient region. Entropy finds the area with most detail and information.",
attention: "Attention",
entropy: "Entropy",
padding: "Padding",
paddingHint: "Extra breathing room around the focus area",
outputQuality: "Output Quality",
outputQualityHint: "For JPEG and WebP outputs. PNG is always lossless.",
subjectDescription:
"Detects the most interesting region using saliency analysis and crops to your target size.",
framing: "Framing",
facePadding: "Face Padding",
facePaddingHint: "Extra space around detected faces",
fewerFalsePositives: "Fewer false positives",
faceDescription:
"Uses AI face detection to keep faces properly framed. Falls back to Subject Focus if no faces are detected.",
trimTolerance: "Tolerance",
trimDescription:
"How different a border pixel can be from the edge color and still be trimmed. Higher = more aggressive.",
padToSquare: "Pad to square",
targetSizePx: "Target size (px)",
padColor: "Pad color",
trimHint:
'Removes uniform-color borders around your subject. Enable "Pad to square" for e-commerce ready images.',
submitSubject: "Smart Crop",
submitFace: "Face Crop",
submitTrim: "Trim Borders",
},
imageEnhancement: {
enhancementMode: "Enhancement Mode",
auto: "Auto",
portrait: "Portrait",
landscape: "Landscape",
lowLight: "Low Light",
food: "Food",
document: "Document",
intensity: "Intensity",
deepEnhance: "Deep Enhance (AI)",
deepEnhanceDescription: "Removes noise and artifacts using AI",
deepEnhanceRequires: "Requires Upscale & Enhance bundle",
analyzingImage: "Analyzing image...",
detectedIssues: "Detected Issues",
imageLooksGood: "Image looks good. Fine-tune with the intensity slider.",
issueUnderexposed: "Low Exposure",
issueOverexposed: "Overexposed",
issueLowContrast: "Flat Contrast",
issueColorCast: "Color Cast",
issueDesaturated: "Desaturated",
issueSoftFocus: "Soft Focus",
issueNoisy: "Noisy",
submit: "Enhance",
submitDeep: "Deep Enhance",
submitBatch: "Enhance ({count} files)",
submitDeepBatch: "Deep Enhance ({count} files)",
progressLabel: "Enhancing image",
progressLabelBatch: "Enhancing {count} images",
},
"noise-removal": {
denoisingTier: "Denoising Tier",
quick: "Quick",
balanced: "Balanced",
quality: "Quality",
maximum: "Maximum",
quickDesc: "Fast, lightweight",
balancedDesc: "Good quality, moderate speed",
qualityDesc: "AI-powered, slow",
maximumDesc: "Best AI model, slowest",
strength: "Strength",
subtle: "Subtle",
aggressive: "Aggressive",
detailPreservation: "Detail Preservation",
smooth: "Smooth",
sharp: "Sharp",
colorNoise: "Color Noise",
heavy: "Heavy",
outputFormat: "Output Format",
gifAiWarning:
"AI denoising on GIF files processes only the first frame. For animated GIFs, use the Quick or Balanced tier.",
submit: "Remove Noise",
submitBatch: "Remove Noise ({count} files)",
progressLabel: "Removing noise",
progressLabelBatch: "Removing noise from {count} images",
},
"red-eye-removal": {
sensitivity: "Sensitivity",
strict: "Strict",
aggressive: "Aggressive",
correctionStrength: "Correction Strength",
subtle: "Subtle",
dark: "Dark",
outputFormat: "Output Format",
quality: "Quality",
submit: "Fix Red Eye",
submitBatch: "Fix Red Eye ({count} files)",
progressLabel: "Fixing red eye",
progressLabelBatch: "Fixing red eye in {count} images",
},
"restore-photo": {
scratchRemoval: "Scratch Removal",
scratchRemovalDesc: "Detect and repair scratches, tears, spots",
faceEnhancement: "Face Enhancement",
faceEnhancementDesc: "Restore degraded faces with CodeFormer AI",
faceFidelity: "Face Fidelity",
enhanced: "Enhanced",
faithful: "Faithful",
noiseReduction: "Noise Reduction",
noiseReductionDesc: "Remove grain and noise from old photos",
denoiseStrength: "Denoise Strength",
autoColorize: "Auto-Colorize",
autoColorizeDesc: "Add color to B&W photos using DDColor AI",
colorizeStrength: "Colorize Strength",
vivid: "Vivid",
submit: "Restore Photo",
submitBatch: "Restore Photos ({count})",
progressLabel: "Restoring photo",
progressLabelBatch: "Restoring {count} photos",
},
"content-aware-resize": {
widthPx: "Width (px)",
heightPx: "Height (px)",
resizeToSquare: "Resize to square",
protectFaces: "Protect faces",
protectFacesHint: "Detect and protect face regions from seam removal using face detection",
smoothing: "Smoothing",
edgeSensitivity: "Edge sensitivity",
submit: "Resize",
submitBatch: "Resize ({count} files)",
progressLabel: "Content-aware resizing",
},
"ai-canvas-expand": {
quality: "Quality",
fast: "Fast",
balanced: "Balanced",
highQuality: "High Quality",
fastDesc: "Quick preview, fewer AI passes",
balancedDesc: "Good quality, moderate speed",
highQualityDesc: "Best results, slower",
extendToAspectRatio: "Extend to aspect ratio",
extendByPixels: "Extend by (pixels)",
top: "Top",
right: "Right",
bottom: "Bottom",
left: "Left",
newSize: "New size: {width} x {height}",
submit: "Extend Canvas",
submitBatch: "Extend ({count} files)",
progressLabel: "Extending canvas",
},
colorize: {
aiModel: "AI Model",
fast: "Fast",
fastDesc: "Quick results",
balanced: "Balanced",
balancedDesc: "Best available",
best: "Best",
bestDesc: "Highest quality",
colorIntensity: "Color Intensity",
grayscaleLabel: "Grayscale",
subtleLabel: "Subtle",
naturalLabel: "Natural",
vividLabel: "Vivid",
intensityHint: "Lower values produce more muted, vintage-style colors.",
strength: "Colorize Strength",
submit: "Colorize",
submitBatch: "Colorize ({count} files)",
progressLabel: "Colorizing",
progressLabelBatch: "Colorizing {count} images",
},
"passport-photo": {
country: "Country",
searchCountries: "Search countries...",
noCountriesFound: "No countries found",
customDimensions: "Custom Dimensions",
documentType: "Document Type",
dimensionsMm: "Dimensions (mm)",
dpi: "DPI",
pixelsPerInch: "pixels per inch",
backgroundColor: "Background Color",
maxFileSize: "Max File Size",
noLimit: "No limit",
customKb: "Custom KB...",
uploadPortrait: "Upload a portrait photo",
uploadHint: "Drop or upload an image in the left panel to preview your passport photo",
analyzingPhoto: "Analyzing photo",
detectingLandmarks: "Detecting face landmarks and removing background...",
generatePassportPhoto: "Generate Passport Photo",
generating: "Generating...",
downloadPhoto: "Download Photo",
faceCentered: "Face centered",
headLevel: "Head level",
lookingStraight: "Looking straight",
faceSize: "Face size",
whatYouSee: "What you see is what you download",
dragToAdjust: "Drag to adjust",
scrollToZoom: "Scroll to zoom",
photoGenerated: "Photo generated. Download from the left panel.",
},
"transparency-fixer": {
description: "Upload a PNG with a fake transparent background and we'll fix it in one click.",
removeWatermark: "Remove Watermark",
removeWatermarkHelp: "Detect and remove semi-transparent watermarks",
requiresEraser: "Requires Object Eraser bundle",
advanced: "Advanced",
defringe: "Defringe",
outputFormat: "Output Format",
submit: "Fix Transparency",
submitBatch: "Fix Transparency ({count} files)",
progressLabel: "Fixing transparency",
},
"watermark-text": {
watermarkText: "Watermark Text",
fontSize: "Font Size",
color: "Color",
opacity: "Opacity",
position: "Position",
rotation: "Rotation",
center: "Center",
topLeft: "Top Left",
topRight: "Top Right",
bottomLeft: "Bottom Left",
bottomRight: "Bottom Right",
tiled: "Tiled",
submit: "Add Watermark",
submitBatch: "Add Watermark ({count} files)",
progressLabel: "Adding watermark",
},
"watermark-image": {
uploadWatermark: "Upload Watermark Image",
position: "Position",
opacity: "Opacity",
scale: "Scale",
submit: "Apply Watermark",
submitBatch: "Apply Watermark ({count} files)",
},
"text-overlay": {
text: "Text",
fontSize: "Font Size",
color: "Color",
position: "Position",
top: "Top",
center: "Center",
bottom: "Bottom",
backgroundBox: "Background Box",
backgroundColor: "Background Color",
shadow: "Shadow",
submit: "Add Text",
submitBatch: "Add Text ({count} files)",
progressLabel: "Adding text overlay",
download: "Download",
defaultText: "Your Text Here",
},
compose: {
uploadOverlay: "Upload Overlay Image",
xPosition: "X Position",
yPosition: "Y Position",
opacity: "Opacity",
blendMode: "Blend Mode",
submit: "Compose",
},
"meme-generator": {
selectTemplate: "Select a template from the gallery or upload your own image to get started.",
chooseLayout: "Choose a text layout for your custom image.",
textContent: "Text Content",
textStyle: "Text Style",
font: "Font",
fontSize: "Font Size",
textColor: "Text Color",
strokeColor: "Stroke Color",
allCaps: "ALL CAPS",
generate: "Generate Meme",
generating: "Generating...",
downloadMeme: "Download Meme",
backToGallery: "Back to Gallery",
},
info: {
loadingInfo: "Loading info...",
readInfo: "Read Info",
reading: "Reading...",
filename: "Filename",
fileSize: "File Size",
dimensions: "Dimensions",
format: "Format",
channels: "Channels",
colorSpace: "Color Space",
density: "Density",
bitDepth: "Bit Depth",
progressive: "Progressive",
pages: "Pages",
hasAlpha: "Alpha",
hasProfile: "Has Profile",
hasExif: "EXIF Data",
hasIcc: "ICC Profile",
hasXmp: "XMP Data",
channelStats: "Channel Stats",
yes: "Yes",
no: "No",
na: "N/A",
failedToRead: "Failed to read info",
},
compare: {
uploadSecondImage: "Upload Second Image",
similarity: "Similarity: {percent}%",
submit: "Compare",
downloadDiff: "Download Diff",
},
"find-duplicates": {
preset: "Preset",
exact: "Exact",
similar: "Similar",
loose: "Loose",
exactDesc: "Pixel-identical copies, same image in different formats.",
similarDesc: "Resized, recompressed, or lightly edited copies.",
looseDesc: "Visually related images, mild crops, different exposures.",
threshold: "Threshold",
submit: "Scan for Duplicates",
scanning: "Scanning...",
},
"color-palette": {
submit: "Extract Palette",
extracting: "Extracting...",
dominantColors: "Dominant Colors",
clickToCopy: "Click to copy",
},
"qr-generate": {
contentType: "Content Type",
url: "URL",
text: "Text",
wifi: "WiFi",
vcard: "vCard",
email: "Email",
phone: "Phone",
sms: "SMS",
styling: "Styling",
dotStyle: "Dot Style",
cornerSquareStyle: "Corner Square Style",
cornerDotStyle: "Corner Dot Style",
foregroundColor: "Foreground Color",
bgColor: "Background Color",
logo: "Logo",
downloadFormat: "Download Format",
submit: "Generate QR Code",
download: "Download QR Code",
},
"html-to-image": {
modeUrl: "URL",
modeHtml: "HTML File",
htmlFile: "HTML File",
url: "URL",
urlPlaceholder: "https://snapotter.com",
format: "Output Format",
quality: "Quality",
devicePreset: "Device",
viewportWidth: "Width",
viewportHeight: "Height",
fullPage: "Full Page",
submit: "Capture",
download: "Download Screenshot",
capturing: "Capturing webpage...",
errorTimeout: "Page took too long to load",
errorBlocked: "This URL cannot be captured",
errorUnavailable: "Screenshot service is not available",
errorFailed: "Failed to capture the page",
placeholder: "Enter a URL and click Capture",
presets: {
desktop: "Desktop",
tablet: "Tablet",
mobile: "Mobile",
custom: "Custom",
},
},
"barcode-read": {
submit: "Scan Barcodes",
submitBatch: "Scan ({count} files)",
scanning: "Scanning...",
noBarcodesFound: "No barcodes found",
barcodesFound: "{count} barcode found",
barcodesFoundPlural: "{count} barcodes found",
},
collage: {
template: "Template",
aspectRatio: "Aspect Ratio",
gap: "Gap",
cornerRadius: "Corner Radius",
backgroundColor: "Background Color",
outputFormat: "Output Format",
quality: "Quality",
submit: "Create Collage",
downloadCollage: "Download Collage",
},
stitch: {
direction: "Direction",
horizontal: "Horizontal",
vertical: "Vertical",
grid: "Grid",
gridColumns: "Grid Columns",
resizeMode: "Resize Mode",
fit: "Fit",
original: "Original",
stretchMode: "Stretch",
cropMode: "Crop",
alignment: "Alignment",
start: "Start",
center: "Center",
end: "End",
gap: "Gap",
border: "Border",
cornerRadius: "Corner Radius",
backgroundColor: "Background Color",
outputFormat: "Output Format",
quality: "Quality",
submit: "Stitch Images",
},
split: {
modeGrid: "Grid",
modeTileSize: "Tile Size",
presets: "Presets",
columns: "Columns",
rows: "Rows",
tileWidth: "Tile Width",
tileHeight: "Tile Height",
outputFormat: "Output Format",
quality: "Quality",
submit: "Split Image",
downloadAll: "Download All (ZIP)",
},
border: {
presets: "Presets",
borderWidth: "Border Width",
borderColor: "Border Color",
padding: "Padding",
paddingColor: "Padding Color",
cornerRadius: "Corner Radius",
shadow: "Shadow",
shadowBlur: "Shadow Blur",
shadowOffsetX: "Shadow Offset X",
shadowOffsetY: "Shadow Offset Y",
shadowColor: "Shadow Color",
shadowOpacity: "Shadow Opacity",
submit: "Add Border",
submitBatch: "Add Border ({count} files)",
progressLabel: "Adding border",
},
beautify: {
preset: "Preset",
backgroundType: "Background Type",
solidColor: "Solid Color",
linearGradient: "Linear Gradient",
radialGradient: "Radial Gradient",
customImage: "Custom Image",
gradientAngle: "Gradient Angle",
padding: "Padding",
borderRadius: "Border Radius",
shadowPreset: "Shadow Preset",
deviceFrame: "Device Frame",
submit: "Beautify",
submitBatch: "Beautify ({count} files)",
progressLabel: "Beautifying screenshot",
},
"svg-to-raster": {
outputFormat: "Output Format",
sizing: "Sizing",
scaleMode: "Scale",
customMode: "Custom",
scalePresets: "Scale Presets",
dpiPresets: "DPI Presets",
customWidth: "Width (px)",
customHeight: "Height (px)",
background: "Background",
bgTransparent: "Transparent",
bgColor: "Color",
quality: "Quality",
submit: "Convert SVG",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting SVG",
},
vectorize: {
preset: "Preset",
logo: "Logo",
illustration: "Illustration",
photo: "Photo",
sketch: "Sketch",
customPreset: "Custom",
colorMode: "Color Mode",
bw: "B&W",
colorModeColor: "Color",
threshold: "Threshold",
colorPrecision: "Color Precision",
layerDifference: "Layer Difference",
filterSpeckle: "Filter Speckle",
pathMode: "Path Mode",
cornerThreshold: "Corner Threshold",
invertColors: "Invert colors",
submit: "Vectorize",
submitBatch: "Vectorize ({count} files)",
progressLabel: "Vectorizing",
},
"gif-tools": {
mode: "Mode",
resize: "Resize",
optimize: "Optimize",
speed: "Speed",
reverse: "Reverse",
extract: "Extract",
rotateMode: "Rotate",
pixel: "Pixel",
percentage: "Percentage",
colors: "Colors",
dither: "Dither",
effort: "Effort",
speedFactor: "Speed Factor",
loopControl: "Loop Control",
infinite: "Infinite",
once: "Once",
customLoop: "Custom",
loopCount: "Loop Count",
extractSingle: "Single",
extractRange: "Range",
extractAll: "All",
frameNumber: "Frame Number",
frameStart: "Start Frame",
frameEnd: "End Frame",
extractFormat: "Format",
submit: "Process GIF",
submitBatch: "Process ({count} files)",
progressLabel: "Processing GIF",
},
"image-to-base64": {
outputFormat: "Output Format",
keepOriginal: "Keep Original",
quality: "Quality",
maxWidth: "Max Width",
maxHeight: "Max Height",
submit: "Convert to Base64",
submitBatch: "Convert ({count} files)",
copyBase64: "Copy Base64",
copyDataUri: "Copy Data URI",
copyImgTag: "Copy <img> Tag",
copyCssUrl: "Copy CSS url()",
},
"enhance-faces-standalone": {
model: "Model",
fast: "Fast",
balanced: "Balanced",
best: "Best",
},
"convert-video": {
format: "Output format",
quality: "Quality",
high: "High",
balanced: "Balanced",
small: "Smallest",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"compress-video": {
quality: "Compression",
light: "Light",
balanced: "Balanced",
strong: "Strong",
resolution: "Resolution",
original: "Original",
submit: "Compress",
submitBatch: "Compress ({count} files)",
progressLabel: "Compressing",
},
"trim-video": {
start: "Start (seconds)",
end: "End (seconds)",
precise: "Frame-accurate (re-encodes)",
submit: "Trim",
submitBatch: "Trim ({count} files)",
progressLabel: "Trimming",
},
"mute-video": {
submit: "Remove audio",
submitBatch: "Remove audio ({count} files)",
progressLabel: "Muting",
},
"video-to-gif": {
fps: "Frames per second",
width: "Width (px)",
start: "Start (seconds)",
duration: "Duration (seconds)",
submit: "Create GIF",
submitBatch: "Create GIFs ({count} files)",
progressLabel: "Creating GIF",
},
"resize-video": {
preset: "Preset",
width: "Width (px)",
height: "Height (px)",
hint: "Leave one dimension empty to keep aspect ratio",
submit: "Resize",
submitBatch: "Resize ({count} files)",
progressLabel: "Resizing",
},
"crop-video": {
width: "Width (px)",
height: "Height (px)",
x: "X offset",
y: "Y offset",
submit: "Crop",
submitBatch: "Crop ({count} files)",
progressLabel: "Cropping",
},
"rotate-video": {
transform: "Transform",
cw90: "Rotate 90 clockwise",
ccw90: "Rotate 90 counter-clockwise",
rotate180: "Rotate 180",
hflip: "Flip horizontal",
vflip: "Flip vertical",
submit: "Rotate",
submitBatch: "Rotate ({count} files)",
progressLabel: "Rotating",
},
"change-fps": {
fps: "Frames per second",
submit: "Change FPS",
submitBatch: "Change FPS ({count} files)",
progressLabel: "Changing FPS",
},
"video-color": {
brightness: "Brightness",
contrast: "Contrast",
saturation: "Saturation",
gamma: "Gamma",
submit: "Apply",
submitBatch: "Apply ({count} files)",
progressLabel: "Adjusting color",
},
"video-speed": {
factor: "Speed factor",
keepPitch: "Keep original pitch",
submit: "Change speed",
submitBatch: "Change speed ({count} files)",
progressLabel: "Changing speed",
},
"reverse-video": {
hint: "Limited to clips up to 5 minutes",
submit: "Reverse",
submitBatch: "Reverse ({count} files)",
progressLabel: "Reversing",
},
"video-loudnorm": {
hint: "Normalizes audio to EBU R128 broadcast standard",
submit: "Normalize",
submitBatch: "Normalize ({count} files)",
progressLabel: "Normalizing",
},
"aspect-pad": {
target: "Target ratio",
color: "Background color",
colorHint: "Hex color, e.g. #000000",
submit: "Pad",
submitBatch: "Pad ({count} files)",
progressLabel: "Padding",
},
"blur-pad": {
target: "Target ratio",
blur: "Blur strength",
submit: "Pad",
submitBatch: "Pad ({count} files)",
progressLabel: "Padding",
},
"watermark-video": {
text: "Watermark text",
position: "Position",
fontSize: "Font size",
opacity: "Opacity",
color: "Color",
colorHint: "Hex color, e.g. #ffffff",
submit: "Watermark",
submitBatch: "Watermark ({count} files)",
progressLabel: "Watermarking",
},
"stabilize-video": {
smoothing: "Smoothing",
hint: "Runs two passes and takes longer than most tools",
submit: "Stabilize",
submitBatch: "Stabilize ({count} files)",
progressLabel: "Stabilizing",
},
"gif-to-video": {
format: "Output format",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"video-to-webp": {
fps: "Frames per second",
width: "Width (px)",
quality: "Quality",
loop: "Loop animation",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"video-to-frames": {
mode: "Extraction mode",
modeAll: "All frames",
modeNth: "Every Nth frame",
modeTimestamps: "Specific timestamps",
n: "Take every Nth frame",
timestamps: "Timestamps (seconds)",
timestampsHint: "Comma-separated, e.g. 0.5, 2, 4.5",
format: "Image format",
submit: "Extract Frames",
submitBatch: "Extract Frames ({count} files)",
progressLabel: "Extracting frames",
},
"merge-videos": {
hint: "Files are joined in upload order",
submit: "Merge",
submitBatch: "Merge ({count} files)",
progressLabel: "Merging",
},
"replace-audio": {
hint: "Upload the video first, then the audio",
submit: "Replace Audio",
submitBatch: "Replace Audio ({count} files)",
progressLabel: "Replacing audio",
},
"burn-subtitles": {
fontSize: "Font size",
hint: "Upload a video and a subtitle file (.srt or .vtt)",
submit: "Burn Subtitles",
submitBatch: "Burn Subtitles ({count} files)",
progressLabel: "Burning subtitles",
},
"embed-subtitles": {
language: "Language code",
languageHint: "Three-letter ISO 639-2 code, e.g. eng, spa, fra",
submit: "Embed Subtitles",
submitBatch: "Embed Subtitles ({count} files)",
progressLabel: "Embedding subtitles",
},
"extract-subtitles": {
submit: "Extract Subtitles",
submitBatch: "Extract Subtitles ({count} files)",
progressLabel: "Extracting subtitles",
},
"images-to-video": {
secondsPerImage: "Seconds per image",
resolution: "Resolution",
fps: "Frames per second",
submit: "Create Video",
submitBatch: "Create Video ({count} files)",
progressLabel: "Creating slideshow",
},
"video-metadata": {
hint: "Metadata report appears in the result",
submit: "Strip Metadata",
submitBatch: "Strip Metadata ({count} files)",
progressLabel: "Stripping metadata",
},
"convert-audio": {
format: "Output format",
bitrate: "Bitrate (kbps)",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"trim-audio": {
start: "Start (seconds)",
end: "End (seconds)",
submit: "Trim",
submitBatch: "Trim ({count} files)",
progressLabel: "Trimming",
},
"extract-audio": {
format: "Output format",
submit: "Extract",
submitBatch: "Extract ({count} files)",
progressLabel: "Extracting",
},
"volume-adjust": {
"gain-db": "Gain (dB)",
submit: "Adjust Volume",
submitBatch: "Adjust Volume ({count} files)",
progressLabel: "Adjusting volume",
},
"normalize-audio": {
hint: "EBU R128 loudness normalization",
submit: "Normalize",
submitBatch: "Normalize ({count} files)",
progressLabel: "Normalizing",
},
"fade-audio": {
"fade-in-s": "Fade in (seconds)",
"fade-out-s": "Fade out (seconds)",
submit: "Apply Fade",
submitBatch: "Apply Fade ({count} files)",
progressLabel: "Applying fade",
},
"reverse-audio": {
submit: "Reverse",
submitBatch: "Reverse ({count} files)",
progressLabel: "Reversing",
},
"audio-speed": {
factor: "Speed factor",
submit: "Change Speed",
submitBatch: "Change Speed ({count} files)",
progressLabel: "Changing speed",
},
"pitch-shift": {
semitones: "Semitones",
hint: "0 semitones is not allowed",
submit: "Shift Pitch",
submitBatch: "Shift Pitch ({count} files)",
progressLabel: "Shifting pitch",
},
"audio-channels": {
mode: "Channel mode",
"stereo-to-mono": "Stereo to mono",
"mono-to-stereo": "Mono to stereo",
swap: "Swap left/right",
submit: "Convert Channels",
submitBatch: "Convert Channels ({count} files)",
progressLabel: "Converting channels",
},
"silence-removal": {
"threshold-db": "Silence threshold (dB)",
"min-silence-s": "Minimum silence duration (seconds)",
submit: "Remove Silence",
submitBatch: "Remove Silence ({count} files)",
progressLabel: "Removing silence",
},
"noise-reduction": {
strength: "Strength",
light: "Light",
medium: "Medium",
strong: "Strong",
submit: "Reduce Noise",
submitBatch: "Reduce Noise ({count} files)",
progressLabel: "Reducing noise",
},
"merge-audio": {
format: "Output format",
mp3: "MP3",
wav: "WAV",
flac: "FLAC",
m4a: "M4A",
"order-hint": "Files will be joined in upload order",
submit: "Merge Audio",
submitBatch: "Merge Audio ({count} files)",
progressLabel: "Merging audio",
},
"split-audio": {
mode: "Split mode",
time: "By time",
parts: "Equal parts",
silence: "By silence",
"segment-s": "Segment length (seconds)",
"num-parts": "Number of parts",
"threshold-db": "Silence threshold (dB)",
"min-silence-s": "Minimum silence duration (seconds)",
submit: "Split Audio",
submitBatch: "Split Audio ({count} files)",
progressLabel: "Splitting audio",
},
"ringtone-maker": {
"start-s": "Start time (seconds)",
"duration-s": "Duration (seconds)",
"max-hint": "Maximum 30 seconds",
submit: "Create Ringtone",
submitBatch: "Create Ringtone ({count} files)",
progressLabel: "Creating ringtone",
},
"waveform-image": {
width: "Width (px)",
height: "Height (px)",
color: "Waveform color",
submit: "Generate Waveform",
submitBatch: "Generate Waveform ({count} files)",
progressLabel: "Generating waveform",
},
"audio-metadata": {
strip: "Strip all metadata",
title: "Title",
artist: "Artist",
album: "Album",
submit: "Apply Metadata",
submitBatch: "Apply Metadata ({count} files)",
progressLabel: "Applying metadata",
},
"merge-pdf": {
addFiles: "Add PDFs to merge",
needTwo: "At least two PDFs are required",
orderHint: "{count} PDFs will merge in this order",
submit: "Merge",
submitBatch: "Merge ({count} files)",
progressLabel: "Merging",
},
"split-pdf": {
mode: "Split mode",
range: "Page range",
rangeHint: "e.g. 1-3, 5, 7-z",
everyN: "Pages per part",
submit: "Split",
submitBatch: "Split ({count} files)",
progressLabel: "Splitting",
},
"compress-pdf": {
preset: "Quality preset",
screen: "Screen (smallest)",
ebook: "Ebook (balanced)",
printer: "Printer (best quality)",
submit: "Compress",
submitBatch: "Compress ({count} files)",
progressLabel: "Compressing",
},
"rotate-pdf": {
angle: "Rotation angle",
range: "Page range",
rangeHint: "e.g. 1-3, 5, 1-z (all pages)",
submit: "Rotate",
submitBatch: "Rotate ({count} files)",
progressLabel: "Rotating",
},
"convert-document": {
format: "Output format",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"convert-presentation": {
format: "Output format",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"convert-spreadsheet": {
format: "Output format",
hint: "Multi-sheet workbooks export the first sheet to CSV.",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"excel-to-pdf": {
submit: "Convert to PDF",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"powerpoint-to-pdf": {
submit: "Convert to PDF",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"word-to-pdf": {
submit: "Convert to PDF",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"extract-pages": {
range: "Page range",
rangeHint: "e.g. 1-3, 5, 7-z",
submit: "Extract",
submitBatch: "Extract ({count} files)",
progressLabel: "Extracting",
},
"remove-pages": {
pages: "Pages to remove",
pagesHint: "e.g. 2, 4-6, z (last page)",
submit: "Remove",
submitBatch: "Remove ({count} files)",
progressLabel: "Removing",
},
"organize-pdf": {
order: "Page order",
orderHint: "e.g. 3,1,2 or 1-z (identity)",
submit: "Reorder",
submitBatch: "Reorder ({count} files)",
progressLabel: "Reordering",
},
"protect-pdf": {
userPassword: "User password",
ownerPassword: "Owner password (optional)",
ownerPasswordHint: "Defaults to user password if empty",
submit: "Protect",
submitBatch: "Protect ({count} files)",
progressLabel: "Encrypting",
},
"unlock-pdf": {
password: "Password",
submit: "Unlock",
submitBatch: "Unlock ({count} files)",
progressLabel: "Decrypting",
},
"repair-pdf": {
submit: "Repair",
submitBatch: "Repair ({count} files)",
progressLabel: "Repairing",
},
"linearize-pdf": {
submit: "Optimize",
submitBatch: "Optimize ({count} files)",
progressLabel: "Linearizing",
},
"grayscale-pdf": {
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"pdfa-convert": {
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"crop-pdf": {
margin: "Margin (points)",
submit: "Crop",
submitBatch: "Crop ({count} files)",
progressLabel: "Cropping",
},
"nup-pdf": {
perSheet: "Pages per sheet",
submit: "Arrange",
submitBatch: "Arrange ({count} files)",
progressLabel: "Arranging",
},
"booklet-pdf": {
perSheet: "Pages per sheet",
submit: "Create Booklet",
submitBatch: "Create Booklet ({count} files)",
progressLabel: "Creating booklet",
},
"watermark-pdf": {
text: "Watermark text",
position: "Position",
fontSize: "Font size",
opacity: "Opacity",
rotation: "Rotation",
submit: "Watermark",
submitBatch: "Watermark ({count} files)",
progressLabel: "Watermarking",
},
"pdf-page-numbers": {
position: "Position",
fontSize: "Font size",
submit: "Add Numbers",
submitBatch: "Add Numbers ({count} files)",
progressLabel: "Numbering",
},
"flatten-pdf": {
submit: "Flatten",
submitBatch: "Flatten ({count} files)",
progressLabel: "Flattening",
},
"redact-pdf": {
terms: "Terms to redact",
termsHint: "One term per line (max 50)",
caseSensitive: "Case sensitive",
submit: "Redact",
submitBatch: "Redact ({count} files)",
progressLabel: "Redacting",
},
"pdf-to-text": {
submit: "Extract Text",
submitBatch: "Extract Text ({count} files)",
progressLabel: "Extracting",
},
"pdf-to-word": {
hint: "Best for text-based PDFs; scanned pages need OCR",
submit: "Convert to Word",
submitBatch: "Convert to Word ({count} files)",
progressLabel: "Converting",
},
"pdf-metadata": {
title: "Title",
author: "Author",
subject: "Subject",
keywords: "Keywords",
submit: "Set Metadata",
submitBatch: "Set Metadata ({count} files)",
progressLabel: "Setting metadata",
},
"html-to-pdf": {
hint: "Remote resources are disabled for privacy.",
submit: "Convert to PDF",
submitBatch: "Convert to PDF ({count} files)",
progressLabel: "Converting",
},
"markdown-to-docx": {
submit: "Convert to DOCX",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"markdown-to-html": {
hint: "Remote images in the source are left as-is in the output.",
submit: "Convert to HTML",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"markdown-to-pdf": {
hint: "Remote resources are disabled for privacy.",
submit: "Convert to PDF",
submitBatch: "Convert to PDF ({count} files)",
progressLabel: "Converting",
},
"epub-convert": {
format: "Output format",
hint: "Remote resources inside the book are not fetched.",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"to-epub": {
submit: "Convert to EPUB",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"csv-excel": {
sheet: "Worksheet number",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"csv-json": {
pretty: "Pretty print",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"json-xml": {
pretty: "Pretty print",
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"split-csv": {
rowsPerFile: "Rows per file",
keepHeader: "Keep header in each file",
submit: "Split",
submitBatch: "Split ({count} files)",
progressLabel: "Splitting",
},
"merge-csvs": {
submit: "Merge",
submitBatch: "Merge ({count} files)",
progressLabel: "Merging",
},
"yaml-json": {
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"xml-to-csv": {
submit: "Convert",
submitBatch: "Convert ({count} files)",
progressLabel: "Converting",
},
"create-zip": {
submit: "Create ZIP",
submitBatch: "Create ZIP ({count} files)",
progressLabel: "Zipping",
},
"extract-zip": {
submit: "Extract",
submitBatch: "Extract ({count} files)",
progressLabel: "Extracting",
},
},
urlImport: {
title: "Import from URLs",
placeholder: "Paste image URLs, one per line...",
importButton: "Import URLs",
addButton: "Add {count} Files",
adding: "Adding...",
retryButton: "Retry",
cancelButton: "Cancel",
readyCount: "{count} ready",
failedStatus: "Failed",
},
comparison: {
original: "Original",
processed: "Processed",
before: "Before",
after: "After",
savings: "Savings",
},
toolPage: {
emptyPrompt: "Drop or upload an image to get started",
filesCount: "Files ({count})",
addMore: "+ Add more",
clearAll: "Clear all",
acceptDescription: "{exts} files only",
notFound: "Tool not found",
configureAndGenerate: "Configure settings and generate.",
processingFailed: "Processing failed for this file",
conversionComplete: "Conversion complete",
cannotPreviewDownload:
"{type} files cannot be previewed in the browser. Use the download button to save your file.",
generatingPreview: "Generating preview...",
cannotPreviewWillProcess:
"{ext} files cannot be previewed in the browser. The tool will still process this file normally.",
previousImage: "Previous image",
nextImage: "Next image",
imageCounter: "{current} / {total}",
settingsLabel: "Settings",
downloadAllZip: "Download All (ZIP)",
hideSettings: "Hide Settings",
imageArea: "Image area",
},
homePage: {
generatingPreview: "Generating preview...",
loadingPreview: "Loading preview...",
changeFile: "Change file",
quickActions: "Quick Actions",
allTools: "All Tools",
},
fullscreenGrid: {
searchPlaceholder: "Search tools...",
hideDetails: "Hide Details",
showDetails: "Show Details",
switchToSidebar: "Switch to sidebar view",
sidebarButton: "Sidebar",
noToolsFound: "No tools found",
tryDifferent: "Try a different search term",
},
editor: {
menu: {
file: {
label: "File",
new: "New",
open: "Open",
save: "Save",
exportAs: "Export As...",
quickExportPng: "Quick Export as PNG",
close: "Close",
},
edit: {
label: "Edit",
undo: "Undo",
redo: "Redo",
cut: "Cut",
copy: "Copy",
copyMerged: "Copy Merged",
paste: "Paste",
pasteInPlace: "Paste in Place",
delete: "Delete",
freeTransform: "Free Transform",
transform: {
label: "Transform",
scale: "Scale",
rotate: "Rotate",
skew: "Skew",
flipHorizontal: "Flip Horizontal",
flipVertical: "Flip Vertical",
},
},
image: {
label: "Image",
imageSize: "Image Size...",
canvasSize: "Canvas Size...",
rotation: {
label: "Image Rotation",
cw90: "90° CW",
ccw90: "90° CCW",
r180: "180°",
flipHorizontal: "Flip Horizontal",
flipVertical: "Flip Vertical",
},
trim: "Trim",
adjustments: {
label: "Adjustments",
brightnessContrast: "Brightness/Contrast",
hueSaturation: "Hue/Saturation",
colorBalance: "Color Balance",
levels: "Levels",
curves: "Curves",
},
},
layer: {
label: "Layer",
newLayer: "New Layer",
duplicateLayer: "Duplicate Layer",
deleteLayer: "Delete Layer",
arrange: {
label: "Arrange",
bringToFront: "Bring to Front",
bringForward: "Bring Forward",
sendBackward: "Send Backward",
sendToBack: "Send to Back",
},
mergeDown: "Merge Down",
flattenImage: "Flatten Image",
},
select: {
label: "Select",
all: "All",
deselect: "Deselect",
inverse: "Inverse",
colorRange: "Color Range...",
},
filter: {
label: "Filter",
blur: {
label: "Blur",
gaussian: "Gaussian Blur",
motion: "Motion Blur",
radial: "Radial Blur",
surface: "Surface Blur",
},
sharpen: {
label: "Sharpen",
sharpen: "Sharpen",
unsharpMask: "Unsharp Mask",
},
noise: {
label: "Noise",
addNoise: "Add Noise",
reduceNoise: "Reduce Noise",
},
pixelate: {
label: "Pixelate",
pixelate: "Pixelate",
mosaic: "Mosaic",
},
stylize: {
label: "Stylize",
emboss: "Emboss",
solarize: "Solarize",
posterize: "Posterize",
},
grayscale: "Grayscale",
sepia: "Sepia",
invert: "Invert",
},
view: {
label: "View",
zoomIn: "Zoom In",
zoomOut: "Zoom Out",
fitOnScreen: "Fit on Screen",
actualPixels: "Actual Pixels",
rulers: "Rulers",
grid: "Grid",
guides: "Guides",
snap: "Snap",
panels: "Panels",
},
},
menuBar: {
backTitle: "Back to SnapOtter",
},
welcome: {
ariaLabel: "Image drop zone",
heading: "Image Editor",
dropDescription: "Drop an image here to get started",
openImageButton: "Open Image",
newDocumentButton: "New Document",
pasteHint: "Or paste from clipboard (Ctrl+V)",
},
mobile: {
heading: "Desktop Recommended",
description:
"The image editor works best on desktop screens. Please switch to a device with a larger display for the full editing experience.",
},
errors: {
serverDecodeFailed: "Server decode failed",
},
shapes: {
shape: "Shape",
fill: "Fill",
stroke: "Stroke",
strokeWidth: "Width",
cornerRadius: "Radius",
sides: "Sides",
points: "Points",
dashStyle: "Dash",
solid: "Solid",
dashed: "Dashed",
dotted: "Dotted",
none: "None",
opacity: "Opacity",
rectangle: "Rectangle",
ellipse: "Ellipse",
line: "Line",
arrow: "Arrow",
polygon: "Polygon",
star: "Star",
},
},
settings: {
heading: "Settings",
nav: {
general: "General",
systemSettings: "System Settings",
security: "Security",
people: "People",
teams: "Teams",
roles: "Roles",
auditLog: "Audit Log",
usage: "Usage",
apiKeys: "API Keys",
aiFeatures: "AI Features",
tools: "Tools",
productAnalytics: "Product Analytics",
about: "About",
},
general: {
heading: "General",
description: "User preferences and display settings.",
loading: "Loading...",
logOut: "Log out",
defaultToolViewLabel: "Default Tool View",
defaultToolViewDescription: "How tools are displayed on the home page",
sidebarOption: "Sidebar",
fullscreenGridOption: "Fullscreen Grid",
appVersionLabel: "App Version",
appVersionDescription: "Current version of SnapOtter",
saveButton: "Save Settings",
saveSuccess: "Settings saved.",
saveFailed: "Failed to save settings.",
},
system: {
heading: "System Settings",
description: "Server-side configuration and limits.",
fileUploadLimitLabel: "File Upload Limit (MB)",
fileUploadLimitDescription: "Maximum file size per upload",
defaultThemeLabel: "Default Theme",
defaultThemeDescription: "Theme applied for new sessions",
lightOption: "Light",
darkOption: "Dark",
systemOption: "System",
languageLabel: "Language",
languageDescription: "Language for the interface",
loginAttemptLimitLabel: "Login Attempt Limit",
loginAttemptLimitDescription: "Max failed login attempts per minute before lockout",
fileManagementHeading: "File Management",
maxFileAgeLabel: "Max File Age (hours)",
maxFileAgeDescription: "How long processed files are kept before automatic cleanup",
startupCleanupLabel: "Startup Cleanup",
startupCleanupDescription: "Clean up old temporary files when the server starts",
saveButton: "Save Settings",
saveSuccess: "Settings saved.",
saveFailed: "Failed to save settings.",
limitsAndResources: "Limits & Resources",
maxFileSize: "Max File Size",
maxBatchSize: "Max Batch Size",
concurrentJobs: "Concurrent Jobs",
workerThreads: "Worker Threads",
maxPipelineSteps: "Max Pipeline Steps",
processingTimeout: "Processing Timeout",
rateLimitPerMin: "Rate Limit (req/min)",
unlimited: "Unlimited",
auto: "Auto",
envOverride: "Set by environment variable",
maxCanvasPixels: "Max Canvas Pixels",
maxSvgSize: "Max SVG Size",
maxSplitGrid: "Max Split Grid",
maxPdfPages: "Max PDF Pages",
sessionDuration: "Session Duration",
supportBundleButton: "Download Support Bundle",
supportBundleDescription:
"Download a diagnostic zip with redacted config, logs, and job data for troubleshooting.",
supportBundleFailed: "Failed to download support bundle.",
},
security: {
heading: "Security",
description: "Password and authentication settings.",
changePasswordHeading: "Change Password",
currentPasswordPlaceholder: "Current Password",
newPasswordPlaceholder: "New Password",
confirmPasswordPlaceholder: "Confirm New Password",
passwordsMismatch: "Passwords do not match",
passwordTooShort:
"Password must be at least 8 characters with uppercase, lowercase, and a number",
changeSuccess: "Password changed successfully",
changeFailed: "Failed to change password",
currentPasswordIncorrect: "Current password is incorrect",
changePasswordButton: "Change Password",
loginAttemptLimitNote: "Login attempt limits can be configured in System Settings.",
},
people: {
heading: "People",
description: "Manage workspace members and their permissions",
userCount: "{count} user",
userCountPlural: "{count} users",
searchPlaceholder: "Search members...",
addMembersButton: "Add Members",
newMemberHeading: "New Member",
usernamePlaceholder: "Username",
passwordPlaceholder: "Password",
roleUserOption: "User",
roleEditorOption: "Editor",
roleAdminOption: "Admin",
roleUserDescription: "Basic tool access",
roleEditorDescription: "All files & pipelines",
roleAdminDescription: "Full access",
noDescription: "No description",
defaultTeamOption: "Default",
createButton: "Create",
cancelButton: "Cancel",
createSuccess: "User created successfully",
createFailed: "Failed to create user",
userLimitReached: "User limit reached ({max} max)",
deleteConfirm: 'Delete user "{username}"? This cannot be undone.',
deleteSuccess: 'User "{username}" deleted',
deleteFailed: "Failed to delete user",
editHeading: "Edit {username}",
updateSuccess: "User updated",
updateFailed: "Failed to update user",
cannotRemoveOwnAdmin: "Cannot remove your own admin role",
resetPasswordHeading: "Reset password for {username}",
newPasswordLabel: "New password (min 8 chars)",
resetPasswordButton: "Reset Password",
resetPasswordWarning: "This will invalidate all sessions and API keys for this user.",
resetSuccess: "Password reset successfully",
resetFailed: "Failed to reset password",
tableHeaderUser: "User",
tableHeaderRole: "Role",
tableHeaderTeam: "Team",
noSearchResults: "No members match your search.",
noUsersFound: "No users found.",
authBadgeLocalOidc: "Local + OIDC",
authBadgeOidc: "OIDC",
editRoleTeamAction: "Edit Role / Team",
resetPasswordAction: "Reset Password",
deleteUserAction: "Delete User",
saveButton: "Save",
copyPasswordButton: "Copy password",
passwordCopied: "Copied!",
copyPasswordWarning:
"Copy this password now. You won't be able to see it after creating the user.",
},
teams: {
heading: "Teams",
description: "Organize members into teams for better management.",
createButton: "Create New Team",
newTeamHeading: "New Team",
teamNamePlaceholder: "Team name",
createSubmitButton: "Create",
cancelButton: "Cancel",
createSuccess: "Team created successfully",
createFailed: "Failed to create team",
duplicateTeamError: "A team with that name already exists",
renameSuccess: "Team renamed",
renameFailed: "Failed to rename team",
deleteConfirm: 'Delete team "{name}"? Members will be unassigned.',
deleteSuccess: 'Team "{name}" deleted',
deleteFailed: "Failed to delete team",
cannotDeleteDefault: "Cannot delete the default team or a team with members",
tableHeaderTeamName: "Team Name",
tableHeaderMembers: "Members",
emptyState: "No teams found.",
renameSaveButton: "Save",
renameCancelButton: "Cancel",
renameAction: "Rename",
deleteAction: "Delete",
totalMembers: "Total Members",
nameRequired: "Team name is required",
nameTooLong: "Team name must be 50 characters or less",
duplicateName: "A team with this name already exists",
},
roles: {
heading: "Roles",
description: "Manage roles and their permissions. Built-in roles cannot be modified.",
createButton: "Create Custom Role",
newRoleHeading: "New Role",
roleNamePlaceholder: "Role name",
descriptionPlaceholder: "Description (optional)",
permissionsLabel: "Permissions",
createSubmitButton: "Create",
cancelButton: "Cancel",
createSuccess: "Role created successfully",
createFailed: "Failed to create role",
duplicateRoleError: "A role with that name already exists",
editHeading: "Edit Role: {name}",
editSaveButton: "Save",
editCancelButton: "Cancel",
updateSuccess: "Role updated",
updateFailed: "Failed to update role",
deleteConfirm: 'Delete role "{name}"? {count} user(s) will need to be reassigned.',
deleteConfirmSimple: 'Delete role "{name}"?',
deleteSuccess: 'Role "{name}" deleted',
deleteFailed: "Failed to delete role",
emptyState: "No roles found.",
builtInBadge: "Built-in",
userCountBadge: "{count} user(s)",
editRoleTitle: "Edit role",
deleteRoleTitle: "Delete role",
permGroup: {
tools: "Tools",
files: "Files",
apiKeys: "API Keys",
pipelines: "Pipelines",
settings: "Settings",
users: "Users",
teams: "Teams",
system: "System",
},
},
auditLog: {
heading: "Audit Log",
allActionsFilter: "All actions",
emptyState: "No audit log entries.",
tableHeaderTime: "Time",
tableHeaderUser: "User",
tableHeaderAction: "Action",
tableHeaderTarget: "Target",
paginationInfo: "Page {page} of {totalPages} ({total} entries)",
previousButton: "Previous",
nextButton: "Next",
justNow: "just now",
minutesAgo: "{mins}m ago",
hoursAgo: "{hrs}h ago",
daysAgo: "{days}d ago",
},
usage: {
heading: "Usage",
description: "Local usage statistics from jobs and file storage.",
periodLabel: "Period",
days7: "7 days",
days30: "30 days",
days90: "90 days",
jobsPerDayHeading: "Jobs per day",
topToolsHeading: "Top tools",
perUserHeading: "Per-user volume",
durationsHeading: "Duration percentiles",
noData: "No data for this period.",
dayColumn: "Day",
totalColumn: "Total",
completedColumn: "Completed",
failedColumn: "Failed",
toolColumn: "Tool",
runsColumn: "Runs",
userColumn: "User",
bytesInColumn: "Bytes in",
poolColumn: "Pool",
p50Column: "p50",
p95Column: "p95",
storageHeading: "Library storage",
storageFiles: "{count} files",
unknownUser: "(unknown)",
},
apiKeys: {
heading: "API Keys",
description: "Manage API keys for programmatic access to SnapOtter.",
keyNamePlaceholder: "Key name (optional)",
generateButton: "Generate API Key",
removeScopingLabel: "Remove permission scoping",
restrictPermissionsLabel: "Restrict permissions (optional)",
expiresLabel: "Expires:",
clearButton: "Clear",
copyTitle: "Copy",
keyWarning: "Store this key securely. It will not be shown again.",
existingKeysHeading: "Existing Keys",
createdPrefix: "Created {date}",
scopedPrefix: "Scoped:",
expiresPrefix: "Expires {date}",
deleteKeyTitle: "Delete key",
deleteConfirm: "Delete this API key? Any integrations using it will stop working.",
emptyState: "No API keys yet. Generate one to get started.",
},
tools: {
heading: "Tools",
description: "Enable or disable individual tools. Disabled tools are hidden from all users.",
restartBanner: "Restart required for changes to take effect.",
searchPlaceholder: "Search tools...",
noSearchResults: "No tools match your search.",
loadFailedError: "Failed to load tool settings. Saving is disabled to prevent data loss.",
saveButton: "Save Tool Settings",
disabledCount: "{count} tool(s) disabled",
},
experimental: {
label: "Enable Experimental Tools",
description: "Show tools that are still in development. These may be unstable.",
},
aiFeatures: {
title: "AI Features",
description: "Manage AI model bundles for advanced image processing.",
installAll: "Install All",
diskUsage: "Disk usage: {size}",
installed: "Installed",
notInstalled: "Not installed",
queued: "Queued",
install: "Install",
repair: "Repair",
uninstall: "Uninstall",
installing: "Installing...",
importBundle: "Import Bundle",
importDescription: "Upload a .tar.gz bundle archive exported from another installation.",
importButton: "Import from file",
importing: "Importing...",
importSuccess: "Bundle imported successfully.",
importError: "Bundle import failed: {error}",
},
fileManagement: {
title: "File Management",
maxAge: "Max File Age (hours)",
maxAgeDescription: "How long processed files are kept before automatic cleanup",
startupCleanup: "Startup Cleanup",
startupCleanupDescription: "Clean up old temporary files when the server starts",
},
analytics: {
heading: "Product Analytics",
description: "Share anonymous usage data to help improve SnapOtter.",
privacyNote: "Your images never leave your network.",
disabledByAdmin: "Product analytics has been disabled by the server administrator.",
enabledLabel: "Analytics enabled",
disabledLabel: "Analytics disabled",
learnMore: "Learn more",
},
about: {
heading: "About",
appName: "SnapOtter",
appDescription:
"A self-hosted, privacy-first image processing suite with 70+ tools. Resize, compress, convert, watermark, and automate your image workflows without sending data to the cloud.",
versionLabel: "Version:",
linksHeading: "Links",
githubLink: "GitHub Repository",
docsLink: "Documentation",
apiRefLink: "API Reference (Swagger)",
licenseLabel: "License:",
licenseDescription:
"SnapOtter is open-source software licensed under the GNU Affero General Public License v3 (AGPLv3).",
},
},
auth: {
login: "Login",
logout: "Log out",
username: "Username",
password: "Password",
loginButton: "Login",
loggingIn: "Logging in...",
invalidCredentials: "Invalid username or password",
connectionError: "Connection error",
signInWith: "Sign in with {provider}",
signInWithSso: "Sign in with SSO",
or: "or",
methodLocal: "Local",
methodOidc: "OIDC",
methodBoth: "Local + OIDC",
oidcAuthFailed: "Authentication failed. Please try again.",
oidcProviderUnreachable: "Could not reach the identity provider. Please try again later.",
oidcSessionExpired: "Login session expired. Please try again.",
oidcUserNotAuthorized:
"Your account is not authorized to access this application. Contact your administrator.",
oidcUserLimitReached: "User limit reached. Contact your administrator.",
oidcGenericError: "Authentication error. Please try again.",
passwordManagedByProvider: "Password changes are managed by your identity provider.",
enterUsername: "Enter username",
enterPassword: "Enter your password",
heroTitle: "Your images. Stay yours.",
heroSubtitle: "Every image tool you need.",
rotatingPhrases: [
"No signups. No accounts.",
"No uploads to the cloud. Ever.",
"100% local processing.",
"Free. Forever.",
"No limits. No hidden caps.",
"Works fully offline.",
"Unlimited batch processing.",
"70+ tools.",
"16 AI models. Your hardware.",
"Lightning fast. Built on Sharp.",
"Air-gapped ready.",
"One Docker container.",
"Open source. Always.",
"Every pixel stays on your hardware.",
"Your server. Your rules.",
"Deploys in a single docker pull.",
"The self-hosted alternative.",
"Resize, compress, convert. Locally.",
"Free image editor. No watermarks.",
"Bulk image processing. Unlimited.",
"Remove backgrounds offline.",
"Self-hosted Canva alternative.",
"No API keys needed.",
"GDPR compliant by design.",
"Works without internet.",
],
},
changePassword: {
title: "Change your password",
description:
"You need to set a new password before continuing. Your password must be at least 8 characters with uppercase, lowercase, and a number.",
usernameLabel: "Username",
currentPasswordLabel: "Current password",
currentPasswordPlaceholder: "Enter current password",
newPasswordLabel: "New password",
generateButton: "Generate strong password",
newPasswordPlaceholder: "At least 8 characters",
confirmPasswordLabel: "Confirm new password",
confirmPasswordPlaceholder: "Repeat new password",
passwordsMismatch: "Passwords do not match",
failedError: "Failed to change password",
connectionError: "Connection error",
changingButton: "Changing...",
changeButton: "Change password",
sidebarTitle: "Hello from the otter side!",
sidebarDescription: "Set a strong password to secure your account, then you're good to go.",
},
automate: {
title: "Automate",
invalidPipelineFile: "Not a valid SnapOtter pipeline file",
newerVersion: "This pipeline was created with a newer version of SnapOtter",
missingName: "Pipeline file is missing a name",
noSteps: "Pipeline file has no steps",
importFailed: "Import failed",
couldNotRead: "Could not read pipeline file",
fileCount: "{count} file",
fileCountPlural: "{count} files",
importFromLibrary: "Import from Library",
addButton: "+ Add",
libraryButton: "Library",
clearButton: "Clear",
processingFailed: "Processing failed for this file",
processingMultiple: "Processing {count} files...",
processingPipeline: "Processing pipeline...",
processButton: "Process",
processButtonMultiple: "Process ({count})",
processAllButton: "Process All ({count})",
addTool: "Add Tool",
toolPalette: "Tool Palette",
clickToAdd: "Click to add to pipeline",
savedLabel: "Saved",
importButton: "Import",
noSavedPipelines: "No saved pipelines",
stepCount: "({count} step)",
stepCountPlural: "({count} steps)",
exportPipeline: "Export pipeline",
deletePipeline: "Delete pipeline",
moreCount: "+{count} more",
pipelineBuilder: "Pipeline Builder",
addToolsPrompt: "Add tools from the palette to get started",
stepsConfigured: "{count} step configured",
stepsConfiguredPlural: "{count} steps configured",
noFilesLoaded: "No files loaded",
downloadZip: "Download ZIP",
saveButton: "Save",
pipelineNamePlaceholder: "Pipeline name",
descriptionPlaceholder: "Description",
savingIndicator: "...",
cancelButton: "Cancel",
preview: "Preview",
previousImage: "Previous image",
nextImage: "Next image",
imageCounter: "{current} / {total}",
imageArea: "Image area",
templateSocialMedia: "Social Media Ready",
templatePrivacyClean: "Privacy Clean",
templateWebOptimization: "Web Optimization",
templateProfilePicture: "Profile Picture",
templateWatermarkBatch: "Watermark Batch",
createNew: "Create New Automation",
savedAutomations: "Saved Automations",
templates: "Templates",
addStep: "Add Step",
removeStep: "Remove",
moveUp: "Move up",
moveDown: "Move down",
savePipeline: "Save Pipeline",
runPipeline: "Process",
pipelineName: "Pipeline Name",
pipelineDescription: "Description (optional)",
noStepsPrompt: "Add steps to build your automation",
noStepsHeading: "No steps yet",
searchToolsPlaceholder: "Search tools...",
step: "Step",
},
nav: {
tools: "Tools",
reader: "Reader",
automate: "Automate",
editor: "Editor",
files: "Files",
help: "Help",
settings: "Settings",
grid: "Grid",
},
files: {
myFiles: "My Files",
recentTab: "Recent",
uploadTab: "Upload Files",
fileDetailsAriaLabel: "File Details",
fileDetailsHeading: "File Details",
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",
urlFetchFailed: "Could not fetch image from URL",
ariaLabel: "File drop zone",
dropPrompt: "Drop your images here",
browseOrPaste: "click anywhere to browse, or paste from clipboard",
uploadButton: "Upload",
defaultFormats: "PNG, JPG, WebP, HEIC, RAW, PSD, and 65+ formats",
orSeparator: "or",
urlPlaceholder: "Paste image URL...",
urlLoadingIndicator: "...",
addUrlButton: "Add",
importMultipleUrls: "Import multiple URLs...",
filesSelected: "{count} files selected",
},
reviewPanel: {
processedResultAlt: "Processed result",
sizeLabel: "Size: {size}",
typeLabel: "Type: {type}",
processedLabel: "Processed: {time}",
undoButton: "Undo",
downloadButton: "Download",
openInEditor: "Open in Editor",
reviewHeading: "Review",
continueEditing: "Continue editing",
},
features: {
notEnabledTitle: "Feature Not Enabled",
notEnabledDescription:
"This feature is not enabled. Ask your administrator to enable it in Settings.",
requiresDownload: "This feature requires an additional download (~{size})",
retryButton: "Retry",
queued: "Queued for installation...",
enableButton: "Enable {name}",
repairRequired: "Repair Required",
repairDescription: "Some model files are missing or corrupted. Repair will re-download them.",
repairButton: "Repair {name}",
lessThanMinute: "Less than a minute left",
oneMinuteLeft: "~1 minute left",
minutesLeft: "~{mins} minutes left",
progressMessages: [
"Almost there... probably...",
"Good things take time...",
"Still faster than watching paint dry...",
"Your patience is truly inspiring...",
"Working harder than it looks...",
"This is the exciting part, trust me...",
"Doing important behind-the-scenes stuff...",
"If you're reading this, it's working...",
"Preparing something awesome...",
"Worth every second, pinky promise...",
"The suspense is part of the experience...",
"Teaching your computer new tricks...",
"Setting up your superpowers...",
"Your images will thank you later...",
"Loading... but make it fancy...",
"This would be a great time for coffee...",
"Rome wasn't built in a day either...",
"Shhh... genius at work...",
"Making your photos jealous of what's coming...",
"Assembling the dream team...",
"Unpacking awesomeness...",
"Almost done thinking about starting... just kidding...",
"Plot twist: this is actually doing something...",
"Warming up the creative engines...",
"Imagination loading...",
"Not a screensaver, we promise...",
"Great art takes time to install...",
"Your future self will thank you...",
"Grabbing some really smart files...",
"Hang tight, the best is yet to come...",
],
},
help: {
heading: "Help",
gettingStarted: {
heading: "Getting Started",
description:
"Select a tool from the sidebar or search for one. Upload an image by dragging it onto the page or clicking the upload area. Adjust settings and download your result.",
},
keyboardShortcuts: {
heading: "Keyboard Shortcuts",
focusSearchBar: "Focus search bar",
goToTools: "Go to tools",
toggleTheme: "Toggle theme",
goToResize: "Go to Resize",
goToCrop: "Go to Crop",
goToCompress: "Go to Compress",
goToConvert: "Go to Convert",
goToRemoveBackground: "Go to Remove Background",
goToWatermarkText: "Go to Watermark Text",
goToStripMetadata: "Go to Strip Metadata",
goToImageInfo: "Go to Image Info",
},
resources: {
heading: "Resources",
githubLink: "GitHub Repository",
reportIssueLink: "Report an Issue",
docsLink: "Documentation",
apiRefLink: "API Reference (Swagger)",
},
versionLabel: "SnapOtter v{version}",
},
errors: {
generic: "An error occurred",
offline: "You're offline",
reconnecting: "Reconnecting to server...",
connected: "Connected",
processingFailed: "Processing failed for this file",
timeout: "Request timed out. The server may be overloaded. Try again.",
networkError: "Network error. Check your connection.",
invalidCredentials: "Invalid username or password",
connectionError: "Connection error",
},
analytics: {
consentTitle: "Help improve SnapOtter",
consentDescription:
"Anonymous usage stats help us fix bugs and build the tools you actually need. Your images and files stay on your network.",
consentChangeable: "You can turn this off anytime in Settings.",
acceptButton: "Sure, sounds good",
declineButton: "Not right now",
settingsTitle: "Product Analytics",
settingsDescription: "Share anonymous usage data to help improve SnapOtter.",
settingsPrivacy: "Your images never leave your network.",
settingsDisabledByAdmin: "Product analytics has been disabled by the server administrator.",
learnMore: "Learn more",
},
sidebar: {
tools: "Tools",
grid: "Grid",
automate: "Automate",
editor: "Editor",
files: "Files",
help: "Help",
settings: "Settings",
},
toolCard: {
addToFavourites: "Add to favourites",
},
appLayout: {
mobileNavTools: "Tools",
mobileNavAutomate: "Automate",
mobileNavEditor: "Editor",
mobileNavFiles: "Files",
mobileNavSettings: "Settings",
},
a11y: {
skipToContent: "Skip to main content",
openSidebar: "Open sidebar",
closeSidebar: "Close sidebar",
closeSettings: "Close settings",
closeHelp: "Close help",
closeDialog: "Close dialog",
zoomIn: "Zoom in",
zoomOut: "Zoom out",
fitToView: "Fit to view",
actualSize: "Actual size",
previousImage: "Previous image",
nextImage: "Next image",
imageArea: "Image area",
imageViewer: "Image viewer",
fileDropZone: "File drop zone",
imageDropZone: "Image drop zone",
beforeAfterSlider: "Before/after comparison slider",
imageControls: "Image controls",
zoomControls: "Zoom controls",
dragToReorder: "Drag to reorder",
whiteBackground: "White background",
blackBackground: "Black background",
expandPanel: "Expand panel",
collapsePanel: "Collapse panel",
swapDimensions: "Swap dimensions",
applyCrop: "Apply crop",
cancelCrop: "Cancel crop",
fontFamily: "Font family",
textColor: "Text color",
flipHorizontal: "Flip horizontal",
flipVertical: "Flip vertical",
hexColorValue: "Hex color value",
backgroundColor: "Background color",
foregroundColor: "Foreground color",
swapColors: "Swap foreground and background colors",
resetColors: "Reset to default black and white",
foregroundHex: "Foreground color hex value",
undo: "Undo",
redo: "Redo",
layers: "Layers",
addLayer: "Add layer",
deleteLayer: "Delete layer",
cancelOperation: "Cancel operation",
fill: "Fill",
fileDetails: "File details",
language: "Language",
selected: "Selected",
deleteKey: "Delete key",
editRole: "Edit role",
deleteRole: "Delete role",
notInstalled: "Not installed",
queued: "Queued for install",
installing: "Installing",
imageNOfTotal: "Image {n} of {total}",
processingComplete: "Image processed successfully",
processingFailed: "Processing failed",
settingsDialog: "Settings",
helpDialog: "Help",
navigationMenu: "Navigation",
},
} as const;
type DeepStringRecord<T> = {
readonly [K in keyof T]: T[K] extends string
? string
: T[K] extends readonly string[]
? readonly string[]
: DeepStringRecord<T[K]>;
};
export type TranslationKeys = DeepStringRecord<typeof en>;