feat: rename ingredients→products, products→user_products; add barcode/OFF import
- Rename catalog: ingredient/* → product/* (canonical_name, barcode, nutrition per 100g)
- Rename pantry: product/* → userproduct/* (user-owned items with expiry)
- Squash migrations into single 001_initial_schema.sql (clean-db baseline)
- product_categories: add English canonical name column; fix COALESCE in queries
- Remove product_translations: product names are stored in their original language
- Add default_unit_name to product API responses via unit_translations JOIN
- Add cmd/importoff: bulk import from OpenFoodFacts JSONL dump (COPY + ON CONFLICT)
- Diary: support product_id entries alongside dish_id (CHECK num_nonnulls = 1)
- Home: getLoggedCalories joins both recipes and catalog products
- Flutter: rename models/providers/services to match backend rename
- Flutter: add barcode scan flow for diary (mobile_scanner, product_portion_sheet)
- Flutter: localise 6 new keys across 12 languages (barcode scan, portion weight)
- Routes: GET /products/search, GET /products/barcode/{barcode}, /user-products
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "الموضع {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "جارٍ المعالجة...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "تصوير الإيصال",
|
||||
"photoReceiptSubtitle": "التعرف على جميع المنتجات من الإيصال",
|
||||
"photoProducts": "تصوير المنتجات",
|
||||
"photoProductsSubtitle": "الثلاجة، الطاولة، الرف — حتى 3 صور"
|
||||
"photoProductsSubtitle": "الثلاجة، الطاولة، الرف — حتى 3 صور",
|
||||
"addPackagedFood": "إضافة منتج معبأ",
|
||||
"scanBarcode": "مسح الباركود",
|
||||
"portionWeightG": "وزن الحصة (جم)",
|
||||
"productNotFound": "المنتج غير موجود",
|
||||
"enterManually": "أدخل يدوياً",
|
||||
"perHundredG": "لكل 100 جم"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Position {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Verarbeitung...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "Kassenbon fotografieren",
|
||||
"photoReceiptSubtitle": "Alle Produkte vom Kassenbon erkennen",
|
||||
"photoProducts": "Produkte fotografieren",
|
||||
"photoProductsSubtitle": "Kühlschrank, Tisch, Regal — bis zu 3 Fotos"
|
||||
"photoProductsSubtitle": "Kühlschrank, Tisch, Regal — bis zu 3 Fotos",
|
||||
"addPackagedFood": "Verpacktes Lebensmittel hinzufügen",
|
||||
"scanBarcode": "Barcode scannen",
|
||||
"portionWeightG": "Portionsgewicht (g)",
|
||||
"productNotFound": "Produkt nicht gefunden",
|
||||
"enterManually": "Manuell eingeben",
|
||||
"perHundredG": "pro 100 g"
|
||||
}
|
||||
|
||||
@@ -102,5 +102,11 @@
|
||||
"photoReceipt": "Photo of receipt",
|
||||
"photoReceiptSubtitle": "Recognize all items from a receipt",
|
||||
"photoProducts": "Photo of products",
|
||||
"photoProductsSubtitle": "Fridge, table, shelf — up to 3 photos"
|
||||
"photoProductsSubtitle": "Fridge, table, shelf — up to 3 photos",
|
||||
"addPackagedFood": "Add packaged food",
|
||||
"scanBarcode": "Scan barcode",
|
||||
"portionWeightG": "Portion weight (g)",
|
||||
"productNotFound": "Product not found",
|
||||
"enterManually": "Enter manually",
|
||||
"perHundredG": "per 100 g"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Posición {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Procesando...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "Fotografiar recibo",
|
||||
"photoReceiptSubtitle": "Reconocemos todos los productos del recibo",
|
||||
"photoProducts": "Fotografiar productos",
|
||||
"photoProductsSubtitle": "Nevera, mesa, estante — hasta 3 fotos"
|
||||
"photoProductsSubtitle": "Nevera, mesa, estante — hasta 3 fotos",
|
||||
"addPackagedFood": "Agregar alimento envasado",
|
||||
"scanBarcode": "Escanear código de barras",
|
||||
"portionWeightG": "Peso de la porción (g)",
|
||||
"productNotFound": "Producto no encontrado",
|
||||
"enterManually": "Ingresar manualmente",
|
||||
"perHundredG": "por 100 g"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Position {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Traitement...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "Photographier le ticket",
|
||||
"photoReceiptSubtitle": "Reconnaissance de tous les produits du ticket",
|
||||
"photoProducts": "Photographier les produits",
|
||||
"photoProductsSubtitle": "Réfrigérateur, table, étagère — jusqu'à 3 photos"
|
||||
"photoProductsSubtitle": "Réfrigérateur, table, étagère — jusqu'à 3 photos",
|
||||
"addPackagedFood": "Ajouter un aliment emballé",
|
||||
"scanBarcode": "Scanner le code-barres",
|
||||
"portionWeightG": "Poids de la portion (g)",
|
||||
"productNotFound": "Produit introuvable",
|
||||
"enterManually": "Saisir manuellement",
|
||||
"perHundredG": "pour 100 g"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "स्थिति {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "प्रसंस्करण हो रहा है...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "रसीद की फ़ोटो",
|
||||
"photoReceiptSubtitle": "रसीद से सभी उत्पाद पहचानें",
|
||||
"photoProducts": "उत्पादों की फ़ोटो",
|
||||
"photoProductsSubtitle": "फ्रिज, टेबल, शेल्फ — 3 फ़ोटो तक"
|
||||
"photoProductsSubtitle": "फ्रिज, टेबल, शेल्फ — 3 फ़ोटो तक",
|
||||
"addPackagedFood": "पैकेज्ड फूड जोड़ें",
|
||||
"scanBarcode": "बारकोड स्कैन करें",
|
||||
"portionWeightG": "हिस्से का वजन (ग्राम)",
|
||||
"productNotFound": "उत्पाद नहीं मिला",
|
||||
"enterManually": "मैन्युअल दर्ज करें",
|
||||
"perHundredG": "प्रति 100 ग्राम"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Posizione {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Elaborazione...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "Fotografa scontrino",
|
||||
"photoReceiptSubtitle": "Riconosciamo tutti i prodotti dallo scontrino",
|
||||
"photoProducts": "Fotografa i prodotti",
|
||||
"photoProductsSubtitle": "Frigo, tavolo, scaffale — fino a 3 foto"
|
||||
"photoProductsSubtitle": "Frigo, tavolo, scaffale — fino a 3 foto",
|
||||
"addPackagedFood": "Aggiungi alimento confezionato",
|
||||
"scanBarcode": "Scansiona codice a barre",
|
||||
"portionWeightG": "Peso della porzione (g)",
|
||||
"productNotFound": "Prodotto non trovato",
|
||||
"enterManually": "Inserisci manualmente",
|
||||
"perHundredG": "per 100 g"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "{position}番目",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "処理中...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "レシートを撮影",
|
||||
"photoReceiptSubtitle": "レシートから全商品を認識",
|
||||
"photoProducts": "食品を撮影",
|
||||
"photoProductsSubtitle": "冷蔵庫・テーブル・棚 — 最大3枚"
|
||||
"photoProductsSubtitle": "冷蔵庫・テーブル・棚 — 最大3枚",
|
||||
"addPackagedFood": "パッケージ食品を追加",
|
||||
"scanBarcode": "バーコードをスキャン",
|
||||
"portionWeightG": "1食分の重さ(g)",
|
||||
"productNotFound": "商品が見つかりません",
|
||||
"enterManually": "手動で入力",
|
||||
"perHundredG": "100gあたり"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "{position}번째",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "처리 중...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "영수증 촬영",
|
||||
"photoReceiptSubtitle": "영수증의 모든 상품 인식",
|
||||
"photoProducts": "식품 촬영",
|
||||
"photoProductsSubtitle": "냉장고, 테이블, 선반 — 최대 3장"
|
||||
"photoProductsSubtitle": "냉장고, 테이블, 선반 — 최대 3장",
|
||||
"addPackagedFood": "포장 식품 추가",
|
||||
"scanBarcode": "바코드 스캔",
|
||||
"portionWeightG": "1회 제공량 (g)",
|
||||
"productNotFound": "제품을 찾을 수 없습니다",
|
||||
"enterManually": "직접 입력",
|
||||
"perHundredG": "100g당"
|
||||
}
|
||||
|
||||
@@ -705,6 +705,42 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'Fridge, table, shelf — up to 3 photos'**
|
||||
String get photoProductsSubtitle;
|
||||
|
||||
/// No description provided for @addPackagedFood.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add packaged food'**
|
||||
String get addPackagedFood;
|
||||
|
||||
/// No description provided for @scanBarcode.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Scan barcode'**
|
||||
String get scanBarcode;
|
||||
|
||||
/// No description provided for @portionWeightG.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Portion weight (g)'**
|
||||
String get portionWeightG;
|
||||
|
||||
/// No description provided for @productNotFound.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Product not found'**
|
||||
String get productNotFound;
|
||||
|
||||
/// No description provided for @enterManually.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Enter manually'**
|
||||
String get enterManually;
|
||||
|
||||
/// No description provided for @perHundredG.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'per 100 g'**
|
||||
String get perHundredG;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -304,4 +304,22 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'الثلاجة، الطاولة، الرف — حتى 3 صور';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'إضافة منتج معبأ';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'مسح الباركود';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'وزن الحصة (جم)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'المنتج غير موجود';
|
||||
|
||||
@override
|
||||
String get enterManually => 'أدخل يدوياً';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'لكل 100 جم';
|
||||
}
|
||||
|
||||
@@ -306,4 +306,22 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get photoProductsSubtitle =>
|
||||
'Kühlschrank, Tisch, Regal — bis zu 3 Fotos';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Verpacktes Lebensmittel hinzufügen';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Barcode scannen';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Portionsgewicht (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Produkt nicht gefunden';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Manuell eingeben';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'pro 100 g';
|
||||
}
|
||||
|
||||
@@ -304,4 +304,22 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'Fridge, table, shelf — up to 3 photos';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Add packaged food';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Scan barcode';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Portion weight (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Product not found';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Enter manually';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'per 100 g';
|
||||
}
|
||||
|
||||
@@ -306,4 +306,22 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'Nevera, mesa, estante — hasta 3 fotos';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Agregar alimento envasado';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Escanear código de barras';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Peso de la porción (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Producto no encontrado';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Ingresar manualmente';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'por 100 g';
|
||||
}
|
||||
|
||||
@@ -307,4 +307,22 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get photoProductsSubtitle =>
|
||||
'Réfrigérateur, table, étagère — jusqu\'à 3 photos';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Ajouter un aliment emballé';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Scanner le code-barres';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Poids de la portion (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Produit introuvable';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Saisir manuellement';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'pour 100 g';
|
||||
}
|
||||
|
||||
@@ -305,4 +305,22 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'फ्रिज, टेबल, शेल्फ — 3 फ़ोटो तक';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'पैकेज्ड फूड जोड़ें';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'बारकोड स्कैन करें';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'हिस्से का वजन (ग्राम)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'उत्पाद नहीं मिला';
|
||||
|
||||
@override
|
||||
String get enterManually => 'मैन्युअल दर्ज करें';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'प्रति 100 ग्राम';
|
||||
}
|
||||
|
||||
@@ -306,4 +306,22 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'Frigo, tavolo, scaffale — fino a 3 foto';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Aggiungi alimento confezionato';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Scansiona codice a barre';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Peso della porzione (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Prodotto non trovato';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Inserisci manualmente';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'per 100 g';
|
||||
}
|
||||
|
||||
@@ -303,4 +303,22 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => '冷蔵庫・テーブル・棚 — 最大3枚';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'パッケージ食品を追加';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'バーコードをスキャン';
|
||||
|
||||
@override
|
||||
String get portionWeightG => '1食分の重さ(g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => '商品が見つかりません';
|
||||
|
||||
@override
|
||||
String get enterManually => '手動で入力';
|
||||
|
||||
@override
|
||||
String get perHundredG => '100gあたり';
|
||||
}
|
||||
|
||||
@@ -303,4 +303,22 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => '냉장고, 테이블, 선반 — 최대 3장';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => '포장 식품 추가';
|
||||
|
||||
@override
|
||||
String get scanBarcode => '바코드 스캔';
|
||||
|
||||
@override
|
||||
String get portionWeightG => '1회 제공량 (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => '제품을 찾을 수 없습니다';
|
||||
|
||||
@override
|
||||
String get enterManually => '직접 입력';
|
||||
|
||||
@override
|
||||
String get perHundredG => '100g당';
|
||||
}
|
||||
|
||||
@@ -306,4 +306,22 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get photoProductsSubtitle =>
|
||||
'Geladeira, mesa, prateleira — até 3 fotos';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Adicionar alimento embalado';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Escanear código de barras';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Peso da porção (g)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Produto não encontrado';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Inserir manualmente';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'por 100 g';
|
||||
}
|
||||
|
||||
@@ -304,4 +304,22 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => 'Холодильник, стол, полка — до 3 фото';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => 'Добавить готовый продукт';
|
||||
|
||||
@override
|
||||
String get scanBarcode => 'Сканировать штрихкод';
|
||||
|
||||
@override
|
||||
String get portionWeightG => 'Вес порции (г)';
|
||||
|
||||
@override
|
||||
String get productNotFound => 'Продукт не найден';
|
||||
|
||||
@override
|
||||
String get enterManually => 'Ввести вручную';
|
||||
|
||||
@override
|
||||
String get perHundredG => 'на 100 г';
|
||||
}
|
||||
|
||||
@@ -303,4 +303,22 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get photoProductsSubtitle => '冰箱、桌子、货架 — 最多3张照片';
|
||||
|
||||
@override
|
||||
String get addPackagedFood => '添加包装食品';
|
||||
|
||||
@override
|
||||
String get scanBarcode => '扫描条形码';
|
||||
|
||||
@override
|
||||
String get portionWeightG => '份量(克)';
|
||||
|
||||
@override
|
||||
String get productNotFound => '未找到产品';
|
||||
|
||||
@override
|
||||
String get enterManually => '手动输入';
|
||||
|
||||
@override
|
||||
String get perHundredG => '每100克';
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "Posição {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "Processando...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "Fotografar recibo",
|
||||
"photoReceiptSubtitle": "Reconhecemos todos os produtos do recibo",
|
||||
"photoProducts": "Fotografar produtos",
|
||||
"photoProductsSubtitle": "Geladeira, mesa, prateleira — até 3 fotos"
|
||||
"photoProductsSubtitle": "Geladeira, mesa, prateleira — até 3 fotos",
|
||||
"addPackagedFood": "Adicionar alimento embalado",
|
||||
"scanBarcode": "Escanear código de barras",
|
||||
"portionWeightG": "Peso da porção (g)",
|
||||
"productNotFound": "Produto não encontrado",
|
||||
"enterManually": "Inserir manualmente",
|
||||
"perHundredG": "por 100 g"
|
||||
}
|
||||
|
||||
@@ -102,5 +102,11 @@
|
||||
"photoReceipt": "Сфотографировать чек",
|
||||
"photoReceiptSubtitle": "Распознаем все продукты из чека",
|
||||
"photoProducts": "Сфотографировать продукты",
|
||||
"photoProductsSubtitle": "Холодильник, стол, полка — до 3 фото"
|
||||
"photoProductsSubtitle": "Холодильник, стол, полка — до 3 фото",
|
||||
"addPackagedFood": "Добавить готовый продукт",
|
||||
"scanBarcode": "Сканировать штрихкод",
|
||||
"portionWeightG": "Вес порции (г)",
|
||||
"productNotFound": "Продукт не найден",
|
||||
"enterManually": "Ввести вручную",
|
||||
"perHundredG": "на 100 г"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"queuePosition": "位置 {position}",
|
||||
"@queuePosition": {
|
||||
"placeholders": {
|
||||
"position": { "type": "int" }
|
||||
"position": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing": "处理中...",
|
||||
@@ -102,5 +104,11 @@
|
||||
"photoReceipt": "拍摄收据",
|
||||
"photoReceiptSubtitle": "识别收据中的所有商品",
|
||||
"photoProducts": "拍摄食品",
|
||||
"photoProductsSubtitle": "冰箱、桌子、货架 — 最多3张照片"
|
||||
"photoProductsSubtitle": "冰箱、桌子、货架 — 最多3张照片",
|
||||
"addPackagedFood": "添加包装食品",
|
||||
"scanBarcode": "扫描条形码",
|
||||
"portionWeightG": "份量(克)",
|
||||
"productNotFound": "未找到产品",
|
||||
"enterManually": "手动输入",
|
||||
"perHundredG": "每100克"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user