i18n(recipes): finish remaining ternaries across components and pages
Migrate FavoritesFilter, IconFilter, TagFilter, FilterPanel, HefeSwapper and the offline-shell, season/[month], icon/[icon], favorites, search, tips-and-tricks, and index pages to use the recipes i18n dictionary. Add corresponding keys for filter toggles, filter placeholders, yeast toggle title, recipes-growing suffix, search "for" preposition, and favorites count labels. Strip unused isEnglish derivations from layout, tag, and category landing pages. Bump site version to 1.56.1.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import TagChip from '$lib/components/recipes/TagChip.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
categories = [],
|
||||
@@ -9,9 +11,9 @@
|
||||
useAndLogic = true
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const label = $derived(isEnglish ? 'Category' : 'Kategorie');
|
||||
const selectLabel = $derived(isEnglish ? 'Select category...' : 'Kategorie auswählen...');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = $derived(t.category_nav);
|
||||
const selectLabel = $derived(t.select_category_placeholder);
|
||||
|
||||
// Convert selected to array for OR mode, keep as single value for AND mode
|
||||
const selectedArray = $derived(
|
||||
|
||||
@@ -74,7 +74,12 @@ const t: Record<string, Record<string, string>> = {
|
||||
moveReferenceDownAria: 'Referenz nach unten verschieben',
|
||||
removeReferenceAria: 'Referenz entfernen',
|
||||
moveListUpAria: 'Liste nach oben verschieben',
|
||||
moveListDownAria: 'Liste nach unten verschieben'
|
||||
moveListDownAria: 'Liste nach unten verschieben',
|
||||
notSet: 'Nicht gesetzt',
|
||||
duration: 'Dauer',
|
||||
temperature: 'Temperatur',
|
||||
mode: 'Modus',
|
||||
customModePlaceholder: 'oder eigenen Modus eingeben…'
|
||||
},
|
||||
en: {
|
||||
preparation: 'Preparation:',
|
||||
@@ -109,7 +114,12 @@ const t: Record<string, Record<string, string>> = {
|
||||
moveReferenceDownAria: 'Move reference down',
|
||||
removeReferenceAria: 'Remove reference',
|
||||
moveListUpAria: 'Move list up',
|
||||
moveListDownAria: 'Move list down'
|
||||
moveListDownAria: 'Move list down',
|
||||
notSet: 'Not set',
|
||||
duration: 'Duration',
|
||||
temperature: 'Temperature',
|
||||
mode: 'Mode',
|
||||
customModePlaceholder: 'or enter custom mode…'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1017,7 +1027,7 @@ h3{
|
||||
{#if add_info.baking.mode}<span class="chip mode">{add_info.baking.mode}</span>{/if}
|
||||
</span>
|
||||
{:else if !bakingExpanded}
|
||||
<span class="baking-summary muted">{lang === 'de' ? 'Nicht gesetzt' : 'Not set'}</span>
|
||||
<span class="baking-summary muted">{t[lang].notSet}</span>
|
||||
{/if}
|
||||
<svg class="chevron" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
|
||||
<path d="M7 10l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
@@ -1027,7 +1037,7 @@ h3{
|
||||
{#if bakingExpanded}
|
||||
<div id="baking-fields-{lang}" class="baking-form">
|
||||
<div class="baking-field">
|
||||
<label for="baking-length-{lang}">{lang === 'de' ? 'Dauer' : 'Duration'}</label>
|
||||
<label for="baking-length-{lang}">{t[lang].duration}</label>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
id="baking-length-{lang}"
|
||||
@@ -1041,7 +1051,7 @@ h3{
|
||||
</div>
|
||||
</div>
|
||||
<div class="baking-field">
|
||||
<label for="baking-temp-{lang}">{lang === 'de' ? 'Temperatur' : 'Temperature'}</label>
|
||||
<label for="baking-temp-{lang}">{t[lang].temperature}</label>
|
||||
<div class="input-wrap">
|
||||
<input
|
||||
id="baking-temp-{lang}"
|
||||
@@ -1055,7 +1065,7 @@ h3{
|
||||
</div>
|
||||
</div>
|
||||
<div class="baking-field mode-field">
|
||||
<span class="mode-label">{lang === 'de' ? 'Modus' : 'Mode'}</span>
|
||||
<span class="mode-label">{t[lang].mode}</span>
|
||||
<div class="mode-chips">
|
||||
{#each BAKING_MODES[lang] as mode}
|
||||
<button
|
||||
@@ -1070,7 +1080,7 @@ h3{
|
||||
type="text"
|
||||
class="mode-custom"
|
||||
bind:value={add_info.baking.mode}
|
||||
placeholder={lang === 'de' ? 'oder eigenen Modus eingeben…' : 'or enter custom mode…'}
|
||||
placeholder={t[lang].customModePlaceholder}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import Toggle from '$lib/components/Toggle.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
enabled = false,
|
||||
@@ -8,8 +10,8 @@
|
||||
lang = 'de'
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const label = $derived(isEnglish ? 'Favorites' : 'Favoriten');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = $derived(t.favorites);
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let checked = $state(enabled);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import SeasonFilter from './SeasonFilter.svelte';
|
||||
import FavoritesFilter from './FavoritesFilter.svelte';
|
||||
import LogicModeToggle from './LogicModeToggle.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
availableCategories = [],
|
||||
@@ -27,6 +29,7 @@
|
||||
onLogicModeToggle = () => {}
|
||||
} = $props();
|
||||
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const months = $derived(isEnglish
|
||||
? ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
||||
@@ -132,7 +135,7 @@
|
||||
|
||||
<div class="filter-wrapper">
|
||||
<button class="toggle-button" onclick={toggleFilters} type="button">
|
||||
<span>{filtersOpen ? (isEnglish ? 'Hide Filters' : 'Filter ausblenden') : (isEnglish ? 'Show Filters' : 'Filter einblenden')}</span>
|
||||
<span>{filtersOpen ? t.hide_filters : t.show_filters}</span>
|
||||
<span class="arrow" class:open={filtersOpen}>▼</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
import { enhance } from '$app/forms';
|
||||
import { page } from '$app/state';
|
||||
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let { item, multiplier = 1, yeastId = 0, lang = 'de' } = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const toggleTitle = $derived(isEnglish
|
||||
? 'Switch between fresh yeast and dry yeast'
|
||||
: 'Zwischen Frischhefe und Trockenhefe wechseln');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const toggleTitle = $derived(t.yeast_toggle_title);
|
||||
|
||||
// Get all current URL parameters to preserve state
|
||||
const currentParams = $derived(browser ? new URLSearchParams(window.location.search) : page.url.searchParams);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import TagChip from '$lib/components/recipes/TagChip.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
availableIcons = [],
|
||||
@@ -9,9 +11,9 @@
|
||||
useAndLogic = true
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = 'Icon';
|
||||
const selectLabel = $derived(isEnglish ? 'Select icon...' : 'Icon auswählen...');
|
||||
const selectLabel = $derived(t.select_icon_placeholder);
|
||||
|
||||
// Convert selected to array for OR mode, keep as single value for AND mode
|
||||
const selectedArray = $derived(
|
||||
|
||||
@@ -5,6 +5,8 @@ import Croissant from '@lucide/svelte/icons/croissant';
|
||||
import Flame from '@lucide/svelte/icons/flame';
|
||||
import CookingPot from '@lucide/svelte/icons/cooking-pot';
|
||||
import UtensilsCrossed from '@lucide/svelte/icons/utensils-crossed';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
let { data } = $props();
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
@@ -99,16 +101,18 @@ const flattenedInstructions = $derived.by(() => {
|
||||
return flattenInstructionReferences(data.instructions, lang);
|
||||
});
|
||||
|
||||
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({
|
||||
preparation: isEnglish ? 'Preparation:' : 'Vorbereitung:',
|
||||
bulkFermentation: isEnglish ? 'Bulk Fermentation:' : 'Stockgare:',
|
||||
finalProof: isEnglish ? 'Final Proof:' : 'Stückgare:',
|
||||
baking: isEnglish ? 'Baking:' : 'Backen:',
|
||||
cooking: isEnglish ? 'Cooking:' : 'Kochen:',
|
||||
onThePlate: isEnglish ? 'On the Plate:' : 'Auf dem Teller:',
|
||||
instructions: isEnglish ? 'Instructions' : 'Zubereitung',
|
||||
at: isEnglish ? 'at' : 'bei'
|
||||
preparation: t.preparation_section,
|
||||
bulkFermentation: t.bulk_fermentation,
|
||||
finalProof: t.final_proof,
|
||||
baking: t.baking_section,
|
||||
cooking: t.cooking_section,
|
||||
onThePlate: t.on_the_plate,
|
||||
instructions: t.instructions_label,
|
||||
at: t.at_temp
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script>
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
useAndLogic = true,
|
||||
@@ -6,10 +8,10 @@
|
||||
lang = 'de'
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const label = $derived(isEnglish ? 'Filter Mode' : 'Filter-Modus');
|
||||
const andLabel = $derived(isEnglish ? 'AND' : 'UND');
|
||||
const orLabel = $derived(isEnglish ? 'OR' : 'ODER');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = $derived(t.filter_mode);
|
||||
const andLabel = $derived(t.and_label);
|
||||
const orLabel = $derived(t.or_label);
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let checked = $state(useAndLogic);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import { browser } from '$app/environment';
|
||||
import FilterPanel from './FilterPanel.svelte';
|
||||
import { getCategories } from '$lib/js/categories';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
// Filter props for different contexts
|
||||
let {
|
||||
@@ -20,12 +22,13 @@
|
||||
// Generate categories internally based on language
|
||||
const categories = $derived(getCategories(lang));
|
||||
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const searchResultsUrl = $derived(isEnglish ? '/recipes/search' : '/rezepte/search');
|
||||
const labels = $derived({
|
||||
placeholder: isEnglish ? 'Search...' : 'Suche...',
|
||||
searchTitle: isEnglish ? 'Search' : 'Suchen',
|
||||
clearTitle: isEnglish ? 'Clear search' : 'Sucheintrag löschen'
|
||||
placeholder: t.search_placeholder_short,
|
||||
searchTitle: t.search_title,
|
||||
clearTitle: t.clear_search_title
|
||||
});
|
||||
|
||||
let searchQuery = $state('');
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import TagChip from '$lib/components/recipes/TagChip.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
selectedSeasons = [],
|
||||
@@ -8,9 +10,9 @@
|
||||
months = []
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const label = $derived(isEnglish ? 'Season' : 'Saison');
|
||||
const selectLabel = $derived(isEnglish ? 'Select season...' : 'Saison auswählen...');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = $derived(t.season_nav);
|
||||
const selectLabel = $derived(t.select_season_placeholder);
|
||||
|
||||
let inputValue = $state('');
|
||||
let dropdownOpen = $state(false);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import TagChip from '$lib/components/recipes/TagChip.svelte';
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
/** @typedef {import('$lib/js/recipesI18n').RecipesLang} RecipesLang */
|
||||
|
||||
let {
|
||||
availableTags = [],
|
||||
@@ -8,9 +10,9 @@
|
||||
lang = 'de'
|
||||
} = $props();
|
||||
|
||||
const isEnglish = $derived(lang === 'en');
|
||||
const t = $derived(m[/** @type {RecipesLang} */ (lang)]);
|
||||
const label = 'Tags';
|
||||
const addTagLabel = $derived(isEnglish ? 'Type or select tag...' : 'Tag eingeben oder auswählen...');
|
||||
const addTagLabel = $derived(t.add_tag_placeholder);
|
||||
|
||||
// Filter out already selected tags
|
||||
const unselectedTags = $derived(availableTags.filter(t => !selectedTags.includes(t)));
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script>
|
||||
import { m } from '$lib/js/recipesI18n';
|
||||
let { item, ondelete, onedit, isEnglish = false } = $props();
|
||||
const t = $derived(isEnglish ? m.en : m.de);
|
||||
|
||||
/** @param {string} url */
|
||||
function getDomain(url) {
|
||||
@@ -142,8 +144,8 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="accent"></div>
|
||||
<button class="card-btn edit-btn" onclick={() => onedit(item)} aria-label={isEnglish ? 'Edit' : 'Bearbeiten'}>✎</button>
|
||||
<button class="card-btn delete-btn" onclick={() => ondelete(item._id)} aria-label={isEnglish ? 'Delete' : 'Löschen'}>✕</button>
|
||||
<button class="card-btn edit-btn" onclick={() => onedit(item)} aria-label={t.edit}>✎</button>
|
||||
<button class="card-btn delete-btn" onclick={() => ondelete(item._id)} aria-label={t.delete}>✕</button>
|
||||
<div class="body">
|
||||
<p class="name">{item.name}</p>
|
||||
{#if item.links?.length}
|
||||
|
||||
@@ -139,5 +139,80 @@ export const de = {
|
||||
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.'
|
||||
empty_favorites_2: 'Besuche ein Rezept und klicke auf das Herz-Symbol, um es zu deinen Favoriten hinzuzufügen.',
|
||||
|
||||
// Filters
|
||||
filter_mode: 'Filter-Modus',
|
||||
and_label: 'UND',
|
||||
or_label: 'ODER',
|
||||
select_category_placeholder: 'Kategorie auswählen…',
|
||||
select_season_placeholder: 'Saison auswählen…',
|
||||
|
||||
// Search component
|
||||
search_placeholder_short: 'Suche…',
|
||||
search_title: 'Suchen',
|
||||
clear_search_title: 'Sucheintrag löschen',
|
||||
|
||||
// Tag / Category landing
|
||||
recipes_with_keyword: 'Rezepte mit Stichwort',
|
||||
recipes_in_category: 'Rezepte in Kategorie',
|
||||
|
||||
// Card actions
|
||||
edit: 'Bearbeiten',
|
||||
delete: 'Löschen',
|
||||
|
||||
// Administration page
|
||||
administration_title: 'Administration',
|
||||
untranslated_recipes: 'Unübersetzte Rezepte',
|
||||
alt_text_generator: 'Alt-Text Generator',
|
||||
image_colors: 'Bildfarben',
|
||||
nutrition_mappings: 'Nährwert-Zuordnungen',
|
||||
|
||||
// Recipe detail page (long site title variant)
|
||||
site_title_long: "Bocken'sche Rezepte",
|
||||
|
||||
// InstructionsPage section labels
|
||||
preparation_section: 'Vorbereitung:',
|
||||
bulk_fermentation: 'Stockgare:',
|
||||
final_proof: 'Stückgare:',
|
||||
baking_section: 'Backen:',
|
||||
cooking_section: 'Kochen:',
|
||||
on_the_plate: 'Auf dem Teller:',
|
||||
instructions_label: 'Zubereitung',
|
||||
at_temp: 'bei',
|
||||
|
||||
// CreateStepList baking
|
||||
not_set: 'Nicht gesetzt',
|
||||
duration: 'Dauer',
|
||||
temperature: 'Temperatur',
|
||||
mode_label: 'Modus',
|
||||
custom_mode_placeholder: 'oder eigenen Modus eingeben…',
|
||||
|
||||
// Administration page descriptions
|
||||
administration_description: 'Rezepte und Inhalte verwalten',
|
||||
untranslated_description: 'Rezepte ansehen und verwalten, die übersetzt werden müssen',
|
||||
alt_text_description: 'Alternativtext für Rezeptbilder mit KI generieren',
|
||||
image_colors_description: 'Dominante Farben aus Rezeptbildern für Ladeplatzhalter extrahieren',
|
||||
nutrition_mappings_description: 'Kalorien- und Nährwertdaten für alle Rezepte generieren oder aktualisieren',
|
||||
|
||||
// Smaller filters / pages
|
||||
loading_offline: 'Lade Offline-Inhalte…',
|
||||
hide_filters: 'Filter ausblenden',
|
||||
show_filters: 'Filter einblenden',
|
||||
select_icon_placeholder: 'Icon auswählen…',
|
||||
add_tag_placeholder: 'Tag eingeben oder auswählen…',
|
||||
|
||||
// Index / tips / yeast
|
||||
recipes_growing_suffix: 'Rezepte und stetig wachsend…',
|
||||
recipes_collection_meta: 'Eine stetig wachsende Ansammlung an Rezepten aus der Bockenschen Küche.',
|
||||
tips_description: "Eine stetig wachsende Ansammlung an Rezepten aus der Bockenschen Küche.",
|
||||
yeast_toggle_title: 'Zwischen Frischhefe und Trockenhefe wechseln',
|
||||
|
||||
// Search results pageTitle
|
||||
search_results_for_word: 'für',
|
||||
|
||||
// Favorites count label
|
||||
favorites_count_label: 'favorisierte Rezepte',
|
||||
favorite_recipe_singular: 'favorite recipe',
|
||||
favorite_recipes_plural: 'favorite recipes'
|
||||
} as const;
|
||||
|
||||
@@ -139,5 +139,80 @@ export const en = {
|
||||
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.'
|
||||
empty_favorites_2: 'Visit a recipe and click the heart icon to add it to your favorites.',
|
||||
|
||||
// Filters
|
||||
filter_mode: 'Filter Mode',
|
||||
and_label: 'AND',
|
||||
or_label: 'OR',
|
||||
select_category_placeholder: 'Select category…',
|
||||
select_season_placeholder: 'Select season…',
|
||||
|
||||
// Search component
|
||||
search_placeholder_short: 'Search…',
|
||||
search_title: 'Search',
|
||||
clear_search_title: 'Clear search',
|
||||
|
||||
// Tag / Category landing
|
||||
recipes_with_keyword: 'Recipes with Keyword',
|
||||
recipes_in_category: 'Recipes in Category',
|
||||
|
||||
// Card actions
|
||||
edit: 'Edit',
|
||||
delete: 'Delete',
|
||||
|
||||
// Administration page
|
||||
administration_title: 'Administration',
|
||||
untranslated_recipes: 'Untranslated Recipes',
|
||||
alt_text_generator: 'Alt-Text Generator',
|
||||
image_colors: 'Image Colors',
|
||||
nutrition_mappings: 'Nutrition Mappings',
|
||||
|
||||
// Recipe detail page
|
||||
site_title_long: 'Bocken Recipes',
|
||||
|
||||
// InstructionsPage section labels
|
||||
preparation_section: 'Preparation:',
|
||||
bulk_fermentation: 'Bulk Fermentation:',
|
||||
final_proof: 'Final Proof:',
|
||||
baking_section: 'Baking:',
|
||||
cooking_section: 'Cooking:',
|
||||
on_the_plate: 'On the Plate:',
|
||||
instructions_label: 'Instructions',
|
||||
at_temp: 'at',
|
||||
|
||||
// CreateStepList baking
|
||||
not_set: 'Not set',
|
||||
duration: 'Duration',
|
||||
temperature: 'Temperature',
|
||||
mode_label: 'Mode',
|
||||
custom_mode_placeholder: 'or enter custom mode…',
|
||||
|
||||
// Administration page descriptions
|
||||
administration_description: 'Manage recipes and content',
|
||||
untranslated_description: 'View and manage recipes that need translation',
|
||||
alt_text_description: 'Generate alternative text for recipe images using AI',
|
||||
image_colors_description: 'Extract dominant colors from recipe images for loading placeholders',
|
||||
nutrition_mappings_description: 'Generate or regenerate calorie and nutrition data for all recipes',
|
||||
|
||||
// Smaller filters / pages
|
||||
loading_offline: 'Loading offline content…',
|
||||
hide_filters: 'Hide Filters',
|
||||
show_filters: 'Show Filters',
|
||||
select_icon_placeholder: 'Select icon…',
|
||||
add_tag_placeholder: 'Type or select tag…',
|
||||
|
||||
// Index / tips / yeast
|
||||
recipes_growing_suffix: 'recipes and constantly growing…',
|
||||
recipes_collection_meta: "A constantly growing collection of recipes from Bocken's kitchen.",
|
||||
tips_description: "A constantly growing collection of recipes from Bocken's kitchen.",
|
||||
yeast_toggle_title: 'Switch between fresh yeast and dry yeast',
|
||||
|
||||
// Search results pageTitle
|
||||
search_results_for_word: 'for',
|
||||
|
||||
// Favorites count label
|
||||
favorites_count_label: 'favorite recipes',
|
||||
favorite_recipe_singular: 'favorite recipe',
|
||||
favorite_recipes_plural: 'favorite recipes'
|
||||
} as const satisfies Record<keyof typeof de, string>;
|
||||
|
||||
Reference in New Issue
Block a user