Files
SnapOtter/packages/shared/src/i18n/en.ts
T
SnapOtter e70fca054a fix: replace hardcoded "52 tools" with "50+" across all copy
Future-proofs marketing text so it doesn't need updating every time
a tool is added.
2026-05-20 14:45:45 +08:00

1933 lines
66 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",
},
categories: {
essentials: "Essentials",
optimization: "Optimization",
adjustments: "Adjustments",
watermark: "Watermark & Overlay",
utilities: "Utilities",
layout: "Layout & Composition",
format: "Format & Conversion",
ai: "AI Tools",
},
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",
},
"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",
},
pipeline: { name: "Pipeline Builder", description: "Chain multiple tools into a workflow" },
},
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",
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",
},
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...",
filename: "Filename",
fileSize: "File Size",
dimensions: "Dimensions",
format: "Format",
channels: "Channels",
colorSpace: "Color Space",
density: "Density",
bitDepth: "Bit Depth",
progressive: "Progressive",
pages: "Pages",
hasAlpha: "Has Alpha",
hasProfile: "Has Profile",
hasExif: "Has EXIF",
hasIcc: "Has ICC",
hasXmp: "Has XMP",
},
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",
},
"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",
},
},
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",
},
},
settings: {
heading: "Settings",
nav: {
general: "General",
systemSettings: "System Settings",
security: "Security",
people: "People",
teams: "Teams",
roles: "Roles",
auditLog: "Audit Log",
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",
},
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 4 characters",
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",
},
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...",
},
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 50+ 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)",
},
},
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.",
"50+ image 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",
step: "Step",
},
nav: {
tools: "Tools",
reader: "Reader",
automate: "Automate",
editor: "Editor",
files: "Files",
help: "Help",
settings: "Settings",
grid: "Grid",
},
files: {
recentTab: "Recent",
uploadTab: "Upload",
fileDetailsAriaLabel: "File Details",
fileDetailsHeading: "File Details",
},
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}",
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",
},
} 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>;