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:
+1
-1
@@ -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 '';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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`, {
|
||||
|
||||
Reference in New Issue
Block a user