mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-24 02:39:20 -05:00
moved food property to seperate component and re-used that for the recipe editor
This commit is contained in:
83
vue3/src/components/inputs/PropertiesEditor.vue
Normal file
83
vue3/src/components/inputs/PropertiesEditor.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<v-btn-group density="compact">
|
||||
<v-btn color="create" @click="properties.push({} as Property)" prepend-icon="$create">{{ $t('Add') }}</v-btn>
|
||||
<v-btn color="secondary" @click="addAllProperties" prepend-icon="fa-solid fa-list">{{ $t('AddAll') }}</v-btn>
|
||||
</v-btn-group>
|
||||
|
||||
<v-row class="d-none d-md-flex mt-2" v-for="p in properties" dense>
|
||||
<v-col cols="0" md="5">
|
||||
<v-number-input :step="10" v-model="p.propertyAmount" control-variant="stacked">
|
||||
<template #append-inner v-if="p.propertyType">
|
||||
<v-chip class="me-4">{{ p.propertyType.unit }} / {{ props.amountFor }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-number-input>
|
||||
</v-col>
|
||||
<v-col cols="0" md="6">
|
||||
<!-- TODO fix card overflow invisible, overflow-visible class is not working -->
|
||||
<model-select :label="$t('Property')" v-model="p.propertyType" model="PropertyType"></model-select>
|
||||
</v-col>
|
||||
<v-col cols="0" md="1">
|
||||
<v-btn color="delete" @click="deleteProperty(p)">
|
||||
<v-icon icon="$delete"></v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-list class="d-md-none">
|
||||
<v-list-item v-for="p in properties" border>
|
||||
<span v-if="p.propertyType">{{ p.propertyAmount }} {{ p.propertyType.unit }} {{ p.propertyType.name }} / {{ props.amountFor }}
|
||||
</span>
|
||||
<span v-else><i><{{ $t('New') }}></i></span>
|
||||
<template #append>
|
||||
<v-btn color="edit">
|
||||
<v-icon icon="$edit"></v-icon>
|
||||
<model-edit-dialog model="Property" :item="p"></model-edit-dialog>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {ApiApi, Property} from "@/openapi";
|
||||
import {VNumberInput} from 'vuetify/labs/VNumberInput'
|
||||
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||
|
||||
const props = defineProps({
|
||||
amountFor: {type: String, required: true}
|
||||
})
|
||||
|
||||
const properties = defineModel<Property[]>({required: true})
|
||||
|
||||
/**
|
||||
* remove a property from the list
|
||||
* @param property property to delete
|
||||
*/
|
||||
function deleteProperty(property: Property) {
|
||||
properties.value = properties.value.filter(p => p !== property)
|
||||
// TODO delete from DB, needs endpoint for property relation to either recipe or food
|
||||
}
|
||||
|
||||
/**
|
||||
* load list of property types from server and add all types that are not yet
|
||||
* in the list to the list
|
||||
*/
|
||||
function addAllProperties() {
|
||||
const api = new ApiApi()
|
||||
api.apiPropertyTypeList().then(r => {
|
||||
r.results.forEach(pt => {
|
||||
if (properties.value.findIndex(x => x.propertyType.name == pt.name) == -1) {
|
||||
properties.value.push({propertyAmount: 0, propertyType: pt} as Property)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -108,7 +108,7 @@
|
||||
<v-card>
|
||||
<v-closable-card-title :title="$t('Ingredients')" v-model="dialogIngredientParser"></v-closable-card-title>
|
||||
<v-card-text>
|
||||
<v-textarea v-model="ingredientTextInput"></v-textarea>
|
||||
<v-textarea v-model="ingredientTextInput" :placeholder="$t('paste_ingredients_placeholder')"></v-textarea>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn @click="parseAndInsertIngredients()" color="save">{{ $t('Add') }}</v-btn>
|
||||
|
||||
@@ -34,46 +34,7 @@
|
||||
<v-number-input :label="$t('Properties_Food_Amount')" v-model="editingObj.propertiesFoodAmount"></v-number-input>
|
||||
<model-select :label="$t('Properties_Food_Unit')" v-model="editingObj.propertiesFoodUnit" model="Unit"></model-select>
|
||||
|
||||
<v-btn-group density="compact">
|
||||
<v-btn color="create" @click="editingObj.properties.push({} as Property)" prepend-icon="$create">{{ $t('Add') }}</v-btn>
|
||||
<v-btn color="secondary" @click="addAllProperties" prepend-icon="fa-solid fa-list">{{ $t('AddAll') }}</v-btn>
|
||||
</v-btn-group>
|
||||
|
||||
<v-row class="d-none d-md-flex mt-2" v-for="p in editingObj.properties" dense>
|
||||
<v-col cols="0" md="5">
|
||||
<v-number-input :step="10" v-model="p.propertyAmount" control-variant="stacked">
|
||||
<template #append-inner v-if="p.propertyType">
|
||||
<v-chip class="me-4">{{ p.propertyType.unit }} / {{ editingObj.propertiesFoodAmount }} <span v-if="editingObj.propertiesFoodUnit"> {{
|
||||
editingObj.propertiesFoodUnit.name
|
||||
}}</span>
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-number-input>
|
||||
</v-col>
|
||||
<v-col cols="0" md="6">
|
||||
<!-- TODO fix card overflow invisible, overflow-visible class is not working -->
|
||||
<model-select :label="$t('Property')" v-model="p.propertyType" model="PropertyType"></model-select>
|
||||
</v-col>
|
||||
<v-col cols="0" md="1">
|
||||
<v-btn color="delete" @click="deleteFoodProperty(p)">
|
||||
<v-icon icon="$delete"></v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-list class="d-md-none">
|
||||
<v-list-item v-for="p in editingObj.properties" border>
|
||||
<span v-if="p.propertyType">{{ p.propertyAmount }} {{ p.propertyType.unit }} {{ p.propertyType.name }}
|
||||
<span v-if="editingObj.propertiesFoodUnit"> / {{ editingObj.propertiesFoodAmount }} {{ editingObj.propertiesFoodUnit.name }}</span>
|
||||
</span>
|
||||
<span v-else><i><{{ $t('New') }}></i></span>
|
||||
<template #append>
|
||||
<v-btn color="edit">
|
||||
<v-icon icon="$edit"></v-icon>
|
||||
<model-edit-dialog model="Property" :item="p"></model-edit-dialog>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<properties-editor v-model="editingObj.properties" :amount-for="propertiesAmountFor"></properties-editor>
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
|
||||
@@ -153,7 +114,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import {onMounted, PropType, ref, watch} from "vue";
|
||||
import {computed, onMounted, PropType, ref, watch} from "vue";
|
||||
import {ApiApi, Food, Property, Unit, UnitConversion} from "@/openapi";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||
@@ -162,6 +123,7 @@ import {VNumberInput} from 'vuetify/labs/VNumberInput'
|
||||
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
|
||||
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
|
||||
import PropertiesEditor from "@/components/inputs/PropertiesEditor.vue";
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
@@ -175,6 +137,22 @@ const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading,
|
||||
|
||||
|
||||
// object specific data (for selects/display)
|
||||
|
||||
/**
|
||||
* compute label for the properties amount input to show user for
|
||||
* what amount of food a property is entered
|
||||
*/
|
||||
const propertiesAmountFor = computed(() => {
|
||||
let amountFor = ''
|
||||
if(editingObj.value.propertiesFoodAmount){
|
||||
amountFor += editingObj.value.propertiesFoodAmount
|
||||
}
|
||||
if(editingObj.value.propertiesFoodUnit){
|
||||
amountFor += " " + editingObj.value.propertiesFoodUnit.name
|
||||
}
|
||||
return amountFor
|
||||
})
|
||||
|
||||
const tab = ref("food")
|
||||
|
||||
const unitConversions = ref([] as UnitConversion[])
|
||||
@@ -220,30 +198,6 @@ async function saveObjectConversions() {
|
||||
// object specific functions
|
||||
// ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* load list of property types from server and add all types that are not yet linked
|
||||
* to the given food to its properties
|
||||
*/
|
||||
function addAllProperties() {
|
||||
const api = new ApiApi()
|
||||
api.apiPropertyTypeList().then(r => {
|
||||
r.results.forEach(pt => {
|
||||
if (editingObj.value.properties.findIndex(x => x.propertyType.name == pt.name) == -1) {
|
||||
editingObj.value.properties.push({propertyAmount: 0, propertyType: pt} as Property)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* remove property from food
|
||||
* //TODO also delete relation in database
|
||||
* @param property property to delete
|
||||
*/
|
||||
function deleteFoodProperty(property: Property) {
|
||||
editingObj.value.properties = editingObj.value.properties.filter(p => p !== property)
|
||||
}
|
||||
|
||||
/**
|
||||
* load conversions for currently editing food from API
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<v-tabs v-model="tab" :disabled="loading" grow>
|
||||
<v-tab value="recipe">{{ $t('Recipe') }}</v-tab>
|
||||
<v-tab value="steps">{{ $t('Steps') }}</v-tab>
|
||||
<v-tab value="properties">{{ $t('Properties') }}</v-tab>
|
||||
<v-tab value="settings">{{ $t('Settings') }}</v-tab>
|
||||
|
||||
</v-tabs>
|
||||
@@ -71,6 +72,12 @@
|
||||
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="properties">
|
||||
<v-form :disabled="loading">
|
||||
<v-alert class="mb-2" icon="$help">{{ $t('PropertiesFoodHelp') }}</v-alert>
|
||||
<properties-editor v-model="editingObj.properties" :amount-for="$t('Serving')"></properties-editor>
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="settings">
|
||||
<v-form :disabled="loading">
|
||||
<v-checkbox :label="$t('Ingredient Overview')" :hint="$t('show_ingredient_overview')" persistent-hint
|
||||
@@ -115,6 +122,7 @@ import {useI18n} from "vue-i18n";
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||
import StepEditor from "@/components/inputs/StepEditor.vue";
|
||||
import {VueDraggable} from "vue-draggable-plus";
|
||||
import PropertiesEditor from "@/components/inputs/PropertiesEditor.vue";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
|
||||
@@ -261,6 +261,7 @@
|
||||
"Select_File": "",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "",
|
||||
|
||||
@@ -254,6 +254,7 @@
|
||||
"Select_File": "Избери файл",
|
||||
"Selected": "Избрано",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Порции",
|
||||
"ServingsText": "",
|
||||
"Settings": "Настройки",
|
||||
|
||||
@@ -333,6 +333,7 @@
|
||||
"Select_File": "Seleccioneu arxiu",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "",
|
||||
|
||||
@@ -331,6 +331,7 @@
|
||||
"Select_File": "Vybrat soubor",
|
||||
"Selected": "Vybrané",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porce",
|
||||
"ServingsText": "",
|
||||
"Settings": "Nastavení",
|
||||
|
||||
@@ -313,6 +313,7 @@
|
||||
"Select_File": "Vælg fil",
|
||||
"Selected": "Valgt",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Serveringer",
|
||||
"ServingsText": "",
|
||||
"Settings": "Indstillinger",
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
"Private_Recipe_Help": "Dieses Rezept ist nur für dich und Personen mit denen du es geteilt hast sichtbar.",
|
||||
"Profile": "Profil",
|
||||
"Properties": "Eigenschaften",
|
||||
"PropertiesFoodHelp": "Jedes Lebensmittel kann Eigenschaften zugeordnet bekommen. Rezepte berechnen die Summe der Eigenschaften basierend auf den verwendeten Lebensmitteln und Ihren Mengen.",
|
||||
"PropertiesFoodHelp": "Eigenschaften können für Rezepte und Lebensmittel erfasst werden. Eigenschaften von Lebensmitteln werden entsprechend der Menge für das Rezept ausgerechnet und überschreiben die Rezepteigenschaften. ",
|
||||
"Properties_Food_Amount": "Eigenschaften: Lebensmittelmenge",
|
||||
"Properties_Food_Unit": "Nährwert Einheit",
|
||||
"Property": "Eigenschaft",
|
||||
@@ -336,6 +336,7 @@
|
||||
"Select_File": "Datei auswählen",
|
||||
"Selected": "Ausgewählt",
|
||||
"SelectedCategories": "Ausgewählte Kategorien",
|
||||
"Serving": "Portion",
|
||||
"Servings": "Portionen",
|
||||
"ServingsText": "Portionstext",
|
||||
"Settings": "Einstellungen",
|
||||
|
||||
@@ -305,6 +305,7 @@
|
||||
"Select_File": "Επιλογή αρχείου",
|
||||
"Selected": "Επιλεγμένο",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Μερίδες",
|
||||
"ServingsText": "",
|
||||
"Settings": "Ρυθμίσεις",
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
"Private_Recipe_Help": "Recipe is only shown to you and people its shared with.",
|
||||
"Profile": "Profile",
|
||||
"Properties": "Properties",
|
||||
"PropertiesFoodHelp": "Every food can have properties. Recipes calculate the properties automatically, based on the properties of their foods and the amount given in the ingredients.",
|
||||
"PropertiesFoodHelp": "Properties can be added to Recipes and Foods. Properties on Foods are calculated according based on their amount in the recipe and override the recipe properties.",
|
||||
"Properties_Food_Amount": "Properties Food Amount",
|
||||
"Properties_Food_Unit": "Properties Food Unit",
|
||||
"Property": "Property",
|
||||
@@ -335,6 +335,7 @@
|
||||
"Select_File": "Select File",
|
||||
"Selected": "Selected",
|
||||
"SelectedCategories": "Selected Categories",
|
||||
"Serving": "Serving",
|
||||
"Servings": "Servings",
|
||||
"ServingsText": "Servings Text",
|
||||
"Settings": "Settings",
|
||||
|
||||
@@ -332,6 +332,7 @@
|
||||
"Select_File": "Seleccionar archivo",
|
||||
"Selected": "Selecionado",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Raciones",
|
||||
"ServingsText": "",
|
||||
"Settings": "Opciones",
|
||||
|
||||
@@ -186,6 +186,7 @@
|
||||
"Select_File": "Valitse Tiedosto",
|
||||
"Selected": "Valittu",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Annokset",
|
||||
"ServingsText": "",
|
||||
"Settings": "Asetukset",
|
||||
|
||||
@@ -333,6 +333,7 @@
|
||||
"Select_File": "Sélectionner le fichier",
|
||||
"Selected": "Sélectionné",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Portions",
|
||||
"ServingsText": "",
|
||||
"Settings": "Paramètres",
|
||||
|
||||
@@ -334,6 +334,7 @@
|
||||
"Select_File": "בחר קובץ",
|
||||
"Selected": "נבחר",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "מנות",
|
||||
"ServingsText": "",
|
||||
"Settings": "הגדרות",
|
||||
|
||||
@@ -307,6 +307,7 @@
|
||||
"Select_File": "Fájl kiválasztása",
|
||||
"Selected": "Kiválasztott",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Adag",
|
||||
"ServingsText": "",
|
||||
"Settings": "Beállítások",
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
"Select_File": "Ընտրել Ֆայլ",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "Կարգավորումներ",
|
||||
|
||||
@@ -283,6 +283,7 @@
|
||||
"Select_File": "Pilih Buku",
|
||||
"Selected": "Terpilih",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porsi",
|
||||
"ServingsText": "",
|
||||
"Settings": "Pengaturan",
|
||||
|
||||
@@ -333,6 +333,7 @@
|
||||
"Select_File": "",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "",
|
||||
|
||||
@@ -291,6 +291,7 @@
|
||||
"Select_File": "Seleziona file",
|
||||
"Selected": "Selezionato",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porzioni",
|
||||
"ServingsText": "",
|
||||
"Settings": "Impostazioni",
|
||||
|
||||
@@ -311,6 +311,7 @@
|
||||
"Select_File": "Pasirinkti Failą",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "",
|
||||
|
||||
@@ -303,6 +303,7 @@
|
||||
"Select_File": "Velg fil",
|
||||
"Selected": "Valgte",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porsjoner",
|
||||
"ServingsText": "",
|
||||
"Settings": "Innstillinger",
|
||||
|
||||
@@ -307,6 +307,7 @@
|
||||
"Select_File": "Selecteer Bestand",
|
||||
"Selected": "Geselecteerd",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porties",
|
||||
"ServingsText": "",
|
||||
"Settings": "Instellingen",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"Select_File": "Wybierz plik",
|
||||
"Selected": "Wybrane",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porcje",
|
||||
"ServingsText": "",
|
||||
"Settings": "Ustawienia",
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
"Select_File": "Selecionar Ficheiro",
|
||||
"Selected": "Selecionado",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Doses",
|
||||
"ServingsText": "",
|
||||
"Settings": "Definições",
|
||||
|
||||
@@ -322,6 +322,7 @@
|
||||
"Select_File": "Selecionar Arquivo",
|
||||
"Selected": "Selecionado",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porções",
|
||||
"ServingsText": "",
|
||||
"Settings": "Configurações",
|
||||
|
||||
@@ -295,6 +295,7 @@
|
||||
"Select_File": "Selectare fișier",
|
||||
"Selected": "Selectat",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porții",
|
||||
"ServingsText": "",
|
||||
"Settings": "Setări",
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
"Select_File": "Выбрать файл",
|
||||
"Selected": "Выбрать",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Порции",
|
||||
"ServingsText": "",
|
||||
"Settings": "Настройки",
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
"Select_File": "Izberi datoteko",
|
||||
"Selected": "Izbrano",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Porcije",
|
||||
"ServingsText": "",
|
||||
"Settings": "Nastavitve",
|
||||
|
||||
@@ -335,6 +335,7 @@
|
||||
"Select_File": "Välj fil",
|
||||
"Selected": "Vald",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Portioner",
|
||||
"ServingsText": "",
|
||||
"Settings": "Inställningar",
|
||||
|
||||
@@ -334,6 +334,7 @@
|
||||
"Select_File": "Dosya Seç",
|
||||
"Selected": "Seçilen",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Servis Sayısı",
|
||||
"ServingsText": "",
|
||||
"Settings": "Ayarlar",
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
"Select_File": "Вибрати Файл",
|
||||
"Selected": "Вибрано",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "Порції",
|
||||
"ServingsText": "",
|
||||
"Settings": "Налаштування",
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
"Select_File": "选择文件",
|
||||
"Selected": "选定",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "份量",
|
||||
"ServingsText": "",
|
||||
"Settings": "设置",
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
"Select_File": "選擇檔案",
|
||||
"Selected": "",
|
||||
"SelectedCategories": "",
|
||||
"Serving": "",
|
||||
"Servings": "",
|
||||
"ServingsText": "",
|
||||
"Settings": "",
|
||||
|
||||
Reference in New Issue
Block a user