feat: add product selection step before meal planning
Inserts a new PlanProductsSheet as step 1 of the planning flow. Users see their current products as a multi-select checklist (all selected by default) before choosing the planning mode and dates. - Empty state explains the benefit and offers "Add products" CTA while always allowing "Plan without products" to skip - Selected product IDs flow through PlanMenuSheet → PlanDatePickerSheet → MenuService.generateForDates → backend - Backend: added ProductIDs field to generate-menu request body; uses ListForPromptByIDs when set, ListForPrompt otherwise - Backend: added Repository.ListForPromptByIDs (filtered SQL query) - All 12 ARB locale files updated with planProducts* keys Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import '../diary/food_search_sheet.dart';
|
||||
import '../menu/menu_provider.dart';
|
||||
import '../menu/plan_date_picker_sheet.dart';
|
||||
import '../menu/plan_menu_sheet.dart';
|
||||
import '../menu/plan_products_sheet.dart';
|
||||
import '../profile/profile_provider.dart';
|
||||
import '../scan/dish_result_screen.dart';
|
||||
import '../scan/recognition_service.dart';
|
||||
@@ -1597,19 +1598,33 @@ class _FutureDayPlanButton extends ConsumerWidget {
|
||||
|
||||
void _openPlanSheet(BuildContext context, WidgetRef ref) {
|
||||
final defaultStart = DateTime.parse(dateString);
|
||||
// Step 1: product selection
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
builder: (_) => PlanMenuSheet(
|
||||
onModeSelected: (mode) {
|
||||
builder: (_) => PlanProductsSheet(
|
||||
onContinue: (selectedProductIds) {
|
||||
// Step 2: planning mode selection
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
builder: (_) => PlanDatePickerSheet(
|
||||
mode: mode,
|
||||
defaultStart: defaultStart,
|
||||
builder: (_) => PlanMenuSheet(
|
||||
selectedProductIds: selectedProductIds,
|
||||
onModeSelected: (mode, productIds) {
|
||||
// Step 3: date / meal type selection
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
builder: (_) => PlanDatePickerSheet(
|
||||
mode: mode,
|
||||
defaultStart: defaultStart,
|
||||
selectedProductIds: productIds,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -192,11 +192,13 @@ class PlanMenuService {
|
||||
Future<void> generateForDates({
|
||||
required List<String> dates,
|
||||
required List<String> mealTypes,
|
||||
List<String> productIds = const [],
|
||||
}) async {
|
||||
final menuService = _ref.read(menuServiceProvider);
|
||||
final plans = await menuService.generateForDates(
|
||||
dates: dates,
|
||||
mealTypes: mealTypes,
|
||||
productIds: productIds,
|
||||
);
|
||||
for (final plan in plans) {
|
||||
_ref.invalidate(menuProvider(isoWeekString(DateTime.parse(plan.weekStart))));
|
||||
|
||||
@@ -27,15 +27,19 @@ class MenuService {
|
||||
}
|
||||
|
||||
/// Generates meals for specific [dates] (YYYY-MM-DD) and [mealTypes].
|
||||
/// When [productIds] is non-empty, only those products are passed to AI.
|
||||
/// Returns the updated MenuPlan for each affected week.
|
||||
Future<List<MenuPlan>> generateForDates({
|
||||
required List<String> dates,
|
||||
required List<String> mealTypes,
|
||||
List<String> productIds = const [],
|
||||
}) async {
|
||||
final data = await _client.post('/ai/generate-menu', data: {
|
||||
final body = <String, dynamic>{
|
||||
'dates': dates,
|
||||
'meal_types': mealTypes,
|
||||
});
|
||||
};
|
||||
if (productIds.isNotEmpty) body['product_ids'] = productIds;
|
||||
final data = await _client.post('/ai/generate-menu', data: body);
|
||||
final plans = data['plans'] as List<dynamic>;
|
||||
return plans
|
||||
.map((planJson) => MenuPlan.fromJson(planJson as Map<String, dynamic>))
|
||||
|
||||
@@ -16,6 +16,7 @@ class PlanDatePickerSheet extends ConsumerStatefulWidget {
|
||||
super.key,
|
||||
required this.mode,
|
||||
required this.defaultStart,
|
||||
required this.selectedProductIds,
|
||||
});
|
||||
|
||||
final PlanMode mode;
|
||||
@@ -24,6 +25,10 @@ class PlanDatePickerSheet extends ConsumerStatefulWidget {
|
||||
/// planned date.
|
||||
final DateTime defaultStart;
|
||||
|
||||
/// Product IDs selected in the previous step. Empty list means the AI
|
||||
/// will use all of the user's products (default behaviour).
|
||||
final List<String> selectedProductIds;
|
||||
|
||||
@override
|
||||
ConsumerState<PlanDatePickerSheet> createState() =>
|
||||
_PlanDatePickerSheetState();
|
||||
@@ -107,6 +112,7 @@ class _PlanDatePickerSheetState extends ConsumerState<PlanDatePickerSheet> {
|
||||
await ref.read(planMenuServiceProvider).generateForDates(
|
||||
dates: dates,
|
||||
mealTypes: mealTypes,
|
||||
productIds: widget.selectedProductIds,
|
||||
);
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
|
||||
@@ -5,11 +5,17 @@ import 'package:food_ai/l10n/app_localizations.dart';
|
||||
enum PlanMode { singleMeal, singleDay, days, week }
|
||||
|
||||
/// Bottom sheet that lets the user choose a planning horizon.
|
||||
/// Closes itself and calls [onModeSelected] with the chosen mode.
|
||||
/// Closes itself and calls [onModeSelected] with the chosen mode and the
|
||||
/// product IDs selected in the previous step (may be empty).
|
||||
class PlanMenuSheet extends StatelessWidget {
|
||||
const PlanMenuSheet({super.key, required this.onModeSelected});
|
||||
const PlanMenuSheet({
|
||||
super.key,
|
||||
required this.onModeSelected,
|
||||
required this.selectedProductIds,
|
||||
});
|
||||
|
||||
final void Function(PlanMode mode) onModeSelected;
|
||||
final void Function(PlanMode mode, List<String> productIds) onModeSelected;
|
||||
final List<String> selectedProductIds;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -61,7 +67,7 @@ class PlanMenuSheet extends StatelessWidget {
|
||||
|
||||
void _select(BuildContext context, PlanMode mode) {
|
||||
Navigator.pop(context);
|
||||
onModeSelected(mode);
|
||||
onModeSelected(mode, selectedProductIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
247
client/lib/features/menu/plan_products_sheet.dart
Normal file
247
client/lib/features/menu/plan_products_sheet.dart
Normal file
@@ -0,0 +1,247 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:food_ai/l10n/app_localizations.dart';
|
||||
|
||||
import '../../shared/models/user_product.dart';
|
||||
import '../products/user_product_provider.dart';
|
||||
|
||||
/// Step-1 bottom sheet for the meal planning flow.
|
||||
///
|
||||
/// Shows the user's current products as a multi-select checklist so they
|
||||
/// can choose which products the AI should consider when generating the menu.
|
||||
/// All products are selected by default. The user may deselect individual
|
||||
/// items or skip the step entirely.
|
||||
///
|
||||
/// Calls [onContinue] with the list of selected product IDs (empty list
|
||||
/// means "plan without products").
|
||||
class PlanProductsSheet extends ConsumerStatefulWidget {
|
||||
const PlanProductsSheet({super.key, required this.onContinue});
|
||||
|
||||
final void Function(List<String> selectedProductIds) onContinue;
|
||||
|
||||
@override
|
||||
ConsumerState<PlanProductsSheet> createState() => _PlanProductsSheetState();
|
||||
}
|
||||
|
||||
class _PlanProductsSheetState extends ConsumerState<PlanProductsSheet> {
|
||||
// IDs of products the user has checked. Null means "not yet initialised"
|
||||
// (we wait for the first data frame to select all by default).
|
||||
Set<String>? _selected;
|
||||
|
||||
void _initSelected(List<UserProduct> products) {
|
||||
if (_selected == null) {
|
||||
_selected = {for (final product in products) product.id};
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleAll(List<UserProduct> products) {
|
||||
setState(() {
|
||||
if (_selected!.length == products.length) {
|
||||
_selected = {};
|
||||
} else {
|
||||
_selected = {for (final product in products) product.id};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _toggleProduct(String productId) {
|
||||
setState(() {
|
||||
if (_selected!.contains(productId)) {
|
||||
_selected = Set.of(_selected!)..remove(productId);
|
||||
} else {
|
||||
_selected = Set.of(_selected!)..add(productId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _continue() {
|
||||
Navigator.pop(context);
|
||||
widget.onContinue(_selected?.toList() ?? []);
|
||||
}
|
||||
|
||||
void _skip() {
|
||||
Navigator.pop(context);
|
||||
widget.onContinue([]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final theme = Theme.of(context);
|
||||
final productsAsync = ref.watch(userProductsProvider);
|
||||
|
||||
return SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 20, 16, 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
l10n.planProductsTitle,
|
||||
style: theme.textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l10n.planProductsSubtitle,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
productsAsync.when(
|
||||
loading: () => const _LoadingSkeleton(),
|
||||
error: (_, __) => _EmptyState(onSkip: _skip, onAddProducts: () {
|
||||
Navigator.pop(context);
|
||||
context.push('/products');
|
||||
}),
|
||||
data: (products) {
|
||||
if (products.isEmpty) {
|
||||
return _EmptyState(
|
||||
onSkip: _skip,
|
||||
onAddProducts: () {
|
||||
Navigator.pop(context);
|
||||
context.push('/products');
|
||||
},
|
||||
);
|
||||
}
|
||||
_initSelected(products);
|
||||
final allSelected = _selected!.length == products.length;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Select all / deselect all chip
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ActionChip(
|
||||
label: Text(
|
||||
allSelected
|
||||
? l10n.planProductsDeselectAll
|
||||
: l10n.planProductsSelectAll,
|
||||
),
|
||||
onPressed: () => _toggleAll(products),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Product list (scrollable, capped at ~4 items before scrolling)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 280),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: products.length,
|
||||
itemBuilder: (context, index) {
|
||||
final product = products[index];
|
||||
final isChecked =
|
||||
_selected!.contains(product.id);
|
||||
return CheckboxListTile(
|
||||
value: isChecked,
|
||||
onChanged: (_) => _toggleProduct(product.id),
|
||||
title: Text(product.name),
|
||||
subtitle: Text(
|
||||
'${product.quantity.toStringAsFixed(product.quantity.truncateToDouble() == product.quantity ? 0 : 1)} ${product.unit}',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
dense: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: _continue,
|
||||
child: Text(l10n.planProductsContinue),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _skip,
|
||||
child: Text(l10n.planProductsSkip),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LoadingSkeleton extends StatelessWidget {
|
||||
const _LoadingSkeleton();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final skeletonColor = theme.colorScheme.surfaceContainerHighest;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(
|
||||
3,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Container(
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: skeletonColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EmptyState extends StatelessWidget {
|
||||
const _EmptyState({required this.onSkip, required this.onAddProducts});
|
||||
|
||||
final VoidCallback onSkip;
|
||||
final VoidCallback onAddProducts;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final theme = Theme.of(context);
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.kitchen_outlined,
|
||||
size: 56,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.planProductsEmpty,
|
||||
style: theme.textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
l10n.planProductsEmptyMessage,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton(
|
||||
onPressed: onAddProducts,
|
||||
child: Text(l10n.planProductsAddProducts),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: onSkip,
|
||||
child: Text(l10n.planProductsSkipNoProducts),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "لم يتم العثور على نتائج لـ \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "حصص",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "وضع علامة كمأكول",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "سيقوم الذكاء الاصطناعي بإنشاء قائمة طعام تشمل الإفطار والغداء والعشاء لكامل الأسبوع",
|
||||
"generatingMenu": "جارٍ إنشاء القائمة...",
|
||||
"dayPlannedLabel": "تم تخطيط اليوم",
|
||||
|
||||
"planMenuButton": "تخطيط الوجبات",
|
||||
"planMenuTitle": "ماذا تريد تخطيطه؟",
|
||||
"planOptionSingleMeal": "وجبة واحدة",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "نوع الوجبة",
|
||||
"planSelectRange": "اختر الفترة",
|
||||
"planGenerateButton": "تخطيط",
|
||||
"planGenerating": "جارٍ إنشاء الخطة\u2026",
|
||||
"planSuccess": "تم تخطيط القائمة!"
|
||||
"planGenerating": "جارٍ إنشاء الخطة…",
|
||||
"planSuccess": "تم تخطيط القائمة!",
|
||||
"planProductsTitle": "مكونات القائمة",
|
||||
"planProductsSubtitle": "سيأخذ الذكاء الاصطناعي المكونات المختارة بعين الاعتبار عند إنشاء الوصفات",
|
||||
"planProductsEmpty": "لم يتم إضافة منتجات",
|
||||
"planProductsEmptyMessage": "أضف المنتجات الموجودة لديك في المنزل — سيقترح الذكاء الاصطناعي وصفات مما لديك بالفعل",
|
||||
"planProductsAddProducts": "إضافة منتجات",
|
||||
"planProductsContinue": "متابعة",
|
||||
"planProductsSkip": "تخطي اختيار المنتجات",
|
||||
"planProductsSkipNoProducts": "التخطيط بدون منتجات",
|
||||
"planProductsSelectAll": "تحديد الكل",
|
||||
"planProductsDeselectAll": "إلغاء تحديد الكل"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "Keine Ergebnisse für \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Portionen",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Als gegessen markieren",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "KI erstellt einen Menüplan mit Frühstück, Mittagessen und Abendessen für die ganze Woche",
|
||||
"generatingMenu": "Menü wird erstellt...",
|
||||
"dayPlannedLabel": "Tag geplant",
|
||||
|
||||
"planMenuButton": "Mahlzeiten planen",
|
||||
"planMenuTitle": "Was planen?",
|
||||
"planOptionSingleMeal": "Einzelne Mahlzeit",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "Mahlzeittyp",
|
||||
"planSelectRange": "Zeitraum wählen",
|
||||
"planGenerateButton": "Planen",
|
||||
"planGenerating": "Plan wird erstellt\u2026",
|
||||
"planSuccess": "Menü geplant!"
|
||||
"planGenerating": "Plan wird erstellt…",
|
||||
"planSuccess": "Menü geplant!",
|
||||
"planProductsTitle": "Zutaten für den Speiseplan",
|
||||
"planProductsSubtitle": "Die KI berücksichtigt die ausgewählten Produkte bei der Rezeptgenerierung",
|
||||
"planProductsEmpty": "Keine Produkte hinzugefügt",
|
||||
"planProductsEmptyMessage": "Füge Produkte hinzu, die du zu Hause hast — die KI schlägt Rezepte aus deinen Vorräten vor",
|
||||
"planProductsAddProducts": "Produkte hinzufügen",
|
||||
"planProductsContinue": "Weiter",
|
||||
"planProductsSkip": "Produktauswahl überspringen",
|
||||
"planProductsSkipNoProducts": "Ohne Produkte planen",
|
||||
"planProductsSelectAll": "Alle auswählen",
|
||||
"planProductsDeselectAll": "Alle abwählen"
|
||||
}
|
||||
|
||||
@@ -150,5 +150,15 @@
|
||||
"planSelectRange": "Select period",
|
||||
"planGenerateButton": "Plan",
|
||||
"planGenerating": "Generating plan\u2026",
|
||||
"planSuccess": "Menu planned!"
|
||||
"planSuccess": "Menu planned!",
|
||||
"planProductsTitle": "Products for the menu",
|
||||
"planProductsSubtitle": "AI will take the selected products into account when generating recipes",
|
||||
"planProductsEmpty": "No products added",
|
||||
"planProductsEmptyMessage": "Add products you have at home \u2014 AI will suggest recipes from what you already have",
|
||||
"planProductsAddProducts": "Add products",
|
||||
"planProductsContinue": "Continue",
|
||||
"planProductsSkip": "Skip product selection",
|
||||
"planProductsSkipNoProducts": "Plan without products",
|
||||
"planProductsSelectAll": "Select all",
|
||||
"planProductsDeselectAll": "Deselect all"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "Nada encontrado para \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Porciones",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Marcar como comido",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "La IA creará un menú con desayuno, comida y cena para toda la semana",
|
||||
"generatingMenu": "Generando menú...",
|
||||
"dayPlannedLabel": "Día planificado",
|
||||
|
||||
"planMenuButton": "Planificar comidas",
|
||||
"planMenuTitle": "¿Qué planificar?",
|
||||
"planOptionSingleMeal": "Una comida",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "Tipo de comida",
|
||||
"planSelectRange": "Seleccionar período",
|
||||
"planGenerateButton": "Planificar",
|
||||
"planGenerating": "Generando plan\u2026",
|
||||
"planSuccess": "¡Menú planificado!"
|
||||
"planGenerating": "Generando plan…",
|
||||
"planSuccess": "¡Menú planificado!",
|
||||
"planProductsTitle": "Productos para el menú",
|
||||
"planProductsSubtitle": "La IA tendrá en cuenta los productos seleccionados al generar recetas",
|
||||
"planProductsEmpty": "No hay productos añadidos",
|
||||
"planProductsEmptyMessage": "Añade productos que tengas en casa — la IA sugerirá recetas con lo que ya tienes",
|
||||
"planProductsAddProducts": "Añadir productos",
|
||||
"planProductsContinue": "Continuar",
|
||||
"planProductsSkip": "Omitir selección de productos",
|
||||
"planProductsSkipNoProducts": "Planificar sin productos",
|
||||
"planProductsSelectAll": "Seleccionar todo",
|
||||
"planProductsDeselectAll": "Deseleccionar todo"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "Rien trouvé pour \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Portions",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Marquer comme mangé",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "L'IA créera un menu avec petit-déjeuner, déjeuner et dîner pour toute la semaine",
|
||||
"generatingMenu": "Génération du menu...",
|
||||
"dayPlannedLabel": "Jour planifié",
|
||||
|
||||
"planMenuButton": "Planifier les repas",
|
||||
"planMenuTitle": "Que planifier ?",
|
||||
"planOptionSingleMeal": "Un repas",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "Type de repas",
|
||||
"planSelectRange": "Choisir la période",
|
||||
"planGenerateButton": "Planifier",
|
||||
"planGenerating": "Génération du plan\u2026",
|
||||
"planSuccess": "Menu planifié !"
|
||||
"planGenerating": "Génération du plan…",
|
||||
"planSuccess": "Menu planifié !",
|
||||
"planProductsTitle": "Produits pour le menu",
|
||||
"planProductsSubtitle": "L'IA tiendra compte des produits sélectionnés lors de la génération des recettes",
|
||||
"planProductsEmpty": "Aucun produit ajouté",
|
||||
"planProductsEmptyMessage": "Ajoutez des produits que vous avez à la maison — l'IA suggérera des recettes à partir de ce que vous avez déjà",
|
||||
"planProductsAddProducts": "Ajouter des produits",
|
||||
"planProductsContinue": "Continuer",
|
||||
"planProductsSkip": "Ignorer la sélection des produits",
|
||||
"planProductsSkipNoProducts": "Planifier sans produits",
|
||||
"planProductsSelectAll": "Tout sélectionner",
|
||||
"planProductsDeselectAll": "Tout désélectionner"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "\"{query}\" के लिए कुछ नहीं मिला",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "सर्विंग",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "खाया हुआ चिह्नित करें",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "AI पूरे सप्ताह के लिए नाश्ता, दोपहर का खाना और रात के खाने के साथ मेनू बनाएगा",
|
||||
"generatingMenu": "मेनू बना रहे हैं...",
|
||||
"dayPlannedLabel": "दिन की योजना बनाई गई",
|
||||
|
||||
"planMenuButton": "भोजन की योजना बनाएं",
|
||||
"planMenuTitle": "क्या योजना बनानी है?",
|
||||
"planOptionSingleMeal": "एक भोजन",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "भोजन का प्रकार",
|
||||
"planSelectRange": "अवधि चुनें",
|
||||
"planGenerateButton": "योजना बनाएं",
|
||||
"planGenerating": "योजना बना रहे हैं\u2026",
|
||||
"planSuccess": "मेनू की योजना बनाई गई!"
|
||||
"planGenerating": "योजना बना रहे हैं…",
|
||||
"planSuccess": "मेनू की योजना बनाई गई!",
|
||||
"planProductsTitle": "मेनू के लिए उत्पाद",
|
||||
"planProductsSubtitle": "AI रेसिपी बनाते समय चुने हुए उत्पादों को ध्यान में रखेगा",
|
||||
"planProductsEmpty": "कोई उत्पाद नहीं जोड़ा गया",
|
||||
"planProductsEmptyMessage": "घर पर उपलब्ध उत्पाद जोड़ें — AI आपके पास पहले से मौजूद चीज़ों से रेसिपी सुझाएगा",
|
||||
"planProductsAddProducts": "उत्पाद जोड़ें",
|
||||
"planProductsContinue": "जारी रखें",
|
||||
"planProductsSkip": "उत्पाद चयन छोड़ें",
|
||||
"planProductsSkipNoProducts": "उत्पादों के बिना योजना बनाएं",
|
||||
"planProductsSelectAll": "सभी चुनें",
|
||||
"planProductsDeselectAll": "सभी हटाएं"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "Nessun risultato per \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Porzioni",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Segna come mangiato",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "L'AI creerà un menu con colazione, pranzo e cena per tutta la settimana",
|
||||
"generatingMenu": "Generazione menu...",
|
||||
"dayPlannedLabel": "Giorno pianificato",
|
||||
|
||||
"planMenuButton": "Pianifica i pasti",
|
||||
"planMenuTitle": "Cosa pianificare?",
|
||||
"planOptionSingleMeal": "Un pasto",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "Tipo di pasto",
|
||||
"planSelectRange": "Seleziona periodo",
|
||||
"planGenerateButton": "Pianifica",
|
||||
"planGenerating": "Generazione piano\u2026",
|
||||
"planSuccess": "Menu pianificato!"
|
||||
"planGenerating": "Generazione piano…",
|
||||
"planSuccess": "Menu pianificato!",
|
||||
"planProductsTitle": "Prodotti per il menu",
|
||||
"planProductsSubtitle": "L'AI terrà conto dei prodotti selezionati nella generazione delle ricette",
|
||||
"planProductsEmpty": "Nessun prodotto aggiunto",
|
||||
"planProductsEmptyMessage": "Aggiungi prodotti che hai in casa — l'AI suggerirà ricette con quello che hai già",
|
||||
"planProductsAddProducts": "Aggiungi prodotti",
|
||||
"planProductsContinue": "Continua",
|
||||
"planProductsSkip": "Salta la selezione dei prodotti",
|
||||
"planProductsSkipNoProducts": "Pianifica senza prodotti",
|
||||
"planProductsSelectAll": "Seleziona tutto",
|
||||
"planProductsDeselectAll": "Deseleziona tutto"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "「{query}」の検索結果はありません",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "人前",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "食べた印をつける",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "AIが一週間の朝食・昼食・夕食のメニューを作成します",
|
||||
"generatingMenu": "メニューを生成中...",
|
||||
"dayPlannedLabel": "日の計画済み",
|
||||
|
||||
"planMenuButton": "食事を計画する",
|
||||
"planMenuTitle": "何を計画する?",
|
||||
"planOptionSingleMeal": "1食",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "食事タイプ",
|
||||
"planSelectRange": "期間を選択",
|
||||
"planGenerateButton": "計画する",
|
||||
"planGenerating": "プランを生成中\u2026",
|
||||
"planSuccess": "メニューが計画されました!"
|
||||
"planGenerating": "プランを生成中…",
|
||||
"planSuccess": "メニューが計画されました!",
|
||||
"planProductsTitle": "メニューの食材",
|
||||
"planProductsSubtitle": "AIはレシピ生成時に選択した食材を考慮します",
|
||||
"planProductsEmpty": "食材が追加されていません",
|
||||
"planProductsEmptyMessage": "家にある食材を追加してください — AIが手持ちの食材でレシピを提案します",
|
||||
"planProductsAddProducts": "食材を追加",
|
||||
"planProductsContinue": "続ける",
|
||||
"planProductsSkip": "食材選択をスキップ",
|
||||
"planProductsSkipNoProducts": "食材なしでプランニング",
|
||||
"planProductsSelectAll": "すべて選択",
|
||||
"planProductsDeselectAll": "すべて解除"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "\"{query}\"에 대한 결과 없음",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "인분",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "먹은 것으로 표시",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "AI가 한 주 동안 아침, 점심, 저녁 식사 메뉴를 만들어 드립니다",
|
||||
"generatingMenu": "메뉴 생성 중...",
|
||||
"dayPlannedLabel": "일일 계획 완료",
|
||||
|
||||
"planMenuButton": "식사 계획하기",
|
||||
"planMenuTitle": "무엇을 계획하시겠어요?",
|
||||
"planOptionSingleMeal": "식사 1회",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "식사 유형",
|
||||
"planSelectRange": "기간 선택",
|
||||
"planGenerateButton": "계획하기",
|
||||
"planGenerating": "플랜 생성 중\u2026",
|
||||
"planSuccess": "메뉴가 계획되었습니다!"
|
||||
"planGenerating": "플랜 생성 중…",
|
||||
"planSuccess": "메뉴가 계획되었습니다!",
|
||||
"planProductsTitle": "메뉴 재료",
|
||||
"planProductsSubtitle": "AI가 레시피 생성 시 선택한 재료를 고려합니다",
|
||||
"planProductsEmpty": "추가된 재료가 없습니다",
|
||||
"planProductsEmptyMessage": "집에 있는 재료를 추가하세요 — AI가 이미 있는 재료로 레시피를 제안합니다",
|
||||
"planProductsAddProducts": "재료 추가",
|
||||
"planProductsContinue": "계속",
|
||||
"planProductsSkip": "재료 선택 건너뛰기",
|
||||
"planProductsSkipNoProducts": "재료 없이 계획하기",
|
||||
"planProductsSelectAll": "모두 선택",
|
||||
"planProductsDeselectAll": "모두 해제"
|
||||
}
|
||||
|
||||
@@ -927,6 +927,66 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'Menu planned!'**
|
||||
String get planSuccess;
|
||||
|
||||
/// No description provided for @planProductsTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Products for the menu'**
|
||||
String get planProductsTitle;
|
||||
|
||||
/// No description provided for @planProductsSubtitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'AI will take the selected products into account when generating recipes'**
|
||||
String get planProductsSubtitle;
|
||||
|
||||
/// No description provided for @planProductsEmpty.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No products added'**
|
||||
String get planProductsEmpty;
|
||||
|
||||
/// No description provided for @planProductsEmptyMessage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add products you have at home — AI will suggest recipes from what you already have'**
|
||||
String get planProductsEmptyMessage;
|
||||
|
||||
/// No description provided for @planProductsAddProducts.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add products'**
|
||||
String get planProductsAddProducts;
|
||||
|
||||
/// No description provided for @planProductsContinue.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Continue'**
|
||||
String get planProductsContinue;
|
||||
|
||||
/// No description provided for @planProductsSkip.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Skip product selection'**
|
||||
String get planProductsSkip;
|
||||
|
||||
/// No description provided for @planProductsSkipNoProducts.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Plan without products'**
|
||||
String get planProductsSkipNoProducts;
|
||||
|
||||
/// No description provided for @planProductsSelectAll.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Select all'**
|
||||
String get planProductsSelectAll;
|
||||
|
||||
/// No description provided for @planProductsDeselectAll.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Deselect all'**
|
||||
String get planProductsDeselectAll;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -420,4 +420,36 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'تم تخطيط القائمة!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'مكونات القائمة';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'سيأخذ الذكاء الاصطناعي المكونات المختارة بعين الاعتبار عند إنشاء الوصفات';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'لم يتم إضافة منتجات';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'أضف المنتجات الموجودة لديك في المنزل — سيقترح الذكاء الاصطناعي وصفات مما لديك بالفعل';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'إضافة منتجات';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'متابعة';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'تخطي اختيار المنتجات';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'التخطيط بدون منتجات';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'تحديد الكل';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'إلغاء تحديد الكل';
|
||||
}
|
||||
|
||||
@@ -422,4 +422,36 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Menü geplant!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Zutaten für den Speiseplan';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'Die KI berücksichtigt die ausgewählten Produkte bei der Rezeptgenerierung';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'Keine Produkte hinzugefügt';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Füge Produkte hinzu, die du zu Hause hast — die KI schlägt Rezepte aus deinen Vorräten vor';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Produkte hinzufügen';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Weiter';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Produktauswahl überspringen';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Ohne Produkte planen';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Alle auswählen';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Alle abwählen';
|
||||
}
|
||||
|
||||
@@ -420,4 +420,36 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Menu planned!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Products for the menu';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'AI will take the selected products into account when generating recipes';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'No products added';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Add products you have at home — AI will suggest recipes from what you already have';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Add products';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Continue';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Skip product selection';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Plan without products';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Select all';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Deselect all';
|
||||
}
|
||||
|
||||
@@ -422,4 +422,36 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => '¡Menú planificado!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Productos para el menú';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'La IA tendrá en cuenta los productos seleccionados al generar recetas';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'No hay productos añadidos';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Añade productos que tengas en casa — la IA sugerirá recetas con lo que ya tienes';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Añadir productos';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Continuar';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Omitir selección de productos';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Planificar sin productos';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Seleccionar todo';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Deseleccionar todo';
|
||||
}
|
||||
|
||||
@@ -423,4 +423,36 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Menu planifié !';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Produits pour le menu';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'L\'IA tiendra compte des produits sélectionnés lors de la génération des recettes';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'Aucun produit ajouté';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Ajoutez des produits que vous avez à la maison — l\'IA suggérera des recettes à partir de ce que vous avez déjà';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Ajouter des produits';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Continuer';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Ignorer la sélection des produits';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Planifier sans produits';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Tout sélectionner';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Tout désélectionner';
|
||||
}
|
||||
|
||||
@@ -421,4 +421,36 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'मेनू की योजना बनाई गई!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'मेनू के लिए उत्पाद';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'AI रेसिपी बनाते समय चुने हुए उत्पादों को ध्यान में रखेगा';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'कोई उत्पाद नहीं जोड़ा गया';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'घर पर उपलब्ध उत्पाद जोड़ें — AI आपके पास पहले से मौजूद चीज़ों से रेसिपी सुझाएगा';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'उत्पाद जोड़ें';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'जारी रखें';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'उत्पाद चयन छोड़ें';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'उत्पादों के बिना योजना बनाएं';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'सभी चुनें';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'सभी हटाएं';
|
||||
}
|
||||
|
||||
@@ -422,4 +422,36 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Menu pianificato!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Prodotti per il menu';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'L\'AI terrà conto dei prodotti selezionati nella generazione delle ricette';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'Nessun prodotto aggiunto';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Aggiungi prodotti che hai in casa — l\'AI suggerirà ricette con quello che hai già';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Aggiungi prodotti';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Continua';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Salta la selezione dei prodotti';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Pianifica senza prodotti';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Seleziona tutto';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Deseleziona tutto';
|
||||
}
|
||||
|
||||
@@ -418,4 +418,35 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'メニューが計画されました!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'メニューの食材';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle => 'AIはレシピ生成時に選択した食材を考慮します';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => '食材が追加されていません';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'家にある食材を追加してください — AIが手持ちの食材でレシピを提案します';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => '食材を追加';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => '続ける';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => '食材選択をスキップ';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => '食材なしでプランニング';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'すべて選択';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'すべて解除';
|
||||
}
|
||||
|
||||
@@ -418,4 +418,35 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => '메뉴가 계획되었습니다!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => '메뉴 재료';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle => 'AI가 레시피 생성 시 선택한 재료를 고려합니다';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => '추가된 재료가 없습니다';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'집에 있는 재료를 추가하세요 — AI가 이미 있는 재료로 레시피를 제안합니다';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => '재료 추가';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => '계속';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => '재료 선택 건너뛰기';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => '재료 없이 계획하기';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => '모두 선택';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => '모두 해제';
|
||||
}
|
||||
|
||||
@@ -422,4 +422,36 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Menu planejado!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Produtos para o menu';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'A IA levará em conta os produtos selecionados ao gerar receitas';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'Nenhum produto adicionado';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Adicione produtos que você tem em casa — a IA sugerirá receitas com o que você já tem';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Adicionar produtos';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Continuar';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Pular seleção de produtos';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Planejar sem produtos';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Selecionar tudo';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Desmarcar tudo';
|
||||
}
|
||||
|
||||
@@ -420,4 +420,36 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => 'Меню запланировано!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => 'Продукты для меню';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle =>
|
||||
'AI учтёт выбранные продукты при составлении рецептов';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => 'Продукты не добавлены';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage =>
|
||||
'Добавьте продукты, которые есть у вас дома — AI подберёт рецепты из того, что уже есть';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => 'Добавить продукты';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => 'Продолжить';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => 'Пропустить выбор продуктов';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => 'Планировать без продуктов';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => 'Выбрать все';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => 'Снять всё';
|
||||
}
|
||||
|
||||
@@ -418,4 +418,34 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get planSuccess => '菜单已规划!';
|
||||
|
||||
@override
|
||||
String get planProductsTitle => '菜单食材';
|
||||
|
||||
@override
|
||||
String get planProductsSubtitle => 'AI在生成食谱时会考虑所选食材';
|
||||
|
||||
@override
|
||||
String get planProductsEmpty => '尚未添加食材';
|
||||
|
||||
@override
|
||||
String get planProductsEmptyMessage => '添加您家中的食材 — AI将根据您已有的食材推荐食谱';
|
||||
|
||||
@override
|
||||
String get planProductsAddProducts => '添加食材';
|
||||
|
||||
@override
|
||||
String get planProductsContinue => '继续';
|
||||
|
||||
@override
|
||||
String get planProductsSkip => '跳过食材选择';
|
||||
|
||||
@override
|
||||
String get planProductsSkipNoProducts => '不选食材直接规划';
|
||||
|
||||
@override
|
||||
String get planProductsSelectAll => '全选';
|
||||
|
||||
@override
|
||||
String get planProductsDeselectAll => '取消全选';
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "Nada encontrado para \"{query}\"",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Porções",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Marcar como comido",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "A IA criará um menu com café da manhã, almoço e jantar para a semana inteira",
|
||||
"generatingMenu": "Gerando menu...",
|
||||
"dayPlannedLabel": "Dia planejado",
|
||||
|
||||
"planMenuButton": "Planejar refeições",
|
||||
"planMenuTitle": "O que planejar?",
|
||||
"planOptionSingleMeal": "Uma refeição",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "Tipo de refeição",
|
||||
"planSelectRange": "Selecionar período",
|
||||
"planGenerateButton": "Planejar",
|
||||
"planGenerating": "Gerando plano\u2026",
|
||||
"planSuccess": "Menu planejado!"
|
||||
"planGenerating": "Gerando plano…",
|
||||
"planSuccess": "Menu planejado!",
|
||||
"planProductsTitle": "Produtos para o menu",
|
||||
"planProductsSubtitle": "A IA levará em conta os produtos selecionados ao gerar receitas",
|
||||
"planProductsEmpty": "Nenhum produto adicionado",
|
||||
"planProductsEmptyMessage": "Adicione produtos que você tem em casa — a IA sugerirá receitas com o que você já tem",
|
||||
"planProductsAddProducts": "Adicionar produtos",
|
||||
"planProductsContinue": "Continuar",
|
||||
"planProductsSkip": "Pular seleção de produtos",
|
||||
"planProductsSkipNoProducts": "Planejar sem produtos",
|
||||
"planProductsSelectAll": "Selecionar tudo",
|
||||
"planProductsDeselectAll": "Desmarcar tudo"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Позиция {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Обрабатываем...",
|
||||
@@ -116,7 +118,9 @@
|
||||
"noResultsForQuery": "По запросу \"{query}\" ничего не найдено",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "Порций",
|
||||
@@ -125,7 +129,9 @@
|
||||
"planningForDate": "Планирование на {date}",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "Отметить как съеденное",
|
||||
@@ -134,7 +140,6 @@
|
||||
"generateWeekSubtitle": "AI составит меню с завтраком, обедом и ужином на всю неделю",
|
||||
"generatingMenu": "Генерируем меню...",
|
||||
"dayPlannedLabel": "День запланирован",
|
||||
|
||||
"planMenuButton": "Спланировать меню",
|
||||
"planMenuTitle": "Что запланировать?",
|
||||
"planOptionSingleMeal": "1 приём пищи",
|
||||
@@ -149,6 +154,16 @@
|
||||
"planSelectMealType": "Приём пищи",
|
||||
"planSelectRange": "Выберите период",
|
||||
"planGenerateButton": "Запланировать",
|
||||
"planGenerating": "Генерирую план\u2026",
|
||||
"planSuccess": "Меню запланировано!"
|
||||
"planGenerating": "Генерирую план…",
|
||||
"planSuccess": "Меню запланировано!",
|
||||
"planProductsTitle": "Продукты для меню",
|
||||
"planProductsSubtitle": "AI учтёт выбранные продукты при составлении рецептов",
|
||||
"planProductsEmpty": "Продукты не добавлены",
|
||||
"planProductsEmptyMessage": "Добавьте продукты, которые есть у вас дома — AI подберёт рецепты из того, что уже есть",
|
||||
"planProductsAddProducts": "Добавить продукты",
|
||||
"planProductsContinue": "Продолжить",
|
||||
"planProductsSkip": "Пропустить выбор продуктов",
|
||||
"planProductsSkipNoProducts": "Планировать без продуктов",
|
||||
"planProductsSelectAll": "Выбрать все",
|
||||
"planProductsDeselectAll": "Снять всё"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@
|
||||
"noResultsForQuery": "未找到 \"{query}\" 的结果",
|
||||
"@noResultsForQuery": {
|
||||
"placeholders": {
|
||||
"query": { "type": "String" }
|
||||
"query": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"servingsLabel": "份数",
|
||||
@@ -127,7 +129,9 @@
|
||||
"planningForDate": "",
|
||||
"@planningForDate": {
|
||||
"placeholders": {
|
||||
"date": { "type": "String" }
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markAsEaten": "标记为已吃",
|
||||
@@ -136,7 +140,6 @@
|
||||
"generateWeekSubtitle": "AI将为整周创建含早餐、午餐和晚餐的菜单",
|
||||
"generatingMenu": "正在生成菜单...",
|
||||
"dayPlannedLabel": "今日已规划",
|
||||
|
||||
"planMenuButton": "规划餐食",
|
||||
"planMenuTitle": "规划什么?",
|
||||
"planOptionSingleMeal": "单次餐食",
|
||||
@@ -151,6 +154,16 @@
|
||||
"planSelectMealType": "餐食类型",
|
||||
"planSelectRange": "选择时间段",
|
||||
"planGenerateButton": "规划",
|
||||
"planGenerating": "正在生成计划\u2026",
|
||||
"planSuccess": "菜单已规划!"
|
||||
"planGenerating": "正在生成计划…",
|
||||
"planSuccess": "菜单已规划!",
|
||||
"planProductsTitle": "菜单食材",
|
||||
"planProductsSubtitle": "AI在生成食谱时会考虑所选食材",
|
||||
"planProductsEmpty": "尚未添加食材",
|
||||
"planProductsEmptyMessage": "添加您家中的食材 — AI将根据您已有的食材推荐食谱",
|
||||
"planProductsAddProducts": "添加食材",
|
||||
"planProductsContinue": "继续",
|
||||
"planProductsSkip": "跳过食材选择",
|
||||
"planProductsSkipNoProducts": "不选食材直接规划",
|
||||
"planProductsSelectAll": "全选",
|
||||
"planProductsDeselectAll": "取消全选"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user