ccc41a2018
- MinIO had no CORS config at all, so the browser's direct PUT to a presigned URL (cross-origin: app on :3001/:3000, storage on :9000) was blocked outright. Added MINIO_API_CORS_ALLOW_ORIGIN — "*" in dev, the app's own origin in prod. Verified end-to-end: photo upload now succeeds with zero console errors. - Removed the public /changelog page and its account-menu link — changelog is admin-only now (/admin/changelog). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1165 lines
47 KiB
JSON
1165 lines
47 KiB
JSON
{
|
||
"nav": {
|
||
"menu": "Menu",
|
||
"recipes": "Recipes",
|
||
"explore": "Explore",
|
||
"search": "Search",
|
||
"feed": "Feed",
|
||
"collections": "Collections",
|
||
"mealPlan": "Meal Plan",
|
||
"nutrition": "Nutrition",
|
||
"pantry": "Pantry",
|
||
"shopping": "Shopping",
|
||
"settings": "Settings",
|
||
"admin": "Admin",
|
||
"signOut": "Sign out",
|
||
"apiKeys": "API keys",
|
||
"webhooks": "Webhooks",
|
||
"language": "Language",
|
||
"notifications": "Notifications",
|
||
"viewProfile": "View profile",
|
||
"lightMode": "Light mode",
|
||
"darkMode": "Dark mode",
|
||
"systemMode": "System"
|
||
},
|
||
"notifications": {
|
||
"title": "Notifications",
|
||
"empty": "No notifications yet.",
|
||
"markAllRead": "Mark all as read",
|
||
"viewAll": "View all",
|
||
"loading": "Loading…",
|
||
"loadMore": "Load more",
|
||
"loadFailed": "Failed to load notifications. Check your connection and try again.",
|
||
"retry": "Retry",
|
||
"unread": "Unread",
|
||
"follow": "{name} followed you",
|
||
"comment": "{name} commented on your recipe",
|
||
"reply": "{name} replied to your comment",
|
||
"reaction": "{name} reacted to your comment",
|
||
"rating": "{name} rated your recipe",
|
||
"mention": "{name} mentioned you in a comment",
|
||
"detail": {
|
||
"comment": "{name} commented on your recipe \"{title}\"",
|
||
"rating": "{name} rated your recipe \"{title}\" {stars} stars",
|
||
"leftoverExpiring": "Your \"{dish}\" from \"{title}\" is about to expire — eat it soon!"
|
||
},
|
||
"pushTitle": {
|
||
"follow": "New follower",
|
||
"comment": "New comment",
|
||
"reply": "New reply",
|
||
"reaction": "New reaction",
|
||
"rating": "New rating",
|
||
"mention": "You were mentioned",
|
||
"leftoverExpiring": "Leftovers expiring soon"
|
||
}
|
||
},
|
||
"recipe": {
|
||
"byAuthor": "by {name}",
|
||
"source": "Source",
|
||
"share": "Share",
|
||
"shareLinkCopied": "Link copied to clipboard",
|
||
"shareCopyFailed": "Failed to copy link",
|
||
"shareNotPublicNotice": "This link will only work once the recipe is set to Public — link copied anyway.",
|
||
"print": "Print",
|
||
"ingredients": "Ingredients",
|
||
"instructions": "Instructions",
|
||
"photos": "Photos",
|
||
"batchCookBadge": "Batch cooking",
|
||
"batchCookPrep": "Prep",
|
||
"batchCookDishesTitle": "Dishes & storage",
|
||
"batchCookFridgeDays": "Fridge: {days}d",
|
||
"batchCookFreezerFriendly": "Freezer-friendly",
|
||
"batchCookDayOf": "On the day",
|
||
"batchCookMarkCooked": "Mark as cooked today",
|
||
"batchCookMarkSuccess": "Marked as cooked",
|
||
"batchCookMarkFailed": "Failed to mark as cooked",
|
||
"batchCookExpiresOn": "Cooked — good until {date}",
|
||
"servings": "{count} servings",
|
||
"prep": "{mins}m prep",
|
||
"cook": "{mins}m cook",
|
||
"total": "{mins}m total",
|
||
"edit": "Edit",
|
||
"variations": "Variations",
|
||
"save": "Save",
|
||
"cancel": "Cancel",
|
||
"delete": "Delete",
|
||
"noIngredientsSteps": "No ingredients or steps yet.",
|
||
"generateContent": "Generate with AI",
|
||
"editManually": "Edit manually",
|
||
"deleted": "Recipe deleted",
|
||
"deleteFailed": "Delete failed",
|
||
"imported": "Recipe imported! Review before publishing.",
|
||
"adapted": "Adapted recipe saved as draft",
|
||
"adaptFailed": "Failed to adapt recipe",
|
||
"adaptConstraintRequired": "Select at least one ingredient to exclude or add a constraint",
|
||
"adaptTooltip": "Adapt",
|
||
"adaptTitle": "Adapt this recipe",
|
||
"adaptDescription": "Tap ingredients to exclude them. AI will find the best substitutes while preserving the dish.",
|
||
"excludeIngredients": "Exclude ingredients",
|
||
"excludedCount": "{count} excluded",
|
||
"additionalConstraints": "Additional constraints",
|
||
"optional": "optional",
|
||
"adapting": "Adapting recipe — this may take 20–30 seconds…",
|
||
"adaptingButton": "Adapting…",
|
||
"adaptButton": "Adapt recipe",
|
||
"clearExclusions": "Clear",
|
||
"variationsDirectionsPlaceholder": "e.g. make it vegan, use only pantry staples, reduce sugar…",
|
||
"historyRestoreFailed": "Failed to restore version",
|
||
"pairingMealFailed": "Failed to suggest pairings",
|
||
"pairingDrinkFailed": "Failed to suggest drinks",
|
||
"pairingGenerateFailed": "Failed to generate \"{name}\"",
|
||
"pairingSaveFailed": "Failed to save \"{name}\"",
|
||
"pairingSuccess": "Recipe generated — review before publishing",
|
||
"pairingBulkSuccess": "{count} recipes generated — find them in your library",
|
||
"pairingDialogTitle": "Complete the meal",
|
||
"pairingDialogDescription": "AI-suggested dishes that pair well with this recipe. Generate any of them as a new recipe.",
|
||
"forkTooltip": "Fork this recipe",
|
||
"forked": "Recipe forked to your library",
|
||
"forkFailed": "Failed to fork recipe",
|
||
"forkLimitReached": "Recipe limit reached for your tier",
|
||
"forkedFrom": "Forked from {title}",
|
||
"pairingFindingLabel": "Finding perfect pairings…",
|
||
"pairingSuggestButton": "Suggest pairings",
|
||
"pairingRegenerate": "Regenerate",
|
||
"pairingGenerateButton": "Generate",
|
||
"pairingGeneratingButton": "Generating {current}/{total}…",
|
||
"pairingGeneratingLabel": "Generating recipe {current} of {total}…",
|
||
"pairingRoleStarter": "Starter",
|
||
"pairingRoleSide": "Side",
|
||
"pairingRoleSalad": "Salad",
|
||
"pairingRoleBread": "Bread",
|
||
"pairingRoleDrink": "Drink",
|
||
"pairingRoleDessert": "Dessert",
|
||
"pairingRoleSauce": "Sauce",
|
||
"drinksDialogTitle": "Drink pairings",
|
||
"drinksDialogDescription": "AI-suggested drinks that complement this recipe.",
|
||
"drinksSuggestButton": "Suggest drinks",
|
||
"drinksExamplesLabel": "e.g.",
|
||
"drinksTypeWine": "Wine",
|
||
"drinksTypeBeer": "Beer",
|
||
"drinksTypeCocktail": "Cocktail",
|
||
"drinksTypeSpirit": "Spirit",
|
||
"drinksTypeNonAlcoholic": "Non-alcoholic",
|
||
"drinksTypeHot": "Hot",
|
||
"cookAction": "Cook",
|
||
"adaptConstraintPlaceholder": "e.g. Make it vegan, lower the calories, use pantry staples only, gluten-free…",
|
||
"photoImportFailed": "Failed to import recipe from photo.",
|
||
"importFromPhoto": "Import from Photo",
|
||
"urlImportTitle": "Import recipe from URL",
|
||
"urlImportDescription": "Paste a recipe URL and AI will extract the ingredients and instructions.",
|
||
"urlImportLabel": "Recipe URL",
|
||
"urlImportButton": "Import",
|
||
"urlImportingButton": "Importing…",
|
||
"urlImportFetchFailed": "Failed to import recipe",
|
||
"urlImportSaveFailed": "Failed to save imported recipe",
|
||
"urlImportSuccess": "Recipe imported! Review before publishing.",
|
||
"diffTitleLabel": "Title",
|
||
"diffDescriptionLabel": "Description",
|
||
"diffIngredientsLabel": "Ingredients",
|
||
"diffStepsLabel": "Steps",
|
||
"viewGrid": "Grid view",
|
||
"viewList": "List view",
|
||
"viewCompact": "Compact view",
|
||
"updatedLabel": "Updated {date}",
|
||
"addToCollection": "Add to collection",
|
||
"addToCollectionTitle": "Add {count, plural, one {1 recipe} other {{count} recipes}} to a collection",
|
||
"newCollectionOption": "New collection…",
|
||
"newCollectionNamePlaceholder": "Collection name",
|
||
"addToCollectionSuccess": "{count, plural, one {1 recipe} other {{count} recipes}} added to \"{name}\"",
|
||
"addToCollectionFailed": "Failed to add to collection",
|
||
"createCollectionFailed": "Failed to create collection",
|
||
"noCollectionsYet": "You don't have any collections yet.",
|
||
"versionHistoryTitle": "Version History",
|
||
"versionsLoading": "Loading versions...",
|
||
"versionsEmpty": "No versions yet. Versions are saved automatically when you edit this recipe.",
|
||
"versionCompare": "Compare",
|
||
"versionCompareWith": "Compare v{version} with current",
|
||
"versionRestore": "Restore",
|
||
"versionRestored": "Recipe restored to version {version}",
|
||
"versionDetailLoading": "Loading...",
|
||
"versionDetailSummary": "{ingredients, plural, one {1 ingredient} other {{ingredients} ingredients}}, {steps, plural, one {1 step} other {{steps} steps}}",
|
||
"analyzingPhoto": "Analyzing photo…",
|
||
"pairMealTooltip": "Pair meal",
|
||
"historyTooltip": "History",
|
||
"translateTooltip": "Translate",
|
||
"drinksTooltip": "Drinks",
|
||
"variationsTooltip": "Variations",
|
||
"viewPublicly": "View publicly",
|
||
"shoppingListCreateFailed": "Failed to create list",
|
||
"shoppingListAddFailed": "Failed to add ingredients",
|
||
"bulkDeleted": "{count, plural, one {1 recipe deleted} other {{count} recipes deleted}}",
|
||
"bulkVisibility": "{count, plural, one {1 recipe set to {visibility}} other {{count} recipes set to {visibility}}}",
|
||
"bulkDeleteFailed": "Delete failed",
|
||
"bulkUpdateFailed": "Update failed",
|
||
"bulkDeleteConfirmTitle": "{count, plural, one {Delete 1 recipe?} other {Delete {count} recipes?}}",
|
||
"bulkDeleteConfirmDescription": "This action cannot be undone.",
|
||
"deselectAll": "Deselect all",
|
||
"selectAll": "Select all",
|
||
"clickToSelect": "Click cards to select",
|
||
"selectedCount": "{count} selected",
|
||
"select": "Select",
|
||
"visibilityMenuLabel": "Visibility",
|
||
"makePublic": "Make public",
|
||
"makeUnlisted": "Make unlisted",
|
||
"makePrivate": "Make private",
|
||
"visibility": {
|
||
"private": "Private",
|
||
"unlisted": "Unlisted",
|
||
"public": "Public"
|
||
},
|
||
"difficulty": {
|
||
"easy": "Easy",
|
||
"medium": "Medium",
|
||
"hard": "Hard"
|
||
},
|
||
"dietary": {
|
||
"vegan": "Vegan",
|
||
"vegetarian": "Vegetarian",
|
||
"glutenFree": "Gluten-free",
|
||
"dairyFree": "Dairy-free",
|
||
"nutFree": "Nut-free",
|
||
"halal": "Halal",
|
||
"kosher": "Kosher"
|
||
}
|
||
},
|
||
"ai": {
|
||
"generate": {
|
||
"title": "Generate recipe with AI",
|
||
"description": "Describe what you want to cook and AI will create a complete recipe.",
|
||
"descriptionFull": "Describe a dish in words or snap a photo — AI builds the full recipe.",
|
||
"tabDescribe": "Describe",
|
||
"tabPhoto": "From photo",
|
||
"surpriseMe": "Surprise me",
|
||
"prompt": "What do you want to cook?",
|
||
"placeholder": "e.g. A creamy mushroom risotto with parmesan, serves 4, easy difficulty",
|
||
"language": "Recipe language",
|
||
"difficulty": "Difficulty",
|
||
"anyDifficulty": "Any",
|
||
"button": "Generate",
|
||
"generating": "Generating…",
|
||
"success": "Recipe generated! Review and edit before publishing.",
|
||
"error": "Failed to generate recipe",
|
||
"saveError": "Failed to save generated recipe",
|
||
"uploadClick": "Click to upload",
|
||
"uploadDrag": "or drag a food photo",
|
||
"uploadFormats": "JPEG, PNG or WebP · AI will reverse-engineer the recipe",
|
||
"analyzing": "Analyzing…",
|
||
"analyzePhoto": "Analyzing dish photo…",
|
||
"recognizeDish": "Recognize dish",
|
||
"photoSuccess": "Recipe recognized! Review and edit before publishing.",
|
||
"photoError": "Failed to analyze photo",
|
||
"contentGenerated": "Ingredients and steps generated!",
|
||
"contentGenerateFailed": "Generation failed",
|
||
"contentSaveFailed": "Failed to save generated content",
|
||
"generatingContent": "Generating recipe content…",
|
||
"photoAnalysisNote": "AI will analyze this dish and infer ingredients, quantities, and cooking steps."
|
||
},
|
||
"variations": {
|
||
"title": "AI Recipe Variations",
|
||
"description": "Generate creative variations of this recipe — dietary adaptations, flavor twists, technique changes.",
|
||
"generate": "Generate 3 variations",
|
||
"generating": "Generating variations…",
|
||
"regenerate": "Regenerate",
|
||
"apply": "Apply",
|
||
"applying": "Applying…",
|
||
"ingredientChanges": "Ingredient changes",
|
||
"stepChanges": "Step changes",
|
||
"success": "Variation created — review and edit before publishing.",
|
||
"error": "Failed to generate variations",
|
||
"saveError": "Failed to save variation",
|
||
"wait": "This may take 20–30 seconds",
|
||
"directions": "Directions",
|
||
"optional": "optional",
|
||
"stepLabel": "Step {n}"
|
||
},
|
||
"translate": {
|
||
"title": "Translate Recipe",
|
||
"description": "Translate this recipe's title, description, ingredients, and steps into another language.",
|
||
"targetLanguage": "Target language",
|
||
"button": "Translate",
|
||
"translating": "Translating…",
|
||
"success": "Translation saved as new draft recipe.",
|
||
"error": "Failed to translate recipe",
|
||
"saveError": "Failed to save translated recipe",
|
||
"wait": "This may take 20–30 seconds"
|
||
}
|
||
},
|
||
"settings": {
|
||
"title": "Settings",
|
||
"subtitle": "Manage your account, preferences, and integrations.",
|
||
"profile": "Profile",
|
||
"language": "Language",
|
||
"units": "Units",
|
||
"metric": "Metric",
|
||
"imperial": "Imperial",
|
||
"security": "Security",
|
||
"aiModels": "AI & Models",
|
||
"notifications": "Notifications",
|
||
"nutrition": "Nutrition",
|
||
"apiKeys": "API Keys",
|
||
"webhooks": "Webhooks",
|
||
"byok": {
|
||
"title": "Your API Keys (BYOK)",
|
||
"description": "Use your own API keys instead of the app's shared quota. Keys are encrypted at rest."
|
||
},
|
||
"modelPrefs": {
|
||
"title": "Model Preferences",
|
||
"description": "Choose which model to use for each task. Defaults to your first configured provider."
|
||
},
|
||
"apiKeysPage": {
|
||
"title": "API Keys",
|
||
"description": "Manage API keys for programmatic access to the Epicure API.",
|
||
"docsLink": "View API documentation"
|
||
},
|
||
"pushNotifications": {
|
||
"title": "Push Notifications",
|
||
"description": "Get notified when someone comments on your recipes or likes your content."
|
||
},
|
||
"nutritionGoals": {
|
||
"title": "Daily Nutrition Goals",
|
||
"description": "Set your daily targets. These are shown as progress bars on your meal plan.",
|
||
"viewDiaryCta": "View nutrition diary",
|
||
"caloriesLabel": "Calories (kcal/day)",
|
||
"proteinLabel": "Protein (g/day)",
|
||
"carbsLabel": "Carbs (g/day)",
|
||
"fatLabel": "Fat (g/day)",
|
||
"caloriesPlaceholder": "e.g. 2000",
|
||
"proteinPlaceholder": "e.g. 50",
|
||
"carbsPlaceholder": "e.g. 250",
|
||
"fatPlaceholder": "e.g. 70",
|
||
"saveButton": "Save goals",
|
||
"saving": "Saving...",
|
||
"saveSuccess": "Nutrition goals saved",
|
||
"saveError": "Failed to save nutrition goals"
|
||
},
|
||
"webhooksPage": {
|
||
"title": "Webhooks",
|
||
"description": "Receive HTTP callbacks when events happen in your Epicure account."
|
||
}
|
||
},
|
||
"print": {
|
||
"footer": "Printed from Epicure",
|
||
"day": "Day",
|
||
"srv": " · {count} srv",
|
||
"days": {
|
||
"mon": "Monday",
|
||
"tue": "Tuesday",
|
||
"wed": "Wednesday",
|
||
"thu": "Thursday",
|
||
"fri": "Friday",
|
||
"sat": "Saturday",
|
||
"sun": "Sunday"
|
||
}
|
||
},
|
||
"publicRecipe": {
|
||
"publicRecipeBy": "Public recipe by",
|
||
"viewInLibrary": "View in your library",
|
||
"signUpFree": "Sign up free",
|
||
"logIn": "Log in",
|
||
"wantToSave": "Want to save this recipe?",
|
||
"wantToSaveDescription": "Create a free account to save recipes, scale servings, and build your own library.",
|
||
"getStartedFree": "Get started free"
|
||
},
|
||
"substitute": {
|
||
"fetchError": "Couldn't fetch substitutes.",
|
||
"titleFor": "Substitute for {ingredient}",
|
||
"substitutesFor": "Substitutes for",
|
||
"finding": "Finding substitutes…",
|
||
"noneFound": "No substitutions found."
|
||
},
|
||
"recipeChat": {
|
||
"sorry": "Sorry, I couldn't answer that.",
|
||
"error": "Something went wrong. Please try again.",
|
||
"suggestion1": "Can I substitute any ingredients?",
|
||
"suggestion2": "How do I know when it's done?",
|
||
"suggestion3": "Can I make this ahead of time?",
|
||
"suggestion4": "What can I serve with this?",
|
||
"ariaLabel": "Ask AI about this recipe",
|
||
"title": "Ask about this recipe",
|
||
"intro": "Ask anything about this recipe — ingredients, techniques, substitutions, timing…",
|
||
"inputPlaceholder": "Ask a question…",
|
||
"send": "Send message"
|
||
},
|
||
"servingScaler": {
|
||
"servings": "Servings",
|
||
"reset": "Reset",
|
||
"aiScale": "AI Scale",
|
||
"scaling": "Scaling…",
|
||
"aiScaledNote": "AI-scaled quantities shown below",
|
||
"dismissAiScaling": "Dismiss AI scaling"
|
||
},
|
||
"people": {
|
||
"title": "Find People",
|
||
"subtitle": "Search for cooks to follow by name or username.",
|
||
"searchPlaceholder": "Search people by name or username…",
|
||
"searching": "Searching…",
|
||
"noneFound": "No one found."
|
||
},
|
||
"messages": {
|
||
"loading": "Loading…",
|
||
"noMessagesYet": "No messages yet. Say hi!",
|
||
"sendFailed": "Failed to send",
|
||
"placeholder": "Type a message…",
|
||
"noConversationsYet": "No conversations yet. Visit a profile to say hi.",
|
||
"unknownUser": "Unknown",
|
||
"noMessagesPreview": "No messages yet",
|
||
"selectConversation": "Select a conversation",
|
||
"messageButton": "Message",
|
||
"startConversationFailed": "Failed to start conversation",
|
||
"title": "Messages",
|
||
"loadOlder": "Load older messages",
|
||
"loadingOlder": "Loading…",
|
||
"send": "Send message"
|
||
},
|
||
"nutritionPanel": {
|
||
"estimateButton": "Estimate nutrition",
|
||
"reEstimateButton": "Re-estimate",
|
||
"estimating": "Estimating…",
|
||
"estimatingNutrition": "Estimating nutrition…",
|
||
"title": "Nutrition per serving",
|
||
"estimateFailed": "Failed to estimate nutrition",
|
||
"error": "Something went wrong",
|
||
"protein": "Protein",
|
||
"carbs": "Carbs",
|
||
"fat": "Fat",
|
||
"fiber": "Fiber",
|
||
"sodium": "Sodium"
|
||
},
|
||
"nutritionDiary": {
|
||
"title": "Nutrition Diary",
|
||
"subtitle": "Your daily nutrition intake, computed from what you've cooked.",
|
||
"dateLabel": "Date",
|
||
"today": "Today",
|
||
"loading": "Loading…",
|
||
"loadError": "Couldn't load your nutrition diary. Please try again.",
|
||
"goalNotSet": "You haven't set daily nutrition goals yet.",
|
||
"setGoalsCta": "Set goals",
|
||
"calories": "Calories",
|
||
"protein": "Protein",
|
||
"carbs": "Carbs",
|
||
"fat": "Fat",
|
||
"fiber": "Fiber",
|
||
"sodium": "Sodium",
|
||
"entriesTitle": "Recipes cooked",
|
||
"noEntries": "Nothing logged for this day. Mark a recipe as \"cooked\" to see it here.",
|
||
"servingsLabel": "{count, plural, one {1 serving} other {{count} servings}}",
|
||
"nutritionUnknownBadge": "Nutrition unknown",
|
||
"unknownNote": "{count, plural, one {1 entry has no nutrition data and isn't included in the totals above.} other {{count} entries have no nutrition data and aren't included in the totals above.}}"
|
||
},
|
||
"explore": {
|
||
"title": "Explore",
|
||
"tabRecipes": "Recipes",
|
||
"tabPeople": "People",
|
||
"searchPlaceholder": "Search public recipes…",
|
||
"maxMinutes": "Max minutes",
|
||
"aiSearchPlaceholder": "e.g. quick weeknight dinners, Italian comfort food…",
|
||
"anyDifficulty": "Any difficulty",
|
||
"resultsFoundSingular": "{count} recipe found",
|
||
"resultsFoundPlural": "{count} recipes found",
|
||
"noResultsTitle": "No recipes found for “{query}”",
|
||
"noResultsHint": "Try different keywords or remove filters",
|
||
"loadMore": "Load more",
|
||
"recipeIdeas": "Recipe ideas",
|
||
"recipeIdeasHint": "Tell the AI what you're in the mood for, or let it surprise you.",
|
||
"generating": "Generating…",
|
||
"getIdeas": "Get ideas",
|
||
"surpriseMe": "Surprise me",
|
||
"generateFullRecipe": "Generate full recipe",
|
||
"trendingThisWeek": "Trending this week",
|
||
"noTrending": "No trending recipes yet. Be the first to share one!",
|
||
"recentlyAdded": "Recently added",
|
||
"noRecent": "No public recipes yet."
|
||
},
|
||
"common": {
|
||
"loading": "Loading…",
|
||
"error": "Something went wrong",
|
||
"save": "Save",
|
||
"saved": "Saved",
|
||
"saveFailed": "Failed to save",
|
||
"exportMarkdown": "Export as Markdown",
|
||
"copyMarkdown": "Copy as Markdown",
|
||
"downloadMarkdown": "Download as Markdown",
|
||
"copiedToClipboard": "Copied to clipboard",
|
||
"copyFailed": "Failed to copy to clipboard",
|
||
"print": "Print",
|
||
"share": "Share",
|
||
"deleteFailed": "Delete failed",
|
||
"updateFailed": "Update failed",
|
||
"deleted": "Deleted",
|
||
"cancel": "Cancel",
|
||
"delete": "Delete",
|
||
"confirm": "Confirm",
|
||
"back": "Back",
|
||
"difficulty": "Difficulty",
|
||
"anyDifficulty": "Any",
|
||
"editManually": "Edit manually",
|
||
"surpriseMe": "Surprise me",
|
||
"generatingContent": "Generating recipe content…",
|
||
"decrease": "Decrease",
|
||
"increase": "Increase"
|
||
},
|
||
"auth": {
|
||
"signIn": "Sign in",
|
||
"signInTitle": "Sign in to your recipe library",
|
||
"signInLoading": "Signing in…",
|
||
"signInFailed": "Sign in failed",
|
||
"signUp": "Sign up",
|
||
"signUpTitle": "Create account",
|
||
"signUpSubtitle": "Start building your recipe library",
|
||
"signUpLoading": "Creating account…",
|
||
"signUpFailed": "Sign up failed",
|
||
"signUpSuccess": "Account created — check your email to verify",
|
||
"continueWithGoogle": "Continue with Google",
|
||
"continueWithGithub": "Continue with GitHub",
|
||
"continueWithDiscord": "Continue with Discord",
|
||
"continueWithAuthentik": "Continue with Authentik",
|
||
"email": "Email",
|
||
"emailPlaceholder": "you@example.com",
|
||
"password": "Password",
|
||
"name": "Name",
|
||
"namePlaceholder": "Your name",
|
||
"forgotPassword": "Forgot password?",
|
||
"forgotPasswordTitle": "Forgot password",
|
||
"forgotPasswordSent": "Check your inbox",
|
||
"forgotPasswordDescription": "Enter your email and we'll send you a reset link.",
|
||
"forgotPasswordSentDescription": "If an account exists for that email, you'll receive a reset link shortly.",
|
||
"forgotPasswordFailed": "Failed to send reset email",
|
||
"sendResetLink": "Send reset link",
|
||
"sendingLink": "Sending…",
|
||
"resetPasswordTitle": "Reset password",
|
||
"resetPasswordDescription": "Enter a new password for your account.",
|
||
"newPassword": "New password",
|
||
"confirmPassword": "Confirm password",
|
||
"updatePassword": "Update password",
|
||
"updatingPassword": "Updating…",
|
||
"invalidToken": "Invalid or missing reset token.",
|
||
"resetPasswordMismatch": "Passwords don't match",
|
||
"resetPasswordFailed": "Reset failed — link may have expired",
|
||
"resetPasswordSuccess": "Password updated",
|
||
"noAccount": "No account? Sign up",
|
||
"alreadyHaveAccount": "Already have an account? Sign in",
|
||
"backToSignIn": "Back to sign in",
|
||
"emailNotVerified": "Email not verified",
|
||
"checkInboxVerification": "Check your inbox for a verification email.",
|
||
"resendVerification": "Resend verification email",
|
||
"resendingSending": "Sending…",
|
||
"resendFailed": "Failed to resend",
|
||
"resendSuccess": "Verification email sent — check your inbox",
|
||
"or": "or"
|
||
},
|
||
"batchCooking": {
|
||
"title": "Batch cooking",
|
||
"subtitle": "Cook once, eat well all week",
|
||
"empty": "No batch-cooking sessions yet",
|
||
"newSession": "New batch-cooking session",
|
||
"dishCount": "{count, plural, one {# dish} other {# dishes}}",
|
||
"wizardTitle": "Plan a batch-cooking session",
|
||
"wizardDescription": "Choose how many meals to cover — we'll design a shared shopping list and one prep session for all of them.",
|
||
"dinners": "Dinners",
|
||
"lunches": "Lunches",
|
||
"servingsPerMeal": "Servings per meal",
|
||
"dietaryPrefs": "Dietary preferences",
|
||
"dietaryPrefsPlaceholder": "e.g. vegetarian, no shellfish",
|
||
"anyDifficulty": "Any",
|
||
"generate": "Generate",
|
||
"generating": "Generating…",
|
||
"generateSuccess": "Batch-cooking session created",
|
||
"generateFailed": "Failed to generate"
|
||
},
|
||
"recipes": {
|
||
"title": "Recipes",
|
||
"subtitle": "Your personal recipe library",
|
||
"new": "New recipe",
|
||
"newTitle": "New recipe",
|
||
"newSubtitle": "Build your recipe from scratch",
|
||
"importUrl": "Import URL",
|
||
"generate": "Generate",
|
||
"batchCooking": "Batch cooking",
|
||
"search": "Search recipes…",
|
||
"noRecipes": "No recipes yet",
|
||
"noMatch": "No recipes match",
|
||
"clearSearch": "Clear search",
|
||
"createFirst": "Create your first recipe",
|
||
"resultSingular": "{count} recipe",
|
||
"resultPlural": "{count} recipes",
|
||
"for": "for",
|
||
"filterByTag": "Filter by tag…",
|
||
"sortRecentlyUpdated": "Recently updated",
|
||
"sortOldestUpdated": "Oldest updated",
|
||
"sortNewestFirst": "Newest first",
|
||
"sortOldestFirst": "Oldest first",
|
||
"sortTitleAZ": "Title A–Z",
|
||
"sortTitleZA": "Title Z–A",
|
||
"sort": "Sort",
|
||
"sortBy": "Sort by",
|
||
"filter": "Filter",
|
||
"all": "All",
|
||
"anyDifficulty": "Any difficulty",
|
||
"visibilityLabel": "Visibility",
|
||
"difficultyLabel": "Difficulty",
|
||
"tagLabel": "Tag",
|
||
"batchCookLabel": "Batch cooking",
|
||
"batchCookOnly": "Batch cooking only",
|
||
"batchCookExclude": "Hide batch cooking",
|
||
"clearFilters": "Clear filters",
|
||
"tabMine": "My Recipes",
|
||
"tabFavorites": "Favorites",
|
||
"favoritesCount": "{count} favorited recipe",
|
||
"favoritesCountPlural": "{count} favorited recipes",
|
||
"favoritesEmpty": "No favorited recipes yet — tap the heart on any recipe to save it here.",
|
||
"favoritesEmptyTitle": "No favorites yet",
|
||
"exploreRecipes": "Explore recipes",
|
||
"emptyStateDescription": "Create your own, import from a URL, or let AI generate one to get started."
|
||
},
|
||
"recipeNotes": {
|
||
"title": "Your private notes",
|
||
"visibilityHint": "Only visible to you — never shared with the recipe's author or anyone else.",
|
||
"placeholder": "e.g. I used less salt than the recipe calls for, great with rice instead of pasta…",
|
||
"save": "Save",
|
||
"saving": "Saving…",
|
||
"saved": "Note saved",
|
||
"saveFailed": "Failed to save note"
|
||
},
|
||
"recipeForm": {
|
||
"titleLabel": "Title *",
|
||
"titleRequired": "Title is required",
|
||
"titlePlaceholder": "My amazing recipe",
|
||
"descriptionLabel": "Description",
|
||
"descriptionPlaceholder": "What makes this recipe special…",
|
||
"servings": "Servings",
|
||
"prepMins": "Prep (min)",
|
||
"cookMins": "Cook (min)",
|
||
"difficulty": "Difficulty",
|
||
"visibility": "Visibility",
|
||
"tags": "Tags",
|
||
"tagsHelp": "Press Enter to add · Backspace to remove last · max 20 tags",
|
||
"tagsPlaceholder": "Add tags… (press Enter)",
|
||
"dietaryTags": "Dietary tags",
|
||
"photos": "Photos",
|
||
"ingredients": "Ingredients",
|
||
"amount": "Amount",
|
||
"unit": "Unit",
|
||
"ingredient": "Ingredient",
|
||
"note": "Note",
|
||
"addIngredient": "Add ingredient",
|
||
"setCover": "Set as cover",
|
||
"removePhoto": "Remove",
|
||
"expand": "Expand",
|
||
"steps": "Steps",
|
||
"stepPlaceholder": "Step {n}…",
|
||
"timerSeconds": "Timer (s)",
|
||
"addStep": "Add step",
|
||
"saving": "Saving…",
|
||
"saveChanges": "Save changes",
|
||
"createRecipe": "Create recipe",
|
||
"updateSuccess": "Recipe updated",
|
||
"createSuccess": "Recipe created",
|
||
"saveError": "Failed to save recipe",
|
||
"ingredientsRequired": "Add at least one ingredient",
|
||
"stepsRequired": "Add at least one step",
|
||
"discardChangesTitle": "Discard changes?",
|
||
"discardChangesDescription": "You have unsaved changes. If you leave now, they will be lost.",
|
||
"keepEditing": "Keep editing",
|
||
"discardChanges": "Discard changes"
|
||
},
|
||
"canCook": {
|
||
"title": "What can I cook?",
|
||
"subtitle": "Recipes you can make with your pantry",
|
||
"emptyPantry": "Your pantry is empty",
|
||
"addPantryItems": "Add pantry items",
|
||
"readyToCook": "Ready to cook",
|
||
"almostThere": "Almost there (70–99%)",
|
||
"partialMatches": "Partial matches",
|
||
"noMatches": "No strong matches found",
|
||
"missing": "Missing",
|
||
"ingredientProgress": "{matched}/{total} ingredients",
|
||
"useItUp": "Use it up"
|
||
},
|
||
"mealPlan": {
|
||
"title": "Meal Plan",
|
||
"shoppingLists": "Shopping lists",
|
||
"print": "Print",
|
||
"shareTitle": "Share this week's plan",
|
||
"shareDescription": "Invite household members to view or edit this week's meal plan.",
|
||
"sharedWithYou": "Shared with you",
|
||
"sharedPlanOf": "{name}'s plan",
|
||
"weekOf": "Week of {date}",
|
||
"sharedMealPlanTitle": "{name}'s Meal Plan",
|
||
"batchCookBadge": "Batch cooking",
|
||
"batchCooking": "Batch cooking",
|
||
"pickDishTitle": "Which dish from \"{recipe}\"?",
|
||
"pickDishDescription": "This is a batch-cooking session — pick the specific dish for this slot.",
|
||
"back": "Back",
|
||
"addTo": "Add to {day} – {meal}",
|
||
"searchRecipes": "Search recipes…",
|
||
"servings": "Servings",
|
||
"servingsAbbrev": "{count} srv",
|
||
"difficulty": "Difficulty",
|
||
"noRecipes": "No recipes found",
|
||
"addFailed": "Failed to add",
|
||
"addedToPantry": "{count, plural, one {1 item added to pantry} other {{count} items added to pantry}}",
|
||
"moveToPantryFailed": "Failed to move items to pantry",
|
||
"aisleOther": "Other",
|
||
"listEmptyState": "This list is empty.",
|
||
"checkedCount": "{checked}/{total} checked",
|
||
"searchItemsPlaceholder": "Search items…",
|
||
"sortByCategory": "By category",
|
||
"sortByAlpha": "Alphabetical",
|
||
"sortByUnchecked": "Unchecked first",
|
||
"noSearchResults": "No items match your search.",
|
||
"autoCategorize": "Auto-categorize",
|
||
"autoCategorizeSuccess": "{count, plural, one {1 item categorized} other {{count} items categorized}}",
|
||
"autoCategorizeNoneFound": "Couldn't guess a category for the remaining items",
|
||
"removeItemConfirmTitle": "Remove item?",
|
||
"removeItemConfirmDescription": "Remove \"{name}\" from this list?",
|
||
"moveToPantry": "Move {count} to pantry",
|
||
"listCreated": "List created",
|
||
"days": {
|
||
"mon": "Mon",
|
||
"tue": "Tue",
|
||
"wed": "Wed",
|
||
"thu": "Thu",
|
||
"fri": "Fri",
|
||
"sat": "Sat",
|
||
"sun": "Sun"
|
||
},
|
||
"meals": {
|
||
"breakfast": "Breakfast",
|
||
"lunch": "Lunch",
|
||
"dinner": "Dinner",
|
||
"snack": "Snack"
|
||
},
|
||
"generateWithAi": "Generate with AI",
|
||
"aiModalDescription": "AI will generate a full week of meals and create draft recipes for you.",
|
||
"dietaryPrefs": "Dietary preferences",
|
||
"dietaryPrefsPlaceholder": "e.g. vegetarian, gluten-free, low-carb…",
|
||
"aiPantryNote": "Your pantry items will be considered when available.",
|
||
"generating": "Generating…",
|
||
"generate": "Generate",
|
||
"cancel": "Cancel",
|
||
"aiGenerated": "Meal plan generated!",
|
||
"includePantryItems": "Include pantry items",
|
||
"pantryMode": "Pantry mode — maximize use of what you have",
|
||
"pantryModeDescription": "Prefer meals that use multiple pantry ingredients and minimize extra shopping.",
|
||
"targetNutritionGoals": "Target my nutrition goals",
|
||
"targetNutritionGoalsDescription": "Nudge the AI to aim for your daily calorie and macro targets across the day's meals.",
|
||
"removeFailed": "Failed to remove",
|
||
"generationFailed": "Generation failed",
|
||
"anyDifficulty": "Any",
|
||
"aiPhaseAnalyzing": "Analyzing your preferences…",
|
||
"aiPhasePlanning": "Planning breakfast, lunch & dinner…",
|
||
"aiPhaseSelecting": "Selecting recipes for each day…",
|
||
"aiPhaseBalancing": "Balancing nutrition across the week…",
|
||
"aiPhaseFinalizing": "Finalizing your meal plan…",
|
||
"newList": "New list",
|
||
"newListTitle": "New shopping list",
|
||
"listNameLabel": "Name",
|
||
"listNamePlaceholder": "Weekly groceries",
|
||
"generateFromWeek": "Generate from meal plan week (optional)",
|
||
"generateFromWeekHint": "Picks Monday of the selected week",
|
||
"generateFromThisWeek": "Add to shopping list",
|
||
"generateFromThisWeekHint": "Merges every recipe's ingredients from this week, summing matching ones and flagging what's already in your pantry.",
|
||
"shoppingListWeekName": "Groceries for {week}",
|
||
"listCreateFailed": "Failed to create",
|
||
"listCreating": "Creating…",
|
||
"listCreate": "Create",
|
||
"pickRecipe": "Pick recipe",
|
||
"addEntry": "+ Add",
|
||
"removeEntry": "Remove meal",
|
||
"markCooked": "Mark as cooked",
|
||
"markCookedSuccess": "Marked as cooked",
|
||
"markCookedFailed": "Failed to mark as cooked"
|
||
},
|
||
"pantry": {
|
||
"title": "Pantry",
|
||
"subtitle": "Track what you have on hand",
|
||
"canCook": "What can I cook?",
|
||
"expiringSoonSuggestionsTitle": "Use it up soon",
|
||
"seeAll": "See all",
|
||
"expiringLeftoversTitle": "Leftovers expiring soon",
|
||
"expiringToday": "Eat today",
|
||
"expiringInDays": "{days}d left",
|
||
"itemNamePlaceholder": "Item name",
|
||
"qtyPlaceholder": "Qty",
|
||
"unitPlaceholder": "Unit",
|
||
"add": "Add",
|
||
"addFailed": "Failed to add",
|
||
"removeFailed": "Failed to remove",
|
||
"removeConfirmTitle": "Remove item?",
|
||
"removeConfirmDescription": "Remove \"{name}\" from your pantry?",
|
||
"empty": "No pantry items yet.",
|
||
"emptyDescription": "Add items by hand, or scan a barcode / photo to fill it in fast.",
|
||
"expired": "Expired",
|
||
"expiresInDays": "Expires in {days}d",
|
||
"expiresOn": "Expires {date}",
|
||
"printItemCountSingular": "{count} item",
|
||
"printItemCountPlural": "{count} items",
|
||
"noItems": "No items in pantry.",
|
||
"colItem": "Item",
|
||
"colQuantity": "Quantity",
|
||
"colExpires": "Expires",
|
||
"expiredDaysAgo": "Expired {days}d ago",
|
||
"scan": "Scan",
|
||
"scanTitle": "Add by scan",
|
||
"scanDescription": "Scan a barcode or take a photo to quickly add pantry items.",
|
||
"scanBarcodeOption": "Scan barcode",
|
||
"scanPhotoOption": "Take/upload photo",
|
||
"scanBarcodeTitle": "Scan barcode",
|
||
"scanBarcodeDescription": "Point your camera at a product barcode.",
|
||
"scanConfirmTitle": "Confirm item",
|
||
"scanConfirmDescription": "Review and edit before adding to your pantry.",
|
||
"scanAnalyzingTitle": "Analyzing photo",
|
||
"scanAnalyzingDescription": "Identifying items in your photo…",
|
||
"scanBack": "Back",
|
||
"scanAddToPantry": "Add to pantry",
|
||
"scanAdded": "Added to pantry",
|
||
"scanLookupFailed": "Barcode lookup failed",
|
||
"scanNotFound": "Product not found. Try a photo scan instead.",
|
||
"scanPhotoFailed": "Photo scan failed",
|
||
"scanNoItemsFound": "No items recognized in this photo",
|
||
"cameraError": "Couldn't access the camera"
|
||
},
|
||
"feed": {
|
||
"title": "Feed",
|
||
"followEmpty": "Follow chefs to see their recipes here.",
|
||
"followEmptyDescription": "Your following feed fills up as soon as you follow a few people.",
|
||
"findPeople": "Find people to follow",
|
||
"noNew": "No new recipes from people you follow.",
|
||
"following": "Following",
|
||
"trending": "Trending",
|
||
"trendingEmpty": "No trending recipes this week.",
|
||
"forYou": "For You",
|
||
"forYouEmpty": "Favorite or rate some recipes to get personalized picks here.",
|
||
"loading": "Loading…",
|
||
"loadMore": "Load more",
|
||
"loadFailed": "Failed to load recipes. Check your connection and try again.",
|
||
"retry": "Retry"
|
||
},
|
||
"shoppingLists": {
|
||
"title": "Shopping Lists",
|
||
"subtitle": "Plan your grocery runs",
|
||
"empty": "No shopping lists yet",
|
||
"emptyDescription": "Generate one from a meal plan, or start one from scratch.",
|
||
"listEmpty": "Empty",
|
||
"generated": "Generated",
|
||
"shareTitle": "Share shopping list",
|
||
"shareDescription": "Invite household members to view or edit this list.",
|
||
"sharedWithYou": "Shared with you",
|
||
"sendToGroceryDelivery": "Send to grocery delivery",
|
||
"copyAsText": "Copy list as text",
|
||
"sendToInstacart": "Send to Instacart",
|
||
"copiedToClipboard": "List copied to clipboard",
|
||
"exportBuildFailed": "Could not build export",
|
||
"instacartNotConfigured": "Instacart isn't configured yet",
|
||
"alreadyInPantry": "Already in pantry",
|
||
"items": "{checked}/{total} items",
|
||
"itemsChecked": "{checked}/{total} items checked",
|
||
"fromMealPlan": " · From meal plan",
|
||
"itemCount": "{count} item",
|
||
"itemCountPlural": "{count} items",
|
||
"addToList": "Add to list",
|
||
"dialogTitle": "Add to shopping list",
|
||
"dialogDescription": "Add the ingredients of <strong>{title}</strong> to a shopping list.",
|
||
"scaledSuffix": "scaled)",
|
||
"loadingLists": "Loading your lists…",
|
||
"modeExisting": "Add to existing list",
|
||
"modeNew": "Create new list",
|
||
"listNamePlaceholder": "List name",
|
||
"ingredientsWillBeAdded": "{count, plural, one {1 ingredient will be added.} other {{count} ingredients will be added.}}",
|
||
"adding": "Adding…",
|
||
"addIngredients": "Add ingredients",
|
||
"addedCount": "{count} ingredients added to list",
|
||
"actionsMenuLabel": "List actions",
|
||
"rename": "Rename",
|
||
"renameListTitle": "Rename list",
|
||
"renameListLabel": "List name",
|
||
"renaming": "Saving…",
|
||
"listRenamed": "List renamed",
|
||
"listRenameFailed": "Failed to rename list",
|
||
"deleteListConfirmTitle": "Delete list?",
|
||
"deleteListConfirmDescription": "This action cannot be undone. The list and all its items will be permanently deleted.",
|
||
"listDeleted": "List deleted",
|
||
"listDeleteFailed": "Failed to delete list",
|
||
"changeCategory": "Change category",
|
||
"deleteItem": "Delete item",
|
||
"aisleOther": "Other",
|
||
"newCategoryPlaceholder": "New category…",
|
||
"addCategory": "Add",
|
||
"categories": {
|
||
"produce": "Produce",
|
||
"dairyEggs": "Dairy & Eggs",
|
||
"meatSeafood": "Meat & Seafood",
|
||
"bakery": "Bakery",
|
||
"frozen": "Frozen",
|
||
"pantry": "Pantry",
|
||
"spicesCondiments": "Spices & Condiments",
|
||
"beverages": "Beverages"
|
||
}
|
||
},
|
||
"collections": {
|
||
"title": "Collections",
|
||
"subtitle": "Curate your favorite recipes into collections",
|
||
"empty": "No collections yet",
|
||
"emptyDescription": "Group your recipes by theme, occasion, or however makes sense to you.",
|
||
"emptyCollection": "No recipes in this collection yet.",
|
||
"public": "Public",
|
||
"recipeCount": "{count} recipe",
|
||
"recipeCountPlural": "{count} recipes",
|
||
"discoverTitle": "Discover",
|
||
"discoverSubtitle": "Trending and recently shared public collections",
|
||
"myCollectionsLink": "My collections",
|
||
"trendingThisWeek": "Trending this week",
|
||
"recentlyAdded": "Recently added",
|
||
"noTrending": "No trending collections yet",
|
||
"noRecent": "No public collections yet",
|
||
"exportPdf": "Export as PDF",
|
||
"shareTitle": "Share collection",
|
||
"shareDescription": "Invite people to view or edit this collection.",
|
||
"new": "New collection",
|
||
"newTitle": "New collection",
|
||
"nameLabel": "Name",
|
||
"namePlaceholder": "Weekend dinners",
|
||
"descriptionLabel": "Description",
|
||
"descriptionPlaceholder": "Optional…",
|
||
"makePublic": "Make public",
|
||
"creating": "Creating…",
|
||
"create": "Create",
|
||
"createFailed": "Failed to create",
|
||
"forking": "Forking…",
|
||
"forkCollection": "Fork collection",
|
||
"forkFailed": "Fork failed"
|
||
},
|
||
"shareDialog": {
|
||
"invite": "Invite",
|
||
"emailPlaceholder": "Email address",
|
||
"owner": "Owner",
|
||
"viewer": "Viewer",
|
||
"editor": "Editor",
|
||
"loadingMembers": "Loading members…",
|
||
"noMembers": "No members yet.",
|
||
"invitationSent": "Invitation sent",
|
||
"alreadyMember": "Already a member",
|
||
"userNotFound": "User not found",
|
||
"inviteFailed": "Could not invite user",
|
||
"loadMembersFailed": "Could not load members",
|
||
"memberRemoved": "Member removed",
|
||
"removeMemberFailed": "Could not remove member",
|
||
"enterEmail": "Enter an email address"
|
||
},
|
||
"social": {
|
||
"followed": "Following",
|
||
"unfollowed": "Unfollowed",
|
||
"commentFailed": "Failed to post comment",
|
||
"deleted": "Deleted",
|
||
"ratingSaved": "Rating saved",
|
||
"collectionCreated": "Collection created",
|
||
"collectionForked": "Collection forked to your library",
|
||
"inviteSent": "Invitation sent",
|
||
"memberRemoved": "Member removed",
|
||
"replyPlaceholder": "Reply…",
|
||
"commentPlaceholder": "Share your thoughts…",
|
||
"commentsTitle": "Comments",
|
||
"noCommentsYet": "No comments yet. Be the first!",
|
||
"deleteCommentTitle": "Delete comment?",
|
||
"deleteCommentDescription": "This action cannot be undone.",
|
||
"blockConfirmTitle": "Block @{username}?",
|
||
"blockConfirmDescription": "They won't be able to follow you or comment on your recipes.",
|
||
"blockConfirmAction": "Block",
|
||
"loadMoreComments": "Load more comments",
|
||
"loadingMoreComments": "Loading…",
|
||
"postButton": "Post",
|
||
"postingButton": "Posting…",
|
||
"replyButton": "Reply",
|
||
"reportButton": "Report",
|
||
"ratingFailed": "Failed to rate",
|
||
"cookedItPrompt": "Cooked it? Rate it and share a photo",
|
||
"reviewTextPlaceholder": "How did it turn out?",
|
||
"reviewPhotoAdd": "Add photo",
|
||
"reviewPhotoUploading": "Uploading…",
|
||
"reviewPhotoFailed": "Failed to upload photo",
|
||
"reviewSubmit": "Post review",
|
||
"reviewSubmitting": "Posting…",
|
||
"reviewsTitle": "{count, plural, one {# review} other {# reviews}}",
|
||
"justNow": "just now",
|
||
"minutesAgo": "{mins}m ago",
|
||
"hoursAgo": "{hours}h ago",
|
||
"daysAgo": "{days}d ago",
|
||
"signInToReact": "Sign in to react to comments",
|
||
"reactionFailed": "Failed to update reaction",
|
||
"addReaction": "Add {type} reaction",
|
||
"removeReaction": "Remove {type} reaction",
|
||
"favoriteAdd": "Save recipe",
|
||
"favoriteRemove": "Unsave recipe"
|
||
},
|
||
"cookingMode": {
|
||
"cooking": "Cooking",
|
||
"stepOf": "Step {current} of {total}",
|
||
"batchPrepLabel": "Prep",
|
||
"ingredients": "Ingredients",
|
||
"startTimer": "Start timer",
|
||
"timerDone": "Done",
|
||
"pause": "Pause",
|
||
"reset": "Reset",
|
||
"previous": "Previous",
|
||
"next": "Next",
|
||
"finish": "Done!",
|
||
"voiceNotSupported": "Voice not supported in this browser",
|
||
"voiceError": "Voice error — try again",
|
||
"enableVoice": "Enable voice control",
|
||
"stopVoice": "Stop voice",
|
||
"toggleIngredients": "Toggle ingredients",
|
||
"pageTitle": "Cooking: {title}",
|
||
"pageTitleFallback": "Cooking Mode",
|
||
"shortcutsTitle": "Shortcuts & commands",
|
||
"keyboardSection": "Keyboard",
|
||
"voiceSection": "Voice commands",
|
||
"enableMicFirst": "Enable voice via the mic button first.",
|
||
"stepRepeatPrefix": "Step {n}: ",
|
||
"shortcuts": {
|
||
"nextStep": "Next step",
|
||
"prevStep": "Previous step",
|
||
"startTimer": "Start timer",
|
||
"toggleHelp": "Toggle this panel",
|
||
"exitMode": "Exit cook mode"
|
||
},
|
||
"voiceLabels": {
|
||
"nextCmd": "next / continue",
|
||
"prevCmd": "previous / back",
|
||
"timerCmd": "timer / start",
|
||
"stopCmd": "stop / pause",
|
||
"resetCmd": "reset",
|
||
"repeatCmd": "repeat / again",
|
||
"nextLabel": "Next step",
|
||
"prevLabel": "Previous step",
|
||
"timerLabel": "Start timer",
|
||
"stopLabel": "Pause timer",
|
||
"resetLabel": "Reset timer",
|
||
"repeatLabel": "Re-read step"
|
||
}
|
||
},
|
||
"settingsForm": {
|
||
"profile": "Profile",
|
||
"displayName": "Display name",
|
||
"email": "Email",
|
||
"emailReadOnly": "Email cannot be changed here.",
|
||
"saving": "Saving…",
|
||
"title": "Settings",
|
||
"subtitle": "Manage your account and preferences",
|
||
"language": "Language",
|
||
"languageDescription": "Choose your preferred language for the app and AI-generated content.",
|
||
"changeEmail": "Change email",
|
||
"newEmail": "New email address",
|
||
"changeEmailDescription": "A verification link will be sent to your new address before it takes effect.",
|
||
"sendVerification": "Send verification",
|
||
"sendingVerification": "Sending…",
|
||
"emailChangeSent": "Verification email sent. Check your inbox.",
|
||
"emailChangeFailed": "Failed to send verification email.",
|
||
"changePassword": "Change password",
|
||
"currentPassword": "Current password",
|
||
"newPassword": "New password",
|
||
"confirmPassword": "Confirm new password",
|
||
"passwordMismatch": "Passwords don't match.",
|
||
"changingPassword": "Changing…",
|
||
"changePasswordButton": "Change password",
|
||
"passwordChanged": "Password changed successfully.",
|
||
"passwordChangeFailed": "Failed to change password.",
|
||
"downloadData": "Download my data",
|
||
"downloadDataDescription": "Get a JSON export of all the personal data Epicure holds about you — your profile, recipes, activity, and settings.",
|
||
"downloadDataButton": "Download my data",
|
||
"webhookCreateFailed": "Failed to create webhook",
|
||
"webhookDeleteFailed": "Failed to delete webhook",
|
||
"webhookUpdateFailed": "Failed to update webhook",
|
||
"redeliverySuccess": "Redelivery queued",
|
||
"redeliveryFailed": "Failed to redeliver",
|
||
"apiKeyCreateFailed": "Failed to create API key",
|
||
"apiKeyRevokeFailed": "Failed to revoke API key",
|
||
"apiKeyNamePlaceholder": "e.g. My app",
|
||
"apiKeyNameLabel": "Key name",
|
||
"apiKeyCreating": "Creating…",
|
||
"apiKeyCreate": "Create",
|
||
"apiKeyRevealNotice": "Save this key — it will not be shown again.",
|
||
"copy": "Copy",
|
||
"copied": "Copied!",
|
||
"dismiss": "Dismiss",
|
||
"noApiKeys": "No API keys yet.",
|
||
"createdOn": "Created {date}",
|
||
"lastUsedOn": "Last used {date}",
|
||
"neverUsed": "Never used",
|
||
"revoke": "Revoke",
|
||
"webhookUrlPlaceholder": "https://example.com/webhook",
|
||
"webhookAdding": "Adding…",
|
||
"webhookAddButton": "Add webhook",
|
||
"webhookDocsLink": "View webhook docs & Zapier integration →",
|
||
"endpointUrlLabel": "Endpoint URL",
|
||
"eventsLabel": "Events",
|
||
"eventsHint": "Select which events trigger this webhook. Leave all unchecked to receive all events.",
|
||
"secretRevealNotice": "Save this signing secret — it will not be shown again.",
|
||
"secretUsageHint": "Use it to verify the X-Epicure-Signature header on incoming requests.",
|
||
"noWebhooks": "No webhooks yet.",
|
||
"addedOn": "Added {date}",
|
||
"active": "Active",
|
||
"inactive": "Inactive",
|
||
"allEvents": "All events",
|
||
"deliveries": "Deliveries",
|
||
"disable": "Disable",
|
||
"enable": "Enable",
|
||
"noDeliveriesYet": "No deliveries yet.",
|
||
"modelDefaultPlaceholder": "Default",
|
||
"modelNamePlaceholder": "e.g. llama3.2",
|
||
"copyFailed": "Failed to copy to clipboard",
|
||
"byokSaved": "{provider} key saved",
|
||
"byokSaveFailed": "Failed to save key",
|
||
"byokRemoved": "{provider} key removed",
|
||
"byokRemoveFailed": "Failed to remove key",
|
||
"byokConfigured": "Configured",
|
||
"byokOllamaHint": "Set via OLLAMA_BASE_URL env var",
|
||
"byokSaving": "Saving…",
|
||
"byokSave": "Save",
|
||
"byokFooter": "Your keys are encrypted at rest. When set, they override the app's default keys for your account.",
|
||
"modelSaved": "Model preferences saved",
|
||
"modelSaveFailed": "Failed to save",
|
||
"useCaseText": "Text generation",
|
||
"useCaseTextDesc": "Recipe generation, variations, translations, adapt",
|
||
"useCaseVision": "Vision / photo import",
|
||
"useCaseVisionDesc": "Dish recognition, recipe import from photo",
|
||
"useCaseMealPlan": "Meal planning",
|
||
"useCaseMealPlanDesc": "Weekly meal plan generation",
|
||
"providerLabel": "Provider",
|
||
"modelLabel": "Model",
|
||
"defaultAuto": "Default (auto)",
|
||
"modelDefault": "Default",
|
||
"modelSaving": "Saving…",
|
||
"saveModelPrefs": "Save model preferences",
|
||
"userUpdated": "User updated successfully",
|
||
"userUpdateFailed": "Failed to save",
|
||
"adminSettingsSaved": "Settings saved",
|
||
"adminSettingsFailed": "Failed to save settings",
|
||
"nutritionGoalsSaved": "Nutrition goals saved",
|
||
"bio": "Bio",
|
||
"publicBio": "Public bio",
|
||
"publicBioDescription": "Shown on your public profile.",
|
||
"publicBioPlaceholder": "Tell other cooks about yourself…",
|
||
"privateBio": "AI context (private)",
|
||
"privateBioDescription": "Never shown publicly. Injected into AI prompts to personalise suggestions — add your dietary preferences, kitchen equipment, cooking skill level, allergies, etc.",
|
||
"privateBioPlaceholder": "e.g. I'm vegetarian, have a stand mixer and an air fryer, intermediate cook, allergic to tree nuts, prefer Mediterranean flavours…",
|
||
"privateAccount": "Private account",
|
||
"privateAccountDescription": "When on, your profile and recipes won't appear in search or discovery (Explore, Trending, For You). People who already follow you keep seeing your recipes."
|
||
},
|
||
"profilePage": {
|
||
"tabRecipes": "Recipes",
|
||
"tabHistory": "Cooking History",
|
||
"tabPhotos": "Photos",
|
||
"statTotalCooked": "Total times cooked",
|
||
"statStreak": "Current streak",
|
||
"statLastCooked": "Last cooked",
|
||
"streakDays": "{count, plural, one {# day} other {# days}}",
|
||
"noneYet": "None yet",
|
||
"recentActivity": "Recent activity",
|
||
"noHistoryYet": "No cooking history yet.",
|
||
"noPhotosYet": "No photos yet.",
|
||
"previous": "Previous",
|
||
"next": "Next",
|
||
"pageOf": "Page {page} of {total}"
|
||
}
|
||
}
|