mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(web): add i18n architecture with English translations
Create translation key system in packages/shared/src/i18n/ with full English locale covering common actions, all 37 tools, settings sections, auth, pipeline, and navigation strings. Add useI18n hook that returns typed translations. Architecture enables adding new languages by creating locale files matching the TranslationKeys type.
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { en, type TranslationKeys } from "@stirling-image/shared";
|
||||
|
||||
/**
|
||||
* Simple i18n hook that returns the current locale translations.
|
||||
*
|
||||
* For now this always returns English. To add a new language:
|
||||
* 1. Create e.g. `packages/shared/src/i18n/de.ts` matching TranslationKeys shape
|
||||
* 2. Import it here and look up the locale from a store
|
||||
* 3. Return the correct locale object
|
||||
*/
|
||||
|
||||
const locales: Record<string, TranslationKeys> = {
|
||||
en,
|
||||
};
|
||||
|
||||
export function useI18n(): { t: TranslationKeys; locale: string } {
|
||||
// In the future, read from a locale store / user preferences
|
||||
const locale = "en";
|
||||
return { t: locales[locale] ?? en, locale };
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* English translations — the default / reference locale.
|
||||
*
|
||||
* Adding a new language is as simple as creating a new file (e.g. de.ts, fr.ts)
|
||||
* that satisfies the same shape as `TranslationKeys`.
|
||||
*/
|
||||
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",
|
||||
},
|
||||
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" },
|
||||
"strip-metadata": { name: "Strip Metadata", description: "Remove EXIF, GPS, and camera info" },
|
||||
"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" },
|
||||
favicon: { name: "Favicon Generator", description: "Generate all favicon and app icon sizes" },
|
||||
"brightness-contrast": { name: "Brightness & Contrast", description: "Adjust brightness and contrast levels" },
|
||||
saturation: { name: "Saturation & Exposure", description: "Adjust color saturation and exposure" },
|
||||
"color-channels": { name: "Color Channels", description: "Adjust individual R, G, B channels" },
|
||||
"color-effects": { name: "Color Effects", description: "Grayscale, Sepia, Invert, Tint" },
|
||||
"replace-color": { name: "Replace & Invert Color", description: "Replace specific colors or invert" },
|
||||
"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: "Paint over unwanted elements" },
|
||||
ocr: { name: "OCR / Text Extraction", description: "Extract text from images" },
|
||||
"blur-faces": { name: "Face / PII Blur", description: "Auto-detect and blur faces and sensitive info" },
|
||||
"smart-crop": { name: "Smart Crop", description: "AI detects subject and crops optimally" },
|
||||
"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" },
|
||||
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 QR codes from text or URLs" },
|
||||
"barcode-read": { name: "Barcode Reader", description: "Read QR codes and barcodes from images" },
|
||||
collage: { name: "Collage / Grid", description: "Combine images into a grid layout" },
|
||||
split: { name: "Image Splitting", description: "Split image into grid parts" },
|
||||
border: { name: "Border & Frame", description: "Add borders, rounded corners, shadows" },
|
||||
"svg-to-raster": { name: "SVG to Raster", description: "Convert SVG to PNG/JPG at custom resolution" },
|
||||
vectorize: { name: "Image to SVG", description: "Vectorize images using tracing" },
|
||||
"gif-tools": { name: "GIF Tools", description: "Resize/crop/convert animated GIFs" },
|
||||
pipeline: { name: "Pipeline Builder", description: "Chain multiple tools into a workflow" },
|
||||
batch: { name: "Batch Processing", description: "Apply any tool to multiple images" },
|
||||
},
|
||||
settings: {
|
||||
title: "Settings",
|
||||
general: "General",
|
||||
system: "System Settings",
|
||||
security: "Security",
|
||||
apiKeys: "API Keys",
|
||||
about: "About",
|
||||
username: "Username",
|
||||
logout: "Log out",
|
||||
defaultView: "Default Tool View",
|
||||
sidebarView: "Sidebar",
|
||||
fullscreenView: "Fullscreen Grid",
|
||||
version: "Version",
|
||||
appName: "App Name",
|
||||
uploadLimit: "File Upload Limit",
|
||||
defaultTheme: "Default Theme",
|
||||
defaultLocale: "Default Locale",
|
||||
changePassword: "Change Password",
|
||||
currentPassword: "Current Password",
|
||||
newPassword: "New Password",
|
||||
confirmPassword: "Confirm Password",
|
||||
passwordChanged: "Password changed successfully",
|
||||
loginAttemptLimit: "Login Attempt Limit",
|
||||
generateKey: "Generate API Key",
|
||||
regenerateKey: "Regenerate",
|
||||
copyKey: "Copy Key",
|
||||
aboutDescription: "Stirling Image is a self-hosted, privacy-first image processing suite with 37+ tools.",
|
||||
aboutLinks: "Links",
|
||||
github: "GitHub",
|
||||
documentation: "Documentation",
|
||||
},
|
||||
auth: {
|
||||
login: "Login",
|
||||
logout: "Log out",
|
||||
username: "Username",
|
||||
password: "Password",
|
||||
loginButton: "Login",
|
||||
loggingIn: "Logging in...",
|
||||
invalidCredentials: "Invalid username or password",
|
||||
connectionError: "Connection error",
|
||||
},
|
||||
pipeline: {
|
||||
title: "Automate",
|
||||
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)",
|
||||
noSteps: "Add steps to build your automation",
|
||||
step: "Step",
|
||||
settings: "Settings",
|
||||
processing: "Processing pipeline...",
|
||||
socialMediaReady: "Social Media Ready",
|
||||
privacyClean: "Privacy Clean",
|
||||
webOptimization: "Web Optimization",
|
||||
profilePicture: "Profile Picture",
|
||||
watermarkBatch: "Watermark Batch",
|
||||
},
|
||||
nav: {
|
||||
tools: "Tools",
|
||||
reader: "Reader",
|
||||
automate: "Automate",
|
||||
files: "Files",
|
||||
help: "Help",
|
||||
settings: "Settings",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type TranslationKeys = typeof en;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { en } from "./en.js";
|
||||
export type { TranslationKeys } from "./en.js";
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./types.js";
|
||||
export * from "./constants.js";
|
||||
export * from "./i18n/index.js";
|
||||
|
||||
Reference in New Issue
Block a user