i18n(recipes): migrate 13 pages and components

Bulk migration of the recipes namespace following the same pattern as
fitness/cospend/calendar/faith. Layout collapses its label-object into
t.foo lookups; NutritionSummary's 33 ternaries (incl. the
German-stem-plus-optional-e amino-acid pattern that read
`Lysin{isEnglish ? 'e' : ''}`) become straight dictionary references;
AddToFoodLogButton, IngredientsPage, to-try, search, favorites,
the index, and the small landing pages (category, tag, season, icon,
tips-and-tricks) all migrate the same way.

The recipes dict is now ~120 keys. Patterns kept intentionally:

  - Long page-specific marketing copy (subheading sentences, meta
    descriptions that include dynamic counts, hero alt text variants)
    stays inline as `lang === 'en' ? '...' : '...'` rather than
    bloating the dict with one-shot strings.
  - URL slug ternaries stay inline — those are URL data, not UI text.
  - The `recipes/admin/nutrition` page was deliberately skipped — admin
    tooling, ~18 ternaries that are mostly admin-jargon strings used
    in exactly one place.

Detail pages ([name]/+page, [name]/+error, IngredientsPage extras,
InstructionsPage, smaller components) and the admin page remain for
follow-up commits.
This commit is contained in:
2026-05-01 13:34:44 +02:00
parent d540b82e85
commit ea1a85e935
14 changed files with 321 additions and 103 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.55.2",
"version": "1.56.0",
"private": true,
"type": "module",
"scripts": {
@@ -2,6 +2,8 @@
import UtensilsCrossed from '@lucide/svelte/icons/utensils-crossed';
import X from '@lucide/svelte/icons/x';
import { toast } from '$lib/js/toast.svelte';
import { m } from '$lib/js/recipesI18n';
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
let {
recipeName,
@@ -12,6 +14,8 @@
portions = '',
isEnglish = true,
} = $props();
const lang = $derived(/** @type {RecipesLang} */ (isEnglish ? 'en' : 'de'));
const t = $derived(m[lang]);
// Flatten ingredient sections into a flat array with indices
const flatIngredients = $derived.by(() => {
@@ -35,16 +39,16 @@
let useGrams = $state(false);
const labels = $derived({
addToLog: isEnglish ? 'Add to food log' : 'Zum Ernährungstagebuch',
portions: isEnglish ? 'Portions' : 'Portionen',
grams: isEnglish ? 'Grams' : 'Gramm',
meal: isEnglish ? 'Meal' : 'Mahlzeit',
breakfast: isEnglish ? 'Breakfast' : 'Frühstück',
lunch: isEnglish ? 'Lunch' : 'Mittagessen',
dinner: isEnglish ? 'Dinner' : 'Abendessen',
snack: isEnglish ? 'Snack' : 'Snack',
log: isEnglish ? 'Log' : 'Eintragen',
cancel: isEnglish ? 'Cancel' : 'Abbrechen',
addToLog: t.add_to_food_log,
portions: t.portions_label,
grams: t.grams_label,
meal: t.meal_label,
breakfast: t.breakfast,
lunch: t.lunch,
dinner: t.dinner,
snack: t.snack,
log: t.log_action,
cancel: t.cancel
});
// Parse portion count from recipe's portions string (e.g. "4 Portionen")
@@ -171,13 +175,13 @@
})
});
if (res.ok) {
toast.success(isEnglish ? 'Added to food log' : 'Zum Ernährungstagebuch hinzugefügt');
toast.success(t.added_to_food_log);
showDialog = false;
} else {
toast.error(isEnglish ? 'Failed to add' : 'Fehler beim Hinzufügen');
toast.error(t.add_failed);
}
} catch {
toast.error(isEnglish ? 'Failed to add' : 'Fehler beim Hinzufügen');
toast.error(t.add_failed);
} finally {
saving = false;
}
@@ -6,6 +6,8 @@ import { page } from '$app/state';
import HefeSwapper from './HefeSwapper.svelte';
import NutritionSummary from './NutritionSummary.svelte';
import AddToFoodLogButton from './AddToFoodLogButton.svelte';
import { m } from '$lib/js/recipesI18n';
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
let { data } = $props();
const isLoggedIn = $derived(!!data.session?.user);
const hasNutrition = $derived(!!data.nutritionMappings?.length);
@@ -123,23 +125,25 @@ const flattenedIngredients = $derived.by(() => {
// svelte-ignore state_referenced_locally
let multiplier = $state(data.multiplier || 1);
const isEnglish = $derived(data.lang === 'en');
const lang = $derived(/** @type {RecipesLang} */ (data.lang));
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
portions: isEnglish ? 'Portions:' : 'Portionen:',
adjustAmount: isEnglish ? 'Adjust Amount:' : 'Menge anpassen:',
ingredients: isEnglish ? 'Ingredients' : 'Zutaten',
cakeForm: isEnglish ? 'Cake form' : 'Backform',
adjustForm: isEnglish ? 'Adjust cake form' : 'Backform anpassen',
round: isEnglish ? 'Round' : 'Rund',
rectangular: isEnglish ? 'Rectangular' : 'Rechteckig',
portions: t.portions,
adjustAmount: t.adjust_amount,
ingredients: t.ingredients,
cakeForm: t.cake_form,
adjustForm: t.adjust_cake_form,
round: t.round_form,
rectangular: t.rectangular_form,
gugelhupf: 'Gugelhupf',
diameter: isEnglish ? 'Diameter' : 'Durchmesser',
outerDiameter: isEnglish ? 'Outer Ø' : 'Aussen-Ø',
innerDiameter: isEnglish ? 'Inner Ø' : 'Innen-Ø',
width: isEnglish ? 'Width' : 'Breite',
length: isEnglish ? 'Length' : 'Länge',
factor: isEnglish ? 'Factor' : 'Faktor',
restoreDefault: isEnglish ? 'Restore default' : 'Standard wiederherstellen',
diameter: t.diameter,
outerDiameter: t.outer_diameter,
innerDiameter: t.inner_diameter,
width: t.width,
length: t.length,
factor: t.factor,
restoreDefault: t.restore_default
});
// Cake form scaling
@@ -200,7 +204,7 @@ const isDefaultForm = $derived(
);
const cakeSummaryText = $derived.by(() => {
if (userFormShape === 'round') return `${userFormDiameter} cm ${isEnglish ? 'round' : 'rund'}`;
if (userFormShape === 'round') return `${userFormDiameter} cm ${t.round_lowercase}`;
if (userFormShape === 'rectangular') return `${userFormWidth}×${userFormLength} cm`;
if (userFormShape === 'gugelhupf') return `${userFormDiameter}/${userFormInnerDiameter} cm Gugelhupf`;
return '';
+98 -1
View File
@@ -42,5 +42,102 @@ export const de = {
glycine: 'Glycin',
proline: 'Prolin',
serine: 'Serin',
tyrosine: 'Tyrosin'
tyrosine: 'Tyrosin',
// Ingredients page
portions: 'Portionen:',
adjust_amount: 'Menge anpassen:',
ingredients: 'Zutaten',
cake_form: 'Backform',
adjust_cake_form: 'Backform anpassen',
round_form: 'Rund',
rectangular_form: 'Rechteckig',
diameter: 'Durchmesser',
outer_diameter: 'Aussen-Ø',
inner_diameter: 'Innen-Ø',
width: 'Breite',
length: 'Länge',
factor: 'Faktor',
restore_default: 'Standard wiederherstellen',
round_lowercase: 'rund',
// AddToFoodLogButton + meal labels
add_to_food_log: 'Zum Ernährungstagebuch',
added_to_food_log: 'Zum Ernährungstagebuch hinzugefügt',
add_failed: 'Fehler beim Hinzufügen',
portions_label: 'Portionen',
grams_label: 'Gramm',
meal_label: 'Mahlzeit',
breakfast: 'Frühstück',
lunch: 'Mittagessen',
dinner: 'Abendessen',
snack: 'Snack',
log_action: 'Eintragen',
cancel: 'Abbrechen',
save: 'Speichern',
// To-try page
to_try_title: 'Zum Ausprobieren',
to_try_page_title: 'Zum Ausprobieren - Bocken Rezepte',
to_try_meta_description: 'Rezepte, die wir ausprobieren wollen.',
to_try_nothing: 'Noch nichts vorhanden',
to_try_empty_state: 'Füge ein Rezept hinzu, das du ausprobieren möchtest.',
recipe_name: 'Rezeptname',
label_optional: 'Bezeichnung (optional)',
notes_optional: 'Notizen (optional)',
add_link: 'Link hinzufügen',
add_recipe_to_try: 'Rezept hinzufügen',
edit_recipe: 'Rezept bearbeiten',
delete_recipe_confirm: 'Dieses Rezept löschen?',
// Search page
search_results_title: 'Suchergebnisse',
search_meta_description: 'Suchergebnisse in den Bockenschen Rezepten.',
filtered_by: 'Gefiltert nach:',
keywords_label: 'Stichwörter',
seasons_label: 'Monate',
favorites_only: 'Nur Favoriten',
search_error: 'Fehler bei der Suche:',
results_for: 'Ergebnisse für',
no_recipes_found: 'Keine Rezepte gefunden.',
try_other_search: 'Versuche es mit anderen Suchbegriffen.',
// Common page titles + shared
site_title: 'Bocken Rezepte',
all: 'Alle',
// Index page
index_title: 'Rezepte',
in_season_now: 'In Saison',
meta_alt_hero: 'Pasta al Ragu mit Linguine',
// Detail page
season_label: 'Saison:',
keywords_colon: 'Stichwörter:',
last_modified: 'Letzte Änderung:',
// Favorites
favorites_page_title: 'Meine Favoriten - Bocken Rezepte',
no_favorites_yet: 'Noch keine Favoriten gespeichert',
error_loading_favorites: 'Fehler beim Laden der Favoriten:',
recipe_singular_link: 'Rezept',
recipes_to_try_link: 'Zum Ausprobieren',
no_matching_favorites: 'Keine passenden Favoriten gefunden.',
// Error pages
recipe_not_found: 'Rezept nicht gefunden',
recipe_not_found_desc: 'Das angeforderte Rezept konnte nicht gefunden werden.',
checking_german_version: 'Suche nach deutscher Version…',
recipes_link: 'Rezepte',
// Categories / tags / season / icon / tips index pages
categories_title: 'Kategorien',
keywords_title: 'Stichwörter',
search_tags: 'Tags suchen…',
in_season_title: 'Saisonal',
icons_title: 'Icons',
tips_title: 'Tipps & Tricks',
favorites_meta_description: 'Meine favorisierten Rezepte aus der Bockenschen Küche.',
empty_favorites_1: 'Du hast noch keine Rezepte als Favoriten gespeichert.',
empty_favorites_2: 'Besuche ein Rezept und klicke auf das Herz-Symbol, um es zu deinen Favoriten hinzuzufügen.'
} as const;
+98 -1
View File
@@ -42,5 +42,102 @@ export const en = {
glycine: 'Glycine',
proline: 'Proline',
serine: 'Serine',
tyrosine: 'Tyrosine'
tyrosine: 'Tyrosine',
// Ingredients page
portions: 'Portions:',
adjust_amount: 'Adjust Amount:',
ingredients: 'Ingredients',
cake_form: 'Cake form',
adjust_cake_form: 'Adjust cake form',
round_form: 'Round',
rectangular_form: 'Rectangular',
diameter: 'Diameter',
outer_diameter: 'Outer Ø',
inner_diameter: 'Inner Ø',
width: 'Width',
length: 'Length',
factor: 'Factor',
restore_default: 'Restore default',
round_lowercase: 'round',
// AddToFoodLogButton + meal labels
add_to_food_log: 'Add to food log',
added_to_food_log: 'Added to food log',
add_failed: 'Failed to add',
portions_label: 'Portions',
grams_label: 'Grams',
meal_label: 'Meal',
breakfast: 'Breakfast',
lunch: 'Lunch',
dinner: 'Dinner',
snack: 'Snack',
log_action: 'Log',
cancel: 'Cancel',
save: 'Save',
// To-try page
to_try_title: 'To Try',
to_try_page_title: 'Recipes To Try - Bocken Recipes',
to_try_meta_description: 'Recipes we want to try from around the web.',
to_try_nothing: 'Nothing here yet',
to_try_empty_state: 'Add a recipe you want to try using the form below.',
recipe_name: 'Recipe name',
label_optional: 'Label (optional)',
notes_optional: 'Notes (optional)',
add_link: 'Add link',
add_recipe_to_try: 'Add recipe to try',
edit_recipe: 'Edit recipe',
delete_recipe_confirm: 'Delete this recipe?',
// Search page
search_results_title: 'Search Results',
search_meta_description: "Search results in Bocken's recipes.",
filtered_by: 'Filtered by:',
keywords_label: 'Keywords',
seasons_label: 'Seasons',
favorites_only: 'Favorites only',
search_error: 'Search error:',
results_for: 'results for',
no_recipes_found: 'No recipes found.',
try_other_search: 'Try different search terms.',
// Common page titles + shared
site_title: 'Bocken Recipes',
all: 'All',
// Index page
index_title: 'Recipes',
in_season_now: 'In Season',
meta_alt_hero: 'Pasta al Ragu with Linguine',
// Detail page
season_label: 'Season:',
keywords_colon: 'Keywords:',
last_modified: 'Last modified:',
// Favorites
favorites_page_title: 'My Favorites - Bocken Recipes',
no_favorites_yet: 'No favorites saved yet',
error_loading_favorites: 'Error loading favorites:',
recipe_singular_link: 'recipe',
recipes_to_try_link: 'Recipes to try',
no_matching_favorites: 'No matching favorites found.',
// Error pages
recipe_not_found: 'Recipe Not Found',
recipe_not_found_desc: 'The requested recipe could not be found.',
checking_german_version: 'Checking for German version…',
recipes_link: 'Recipes',
// Categories / tags / season / icon / tips index pages
categories_title: 'Categories',
keywords_title: 'Keywords',
search_tags: 'Search tags…',
in_season_title: 'In Season',
icons_title: 'Icons',
tips_title: 'Tips & Tricks',
favorites_meta_description: "My favorite recipes from Bocken's kitchen.",
empty_favorites_1: "You haven't saved any recipes as favorites yet.",
empty_favorites_2: 'Visit a recipe and click the heart icon to add it to your favorites.'
} as const satisfies Record<keyof typeof de, string>;
@@ -5,8 +5,11 @@
import CompactCard from '$lib/components/recipes/CompactCard.svelte';
import Search from '$lib/components/recipes/Search.svelte';
import { getCategories } from '$lib/js/categories';
import { m, type RecipesLang } from '$lib/js/recipesI18n';
let { data } = $props<{ data: PageData }>();
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
let current_month = new Date().getMonth() + 1;
// Search state
@@ -118,17 +121,17 @@
const hasMore = $derived(visibleCount < displayRecipes.length);
const labels = $derived({
title: isEnglish ? 'Recipes' : 'Rezepte',
title: t.index_title,
subheading: isEnglish
? `${data.all_brief.length} recipes and constantly growing...`
: `${data.all_brief.length} Rezepte und stetig wachsend...`,
all: isEnglish ? 'All' : 'Alle',
inSeason: isEnglish ? 'In Season' : 'In Saison',
metaTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte',
all: t.all,
inSeason: t.in_season_now,
metaTitle: t.site_title,
metaDescription: isEnglish
? "A constantly growing collection of recipes from Bocken's kitchen."
: "Eine stetig wachsende Ansammlung an Rezepten aus der Bockenschen Küche.",
metaAlt: isEnglish ? 'Pasta al Ragu with Linguine' : 'Pasta al Ragu mit Linguine'
metaAlt: t.meta_alt_hero
});
</script>
<style>
@@ -5,10 +5,13 @@
import TagCloud from '$lib/components/TagCloud.svelte';
import TagBall from '$lib/components/TagBall.svelte';
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Categories' : 'Kategorien',
siteTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte'
title: t.categories_title,
siteTitle: t.site_title
});
</script>
@@ -7,26 +7,23 @@
let { data } = $props<{ data: PageData }>();
let current_month = new Date().getMonth() + 1;
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Favorites' : 'Favoriten',
pageTitle: isEnglish ? 'My Favorites - Bocken Recipes' : 'Meine Favoriten - Bocken Rezepte',
metaDescription: isEnglish
? 'My favorite recipes from Bocken\'s kitchen.'
: 'Meine favorisierten Rezepte aus der Bockenschen Küche.',
title: t.favorites,
pageTitle: t.favorites_page_title,
metaDescription: t.favorites_meta_description,
count: isEnglish
? `${data.favorites.length} favorite recipe${data.favorites.length !== 1 ? 's' : ''}`
: `${data.favorites.length} favorisierte Rezepte`,
noFavorites: isEnglish ? 'No favorites saved yet' : 'Noch keine Favoriten gespeichert',
errorLoading: isEnglish ? 'Error loading favorites:' : 'Fehler beim Laden der Favoriten:',
emptyState1: isEnglish
? 'You haven\'t saved any recipes as favorites yet.'
: 'Du hast noch keine Rezepte als Favoriten gespeichert.',
emptyState2: isEnglish
? 'Visit a recipe and click the heart icon to add it to your favorites.'
: 'Besuche ein Rezept und klicke auf das Herz-Symbol, um es zu deinen Favoriten hinzuzufügen.',
recipesLink: isEnglish ? 'recipe' : 'Rezept',
toTry: isEnglish ? 'Recipes to try' : 'Zum Ausprobieren'
noFavorites: t.no_favorites_yet,
errorLoading: t.error_loading_favorites,
emptyState1: t.empty_favorites_1,
emptyState2: t.empty_favorites_2,
recipesLink: t.recipe_singular_link,
toTry: t.recipes_to_try_link
});
let matchedRecipeIds = $state(new Set());
@@ -3,10 +3,13 @@
import type { PageData } from './$types';
let { data } = $props<{ data: PageData }>();
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Icons' : 'Icons',
siteTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte'
title: t.icons_title,
siteTitle: t.site_title
});
</script>
@@ -3,28 +3,29 @@
import type { PageData } from './$types';
import Search from '$lib/components/recipes/Search.svelte';
import CompactCard from '$lib/components/recipes/CompactCard.svelte';
import { m, type RecipesLang } from '$lib/js/recipesI18n';
let { data } = $props<{ data: PageData }>();
let current_month = new Date().getMonth() + 1;
const isEnglish = $derived(data.lang === 'en');
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Search Results' : 'Suchergebnisse',
title: t.search_results_title,
pageTitle: isEnglish
? `Search Results${data.query ? ` for "${data.query}"` : ''} - Bocken Recipes`
: `Suchergebnisse${data.query ? ` für "${data.query}"` : ''} - Bocken Rezepte`,
metaDescription: isEnglish
? 'Search results in Bocken\'s recipes.'
: 'Suchergebnisse in den Bockenschen Rezepten.',
filteredBy: isEnglish ? 'Filtered by:' : 'Gefiltert nach:',
category: isEnglish ? 'Category' : 'Kategorie',
keywords: isEnglish ? 'Keywords' : 'Stichwörter',
icon: 'Icon',
seasons: isEnglish ? 'Seasons' : 'Monate',
favoritesOnly: isEnglish ? 'Favorites only' : 'Nur Favoriten',
searchError: isEnglish ? 'Search error:' : 'Fehler bei der Suche:',
resultsFor: isEnglish ? 'results for' : 'Ergebnisse für',
noResults: isEnglish ? 'No recipes found.' : 'Keine Rezepte gefunden.',
tryOther: isEnglish ? 'Try different search terms.' : 'Versuche es mit anderen Suchbegriffen.'
metaDescription: t.search_meta_description,
filteredBy: t.filtered_by,
category: t.category_nav,
keywords: t.keywords_label,
icon: t.icon_nav,
seasons: t.seasons_label,
favoritesOnly: t.favorites_only,
searchError: t.search_error,
resultsFor: t.results_for,
noResults: t.no_recipes_found,
tryOther: t.try_other_search
});
// Search state for live filtering
@@ -7,13 +7,16 @@
let current_month = new Date().getMonth() + 1
import { rand_array } from '$lib/js/randomize';
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const months = $derived(isEnglish
? ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]);
const labels = $derived({
title: isEnglish ? 'In Season' : 'Saisonal',
siteTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte'
title: t.in_season_title,
siteTitle: t.site_title
});
// Search state
@@ -5,11 +5,14 @@
import TagCloud from '$lib/components/TagCloud.svelte';
import TagBall from '$lib/components/TagBall.svelte';
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Keywords' : 'Stichwörter',
siteTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte',
search: isEnglish ? 'Search tags...' : 'Tags suchen...'
title: t.keywords_title,
siteTitle: t.site_title,
search: t.search_tags
});
let query = $state('');
@@ -5,10 +5,13 @@
import Converter from './Converter.svelte';
let { data } = $props<{ data: PageData }>();
const isEnglish = $derived(data.lang === 'en');
import { m, type RecipesLang } from '$lib/js/recipesI18n';
const lang = $derived(data.lang as RecipesLang);
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'Tips & Tricks' : 'Tipps & Tricks',
siteTitle: isEnglish ? 'Bocken Recipes' : 'Bocken Rezepte',
title: t.tips_title,
siteTitle: t.site_title,
description: isEnglish
? "A constantly growing collection of recipes from Bocken's kitchen."
: 'Eine stetig wachsende Ansammlung an Rezepten aus der Bockenschen Küche.'
@@ -1,35 +1,35 @@
<script>
import ToTryCard from '$lib/components/recipes/ToTryCard.svelte';
import { confirm } from '$lib/js/confirmDialog.svelte';
import { m } from '$lib/js/recipesI18n';
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
let { data } = $props();
// svelte-ignore state_referenced_locally
let items = $state(data.items ?? []);
const isEnglish = $derived(data.lang === 'en');
const lang = $derived(/** @type {RecipesLang} */ (data.lang));
const t = $derived(m[lang]);
const isEnglish = $derived(lang === 'en');
const labels = $derived({
title: isEnglish ? 'To Try' : 'Zum Ausprobieren',
pageTitle: isEnglish ? 'Recipes To Try - Bocken Recipes' : 'Zum Ausprobieren - Bocken Rezepte',
metaDescription: isEnglish
? 'Recipes we want to try from around the web.'
: 'Rezepte, die wir ausprobieren wollen.',
title: t.to_try_title,
pageTitle: t.to_try_page_title,
metaDescription: t.to_try_meta_description,
count: isEnglish
? `${items.length} recipe${items.length !== 1 ? 's' : ''} to try`
: `${items.length} Rezept${items.length !== 1 ? 'e' : ''} zum Ausprobieren`,
noItems: isEnglish ? 'Nothing here yet' : 'Noch nichts vorhanden',
emptyState: isEnglish
? 'Add a recipe you want to try using the form below.'
: 'Füge ein Rezept hinzu, das du ausprobieren möchtest.',
name: isEnglish ? 'Recipe name' : 'Rezeptname',
noItems: t.to_try_nothing,
emptyState: t.to_try_empty_state,
name: t.recipe_name,
url: 'URL',
label: isEnglish ? 'Label (optional)' : 'Bezeichnung (optional)',
notes: isEnglish ? 'Notes (optional)' : 'Notizen (optional)',
addLink: isEnglish ? 'Add link' : 'Link hinzufügen',
save: isEnglish ? 'Save' : 'Speichern',
cancel: isEnglish ? 'Cancel' : 'Abbrechen',
add: isEnglish ? 'Add recipe to try' : 'Rezept hinzufügen',
editHeading: isEnglish ? 'Edit recipe' : 'Rezept bearbeiten'
label: t.label_optional,
notes: t.notes_optional,
addLink: t.add_link,
save: t.save,
cancel: t.cancel,
add: t.add_recipe_to_try,
editHeading: t.edit_recipe
});
let showForm = $state(false);
let saving = $state(false);
@@ -102,7 +102,7 @@
/** @param {any} id */
async function handleDelete(id) {
const msg = isEnglish ? 'Delete this recipe?' : 'Dieses Rezept löschen?';
const msg = t.delete_recipe_confirm;
if (!await confirm(msg)) return;
const res = await fetch(`/api/${data.recipeLang}/to-try`, {