mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-21 22:13:31 -07:00
Merge branch 'mealie-next' into mealie-next
This commit is contained in:
commit
55b66c9446
117 changed files with 4263 additions and 3773 deletions
|
@ -1,6 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
exclude: "mkdocs.yml"
|
||||
|
@ -12,7 +12,7 @@ repos:
|
|||
exclude: ^tests/data/
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.12.7
|
||||
rev: v0.12.8
|
||||
hooks:
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
|
|
|
@ -71,6 +71,7 @@ tasks:
|
|||
desc: run code generators
|
||||
cmds:
|
||||
- poetry run python dev/code-generation/main.py {{ .CLI_ARGS }}
|
||||
- task: docs:gen
|
||||
- task: py:format
|
||||
|
||||
dev:services:
|
||||
|
|
|
@ -8,8 +8,8 @@ from utils import log
|
|||
# ============================================================
|
||||
|
||||
template = """// This Code is auto generated by gen_ts_types.py
|
||||
{% for name in global %}import {{ name }} from "@/components/global/{{ name }}.vue";
|
||||
{% endfor %}{% for name in layout %}import {{ name }} from "@/components/layout/{{ name }}.vue";
|
||||
{% for name in global %}import type {{ name }} from "@/components/global/{{ name }}.vue";
|
||||
{% endfor %}{% for name in layout %}import type {{ name }} from "@/components/layout/{{ name }}.vue";
|
||||
{% endfor %}
|
||||
declare module "vue" {
|
||||
export interface GlobalComponents {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
###############################################
|
||||
# Frontend Build
|
||||
###############################################
|
||||
FROM node:20 AS frontend-builder
|
||||
FROM node:20@sha256:572a90df10a58ebb7d3f223d661d964a6c2383a9c2b5763162b4f631c53dc56a \
|
||||
AS frontend-builder
|
||||
|
||||
WORKDIR /frontend
|
||||
|
||||
|
@ -20,7 +21,8 @@ RUN yarn generate
|
|||
###############################################
|
||||
# Base Image - Python
|
||||
###############################################
|
||||
FROM python:3.12-slim AS python-base
|
||||
FROM python:3.12-slim@sha256:2267adc248a477c1f1a852a07a5a224d42abe54c28aafa572efa157dfb001bba \
|
||||
AS python-base
|
||||
|
||||
ENV MEALIE_HOME="/app"
|
||||
|
||||
|
@ -132,7 +134,7 @@ RUN apt-get update \
|
|||
gosu \
|
||||
iproute2 \
|
||||
libldap-common \
|
||||
libldap-2.5 \
|
||||
libldap2 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# create directory used for Docker Secrets
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -70,7 +70,7 @@ import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue"
|
|||
import { useCookbookStore } from "~/composables/store/use-cookbook-store";
|
||||
import { useCookbook } from "~/composables/use-group-cookbooks";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
import type { RecipeCookBook } from "~/lib/api/types/cookbook";
|
||||
import type { ReadCookBook } from "~/lib/api/types/cookbook";
|
||||
import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue";
|
||||
|
||||
const $auth = useMealieAuth();
|
||||
|
@ -100,7 +100,7 @@ const dialogStates = reactive({
|
|||
edit: false,
|
||||
});
|
||||
|
||||
const editTarget = ref<RecipeCookBook | null>(null);
|
||||
const editTarget = ref<ReadCookBook | null>(null);
|
||||
function handleEditCookbook() {
|
||||
dialogStates.edit = true;
|
||||
editTarget.value = book.value;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<v-list :class="tile ? 'd-flex flex-wrap background' : 'background'">
|
||||
<v-list :class="tile ? 'd-flex flex-wrap background' : 'background'" style="background-color: transparent;">
|
||||
<v-sheet
|
||||
v-for="recipe, index in recipes"
|
||||
:key="recipe.id"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="text"
|
||||
class="ml-2 handle"
|
||||
icon
|
||||
v-bind="props"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
v-model="listItem.checked"
|
||||
hide-details
|
||||
density="compact"
|
||||
class="mt-0"
|
||||
class="mt-0 flex-shrink-0"
|
||||
color="null"
|
||||
@change="$emit('checked', listItem)"
|
||||
/>
|
||||
|
@ -27,16 +27,6 @@
|
|||
</div>
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
<v-col
|
||||
v-if="label && showLabel"
|
||||
cols="3"
|
||||
class="text-right"
|
||||
>
|
||||
<MultiPurposeLabel
|
||||
:label="label"
|
||||
size="small"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="auto"
|
||||
class="text-right"
|
||||
|
@ -75,27 +65,6 @@
|
|||
</template>
|
||||
<span>Toggle Recipes</span>
|
||||
</v-tooltip>
|
||||
<!-- Dummy button so the spacing is consistent when labels are enabled -->
|
||||
<v-btn
|
||||
v-else
|
||||
size="small"
|
||||
variant="text"
|
||||
class="ml-2"
|
||||
icon
|
||||
disabled
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="text"
|
||||
class="ml-2 handle"
|
||||
icon
|
||||
v-bind="props"
|
||||
>
|
||||
<v-icon>
|
||||
{{ $globals.icons.arrowUpDown }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="text"
|
||||
|
@ -107,6 +76,17 @@
|
|||
{{ $globals.icons.edit }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="text"
|
||||
class="handle"
|
||||
icon
|
||||
v-bind="props"
|
||||
>
|
||||
<v-icon>
|
||||
{{ $globals.icons.arrowUpDown }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list density="compact">
|
||||
<v-list-item
|
||||
|
@ -177,7 +157,6 @@
|
|||
import { useOnline } from "@vueuse/core";
|
||||
import RecipeIngredientListItem from "../Recipe/RecipeIngredientListItem.vue";
|
||||
import ShoppingListItemEditor from "./ShoppingListItemEditor.vue";
|
||||
import MultiPurposeLabel from "./MultiPurposeLabel.vue";
|
||||
import type { ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import type { MultiPurposeLabelOut, MultiPurposeLabelSummary } from "~/lib/api/types/labels";
|
||||
import type { IngredientFood, IngredientUnit, RecipeSummary } from "~/lib/api/types/recipe";
|
||||
|
@ -189,16 +168,12 @@ interface actions {
|
|||
}
|
||||
|
||||
export default defineNuxtComponent({
|
||||
components: { ShoppingListItemEditor, MultiPurposeLabel, RecipeList, RecipeIngredientListItem },
|
||||
components: { ShoppingListItemEditor, RecipeList, RecipeIngredientListItem },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object as () => ShoppingListItemOut,
|
||||
required: true,
|
||||
},
|
||||
showLabel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
labels: {
|
||||
type: Array as () => MultiPurposeLabelOut[],
|
||||
required: true,
|
||||
|
@ -220,7 +195,7 @@ export default defineNuxtComponent({
|
|||
setup(props, context) {
|
||||
const i18n = useI18n();
|
||||
const displayRecipeRefs = ref(false);
|
||||
const itemLabelCols = ref<string>(props.modelValue.checked ? "auto" : props.showLabel ? "4" : "6");
|
||||
const itemLabelCols = ref<string>(props.modelValue.checked ? "auto" : "6");
|
||||
const isOffline = computed(() => useOnline().value === false);
|
||||
|
||||
const contextMenu: actions[] = [
|
||||
|
@ -305,7 +280,7 @@ export default defineNuxtComponent({
|
|||
}
|
||||
|
||||
listItem.value.recipeReferences.forEach((ref) => {
|
||||
const recipe = props.recipes.get(ref.recipeId);
|
||||
const recipe = props.recipes?.get(ref.recipeId);
|
||||
if (recipe) {
|
||||
recipeList.push(recipe);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
:name="inputField.varName"
|
||||
:disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))"
|
||||
:hint="inputField.hint"
|
||||
hide-details="auto"
|
||||
:hide-details="!inputField.hint"
|
||||
:persistent-hint="!!inputField.hint"
|
||||
density="comfortable"
|
||||
@change="emitBlur">
|
||||
<template #label>
|
||||
|
@ -45,7 +46,7 @@
|
|||
{{ inputField.label }}
|
||||
</span>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</v-checkbox>
|
||||
|
||||
<!-- Text Field -->
|
||||
<v-text-field
|
||||
|
@ -97,8 +98,8 @@
|
|||
:label="inputField.label"
|
||||
:name="inputField.varName"
|
||||
:items="inputField.options"
|
||||
:item-title="inputField.itemText"
|
||||
:item-value="inputField.itemValue"
|
||||
item-title="text"
|
||||
item-value="text"
|
||||
:return-object="false"
|
||||
:hint="inputField.hint"
|
||||
density="comfortable"
|
||||
|
@ -107,10 +108,11 @@
|
|||
@blur="emitBlur"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div>
|
||||
<v-list-item-title>{{ item.raw.text }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ item.raw.description }}</v-list-item-subtitle>
|
||||
</div>
|
||||
<v-list-item
|
||||
v-bind="props"
|
||||
:title="item.raw.text"
|
||||
:subtitle="item.raw.description"
|
||||
/>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import type { ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import { useCopyList } from "~/composables/use-copy";
|
||||
|
||||
type CopyTypes = "plain" | "markdown";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list copy functionality
|
||||
*/
|
||||
export function useShoppingListCopy() {
|
||||
const copy = useCopyList();
|
||||
|
||||
function copyListItems(itemsByLabel: { [key: string]: ShoppingListItemOut[] }, copyType: CopyTypes) {
|
||||
const text: string[] = [];
|
||||
Object.entries(itemsByLabel).forEach(([label, items], idx) => {
|
||||
if (idx) {
|
||||
text.push("");
|
||||
}
|
||||
|
||||
text.push(formatCopiedLabelHeading(copyType, label));
|
||||
items.forEach(item => text.push(formatCopiedListItem(copyType, item)));
|
||||
});
|
||||
|
||||
copy.copyPlain(text);
|
||||
}
|
||||
|
||||
function formatCopiedListItem(copyType: CopyTypes, item: ShoppingListItemOut): string {
|
||||
const display = item.display || "";
|
||||
switch (copyType) {
|
||||
case "markdown":
|
||||
return `- [ ] ${display}`;
|
||||
default:
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
function formatCopiedLabelHeading(copyType: CopyTypes, label: string): string {
|
||||
switch (copyType) {
|
||||
case "markdown":
|
||||
return `# ${label}`;
|
||||
default:
|
||||
return `[${label}]`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
copyListItems,
|
||||
formatCopiedListItem,
|
||||
formatCopiedLabelHeading,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
import type { ShoppingListOut, ShoppingListItemOut, ShoppingListMultiPurposeLabelOut } from "~/lib/api/types/household";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { uuid4 } from "~/composables/use-utils";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list item CRUD operations
|
||||
*/
|
||||
export function useShoppingListCrud(
|
||||
shoppingList: Ref<ShoppingListOut | null>,
|
||||
loadingCounter: Ref<number>,
|
||||
listItems: { unchecked: ShoppingListItemOut[]; checked: ShoppingListItemOut[] },
|
||||
shoppingListItemActions: any,
|
||||
refresh: () => void,
|
||||
sortCheckedItems: (a: ShoppingListItemOut, b: ShoppingListItemOut) => number,
|
||||
updateListItemOrder: () => void,
|
||||
) {
|
||||
const { t } = useI18n();
|
||||
const userApi = useUserApi();
|
||||
|
||||
const createListItemData = ref<ShoppingListItemOut>(listItemFactory());
|
||||
const localLabels = ref<ShoppingListMultiPurposeLabelOut[]>();
|
||||
|
||||
function listItemFactory(): ShoppingListItemOut {
|
||||
return {
|
||||
id: uuid4(),
|
||||
shoppingListId: shoppingList.value?.id || "",
|
||||
checked: false,
|
||||
position: shoppingList.value?.listItems?.length || 1,
|
||||
quantity: 0,
|
||||
note: "",
|
||||
labelId: undefined,
|
||||
unitId: undefined,
|
||||
foodId: undefined,
|
||||
} as ShoppingListItemOut;
|
||||
}
|
||||
|
||||
// Check/Uncheck All operations
|
||||
function checkAllItems() {
|
||||
let hasChanged = false;
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (!item.checked) {
|
||||
hasChanged = true;
|
||||
item.checked = true;
|
||||
}
|
||||
});
|
||||
if (hasChanged) {
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
}
|
||||
|
||||
function uncheckAllItems() {
|
||||
let hasChanged = false;
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (item.checked) {
|
||||
hasChanged = true;
|
||||
item.checked = false;
|
||||
}
|
||||
});
|
||||
if (hasChanged) {
|
||||
listItems.unchecked = [...listItems.unchecked, ...listItems.checked];
|
||||
listItems.checked = [];
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
}
|
||||
|
||||
function deleteCheckedItems() {
|
||||
const checked = shoppingList.value?.listItems?.filter(item => item.checked);
|
||||
|
||||
if (!checked || checked?.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
deleteListItems(checked);
|
||||
loadingCounter.value -= 1;
|
||||
refresh();
|
||||
}
|
||||
|
||||
function saveListItem(item: ShoppingListItemOut) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set a temporary updatedAt timestamp prior to refresh so it appears at the top of the checked items
|
||||
item.updatedAt = new Date().toISOString();
|
||||
|
||||
// make updates reflect immediately
|
||||
if (shoppingList.value.listItems) {
|
||||
shoppingList.value.listItems.forEach((oldListItem: ShoppingListItemOut, idx: number) => {
|
||||
if (oldListItem.id === item.id && shoppingList.value?.listItems) {
|
||||
shoppingList.value.listItems[idx] = item;
|
||||
}
|
||||
});
|
||||
// Immediately update checked/unchecked arrays for UI
|
||||
listItems.unchecked = shoppingList.value.listItems.filter(i => !i.checked);
|
||||
listItems.checked = shoppingList.value.listItems.filter(i => i.checked)
|
||||
.sort(sortCheckedItems);
|
||||
}
|
||||
|
||||
// Update the item if it's checked, otherwise updateUncheckedListItems will handle it
|
||||
if (item.checked) {
|
||||
shoppingListItemActions.updateItem(item);
|
||||
}
|
||||
|
||||
updateListItemOrder();
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
|
||||
function deleteListItem(item: ShoppingListItemOut) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
shoppingListItemActions.deleteItem(item);
|
||||
|
||||
// remove the item from the list immediately so the user sees the change
|
||||
if (shoppingList.value.listItems) {
|
||||
shoppingList.value.listItems = shoppingList.value.listItems.filter(itm => itm.id !== item.id);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
function deleteListItems(items: ShoppingListItemOut[]) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
shoppingListItemActions.deleteItem(item);
|
||||
});
|
||||
// remove the items from the list immediately so the user sees the change
|
||||
if (shoppingList.value?.listItems) {
|
||||
const deletedItems = new Set(items.map(item => item.id));
|
||||
shoppingList.value.listItems = shoppingList.value.listItems.filter(itm => !deletedItems.has(itm.id));
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
function createListItem() {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!createListItemData.value.foodId && !createListItemData.value.note) {
|
||||
// don't create an empty item
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
|
||||
// make sure it's inserted into the end of the list, which may have been updated
|
||||
createListItemData.value.position = shoppingList.value?.listItems?.length
|
||||
? (shoppingList.value.listItems.reduce((a, b) => (a.position || 0) > (b.position || 0) ? a : b).position || 0) + 1
|
||||
: 0;
|
||||
|
||||
createListItemData.value.createdAt = new Date().toISOString();
|
||||
createListItemData.value.updatedAt = createListItemData.value.createdAt;
|
||||
|
||||
updateListItemOrder();
|
||||
|
||||
shoppingListItemActions.createItem(createListItemData.value);
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (shoppingList.value.listItems) {
|
||||
// add the item to the list immediately so the user sees the change
|
||||
shoppingList.value.listItems.push(createListItemData.value);
|
||||
updateListItemOrder();
|
||||
}
|
||||
createListItemData.value = listItemFactory();
|
||||
refresh();
|
||||
}
|
||||
|
||||
function updateUncheckedListItems() {
|
||||
if (!shoppingList.value?.listItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set position for unchecked items
|
||||
listItems.unchecked.forEach((item: ShoppingListItemOut, idx: number) => {
|
||||
item.position = idx;
|
||||
shoppingListItemActions.updateItem(item);
|
||||
});
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
// Label management
|
||||
function updateLabelOrder(labelSettings: ShoppingListMultiPurposeLabelOut[]) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
labelSettings.forEach((labelSetting, index) => {
|
||||
labelSetting.position = index;
|
||||
return labelSetting;
|
||||
});
|
||||
|
||||
localLabels.value = labelSettings;
|
||||
}
|
||||
|
||||
function cancelLabelOrder() {
|
||||
loadingCounter.value -= 1;
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
// restore original state
|
||||
localLabels.value = shoppingList.value.labelSettings;
|
||||
}
|
||||
|
||||
async function saveLabelOrder(updateItemsByLabel: () => void) {
|
||||
if (!shoppingList.value || !localLabels.value || (localLabels.value === shoppingList.value.labelSettings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
const { data } = await userApi.shopping.lists.updateLabelSettings(shoppingList.value.id, localLabels.value);
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
// update shoppingList labels using the API response
|
||||
shoppingList.value.labelSettings = (data as ShoppingListOut).labelSettings;
|
||||
updateItemsByLabel();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleReorderLabelsDialog(reorderLabelsDialog: Ref<boolean>) {
|
||||
// stop polling and populate localLabels
|
||||
loadingCounter.value += 1;
|
||||
reorderLabelsDialog.value = !reorderLabelsDialog.value;
|
||||
localLabels.value = shoppingList.value?.labelSettings;
|
||||
}
|
||||
|
||||
// Context menu actions
|
||||
const contextActions = {
|
||||
delete: "delete",
|
||||
};
|
||||
|
||||
const contextMenu = [
|
||||
{ title: t("general.delete"), action: contextActions.delete },
|
||||
];
|
||||
|
||||
return {
|
||||
createListItemData,
|
||||
localLabels,
|
||||
listItemFactory,
|
||||
checkAllItems,
|
||||
uncheckAllItems,
|
||||
deleteCheckedItems,
|
||||
saveListItem,
|
||||
deleteListItem,
|
||||
deleteListItems,
|
||||
createListItem,
|
||||
updateUncheckedListItems,
|
||||
updateLabelOrder,
|
||||
cancelLabelOrder,
|
||||
saveLabelOrder,
|
||||
toggleReorderLabelsDialog,
|
||||
contextActions,
|
||||
contextMenu,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
import { useOnline, useIdle } from "@vueuse/core";
|
||||
import type { ShoppingListOut } from "~/lib/api/types/household";
|
||||
import { useShoppingListItemActions } from "~/composables/use-shopping-list-item-actions";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list data fetching and polling
|
||||
*/
|
||||
export function useShoppingListData(listId: string, shoppingList: Ref<ShoppingListOut | null>, loadingCounter: Ref<number>) {
|
||||
const isOffline = computed(() => useOnline().value === false);
|
||||
const { idle } = useIdle(5 * 60 * 1000); // 5 minutes
|
||||
const shoppingListItemActions = useShoppingListItemActions(listId);
|
||||
|
||||
async function fetchShoppingList() {
|
||||
const data = await shoppingListItemActions.getList();
|
||||
return data;
|
||||
}
|
||||
|
||||
async function refresh(updateListItemOrder: () => void) {
|
||||
loadingCounter.value += 1;
|
||||
try {
|
||||
await shoppingListItemActions.process();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
let newListValue: typeof shoppingList.value = null;
|
||||
try {
|
||||
newListValue = await fetchShoppingList();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
// only update the list with the new value if we're not loading, to prevent UI jitter
|
||||
if (loadingCounter.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent overwriting local changes with stale backend data when offline
|
||||
if (isOffline.value) {
|
||||
// Do not update shoppingList.value from backend when offline
|
||||
updateListItemOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not connected to the network, this will be null, so we don't want to clear the list
|
||||
if (newListValue) {
|
||||
shoppingList.value = newListValue;
|
||||
}
|
||||
|
||||
updateListItemOrder();
|
||||
}
|
||||
|
||||
// constantly polls for changes
|
||||
async function pollForChanges(updateListItemOrder: () => void) {
|
||||
// pause polling if the user isn't active or we're busy
|
||||
if (idle.value || loadingCounter.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await refresh(updateListItemOrder);
|
||||
|
||||
if (shoppingList.value) {
|
||||
attempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the refresh was unsuccessful, the shopping list will be null, so we increment the attempt counter
|
||||
attempts++;
|
||||
}
|
||||
catch {
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// if we hit too many errors, stop polling
|
||||
if (attempts >= maxAttempts) {
|
||||
clearInterval(pollTimer);
|
||||
}
|
||||
}
|
||||
|
||||
// start polling
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
// max poll time = pollFrequency * maxAttempts = 24 hours
|
||||
// we use a long max poll time since polling stops when the user is idle anyway
|
||||
const pollFrequency = 5000;
|
||||
const maxAttempts = 17280;
|
||||
let attempts = 0;
|
||||
let pollTimer: ReturnType<typeof setInterval>;
|
||||
|
||||
function startPolling(updateListItemOrder: () => void) {
|
||||
pollForChanges(updateListItemOrder); // populate initial list
|
||||
|
||||
pollTimer = setInterval(() => {
|
||||
pollForChanges(updateListItemOrder);
|
||||
}, pollFrequency);
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollTimer) {
|
||||
clearInterval(pollTimer);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isOffline,
|
||||
fetchShoppingList,
|
||||
refresh,
|
||||
startPolling,
|
||||
stopPolling,
|
||||
shoppingListItemActions,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import { useToggle } from "@vueuse/core";
|
||||
import type { ShoppingListOut, ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list label state and operations
|
||||
*/
|
||||
export function useShoppingListLabels(shoppingList: Ref<ShoppingListOut | null>) {
|
||||
const { t } = useI18n();
|
||||
const labelOpenState = ref<{ [key: string]: boolean }>({});
|
||||
const [showChecked, toggleShowChecked] = useToggle(false);
|
||||
|
||||
const initializeLabelOpenStates = () => {
|
||||
if (!shoppingList.value?.listItems) return;
|
||||
|
||||
const existingLabels = new Set(Object.keys(labelOpenState.value));
|
||||
let hasChanges = false;
|
||||
|
||||
for (const item of shoppingList.value.listItems) {
|
||||
const labelName = item.label?.name || t("shopping-list.no-label");
|
||||
if (!existingLabels.has(labelName) && !(labelName in labelOpenState.value)) {
|
||||
labelOpenState.value[labelName] = true;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
labelOpenState.value = { ...labelOpenState.value };
|
||||
}
|
||||
};
|
||||
|
||||
const labelNames = computed(() => {
|
||||
return new Set(
|
||||
shoppingList.value?.listItems
|
||||
?.map(item => item.label?.name || t("shopping-list.no-label"))
|
||||
.filter(Boolean) ?? [],
|
||||
);
|
||||
});
|
||||
|
||||
watch(labelNames, initializeLabelOpenStates, { immediate: true });
|
||||
|
||||
function toggleShowLabel(key: string) {
|
||||
labelOpenState.value[key] = !labelOpenState.value[key];
|
||||
}
|
||||
|
||||
function getLabelColor(item: ShoppingListItemOut | null) {
|
||||
return item?.label?.color;
|
||||
}
|
||||
|
||||
const presentLabels = computed(() => {
|
||||
const labels: Array<{ id: string; name: string }> = [];
|
||||
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (item.labelId && item.label) {
|
||||
labels.push({
|
||||
name: item.label.name,
|
||||
id: item.labelId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
});
|
||||
|
||||
return {
|
||||
labelOpenState,
|
||||
showChecked,
|
||||
toggleShowChecked,
|
||||
toggleShowLabel,
|
||||
getLabelColor,
|
||||
presentLabels,
|
||||
initializeLabelOpenStates,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import type { ShoppingListOut } from "~/lib/api/types/household";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list recipe references
|
||||
*/
|
||||
export function useShoppingListRecipes(
|
||||
shoppingList: Ref<ShoppingListOut | null>,
|
||||
loadingCounter: Ref<number>,
|
||||
recipeReferenceLoading: Ref<boolean>,
|
||||
refresh: () => void,
|
||||
) {
|
||||
const userApi = useUserApi();
|
||||
|
||||
async function addRecipeReferenceToList(recipeId: string) {
|
||||
if (!shoppingList.value || recipeReferenceLoading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
recipeReferenceLoading.value = true;
|
||||
const { data } = await userApi.shopping.lists.addRecipes(shoppingList.value.id, [{ recipeId }]);
|
||||
recipeReferenceLoading.value = false;
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
async function removeRecipeReferenceToList(recipeId: string) {
|
||||
if (!shoppingList.value || recipeReferenceLoading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
recipeReferenceLoading.value = true;
|
||||
const { data } = await userApi.shopping.lists.removeRecipe(shoppingList.value.id, recipeId);
|
||||
recipeReferenceLoading.value = false;
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
addRecipeReferenceToList,
|
||||
removeRecipeReferenceToList,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
import type { ShoppingListOut, ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
|
||||
interface ListItemGroup {
|
||||
position: number;
|
||||
createdAt: string;
|
||||
items: ShoppingListItemOut[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list item sorting and organization
|
||||
*/
|
||||
export function useShoppingListSorting() {
|
||||
const { t } = useI18n();
|
||||
|
||||
function sortItems(a: ShoppingListItemOut | ListItemGroup, b: ShoppingListItemOut | ListItemGroup) {
|
||||
// Sort by position ASC, then by createdAt ASC
|
||||
const posA = a.position ?? 0;
|
||||
const posB = b.position ?? 0;
|
||||
if (posA !== posB) {
|
||||
return posA - posB;
|
||||
}
|
||||
const createdA = a.createdAt ?? "";
|
||||
const createdB = b.createdAt ?? "";
|
||||
if (createdA !== createdB) {
|
||||
return createdA < createdB ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function groupAndSortListItemsByFood(shoppingList: ShoppingListOut) {
|
||||
if (!shoppingList?.listItems?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const checkedItemKey = "__checkedItem";
|
||||
const listItemGroupsMap = new Map<string, ListItemGroup>();
|
||||
listItemGroupsMap.set(checkedItemKey, { position: Number.MAX_SAFE_INTEGER, createdAt: "", items: [] });
|
||||
|
||||
// group items by checked status, food, or note
|
||||
shoppingList.listItems.forEach((item) => {
|
||||
const key = item.checked
|
||||
? checkedItemKey
|
||||
: item.food?.name
|
||||
? item.food.name
|
||||
: item.note || "";
|
||||
|
||||
const group = listItemGroupsMap.get(key);
|
||||
if (!group) {
|
||||
listItemGroupsMap.set(key, { position: item.position || 0, createdAt: item.createdAt || "", items: [item] });
|
||||
}
|
||||
else {
|
||||
group.items.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
const listItemGroups = Array.from(listItemGroupsMap.values());
|
||||
listItemGroups.sort(sortItems);
|
||||
|
||||
// sort group items, then aggregate them
|
||||
const sortedItems: ShoppingListItemOut[] = [];
|
||||
let nextPosition = 0;
|
||||
listItemGroups.forEach((listItemGroup) => {
|
||||
listItemGroup.items.sort(sortItems);
|
||||
listItemGroup.items.forEach((item) => {
|
||||
item.position = nextPosition;
|
||||
nextPosition += 1;
|
||||
sortedItems.push(item);
|
||||
});
|
||||
});
|
||||
|
||||
shoppingList.listItems = sortedItems;
|
||||
}
|
||||
|
||||
function sortListItems(shoppingList: ShoppingListOut) {
|
||||
if (!shoppingList?.listItems?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
shoppingList.listItems.sort(sortItems);
|
||||
}
|
||||
|
||||
function updateItemsByLabel(shoppingList: ShoppingListOut) {
|
||||
const items: { [prop: string]: ShoppingListItemOut[] } = {};
|
||||
const noLabelText = t("shopping-list.no-label");
|
||||
const noLabel = [] as ShoppingListItemOut[];
|
||||
|
||||
shoppingList?.listItems?.forEach((item) => {
|
||||
if (item.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.labelId) {
|
||||
if (item.label && item.label.name in items) {
|
||||
items[item.label.name].push(item);
|
||||
}
|
||||
else if (item.label) {
|
||||
items[item.label.name] = [item];
|
||||
}
|
||||
}
|
||||
else {
|
||||
noLabel.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
if (noLabel.length > 0) {
|
||||
items[noLabelText] = noLabel;
|
||||
}
|
||||
|
||||
// sort the map by label order
|
||||
const orderedLabelNames = shoppingList?.labelSettings?.map(labelSetting => labelSetting.label.name);
|
||||
if (!orderedLabelNames) {
|
||||
return items;
|
||||
}
|
||||
|
||||
const itemsSorted: { [prop: string]: ShoppingListItemOut[] } = {};
|
||||
if (noLabelText in items) {
|
||||
itemsSorted[noLabelText] = items[noLabelText];
|
||||
}
|
||||
|
||||
orderedLabelNames.forEach((labelName) => {
|
||||
if (labelName in items) {
|
||||
itemsSorted[labelName] = items[labelName];
|
||||
}
|
||||
});
|
||||
|
||||
return itemsSorted;
|
||||
}
|
||||
|
||||
return {
|
||||
sortItems,
|
||||
groupAndSortListItemsByFood,
|
||||
sortListItems,
|
||||
updateItemsByLabel,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
import type { ShoppingListOut, ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
|
||||
/**
|
||||
* Composable for managing shopping list state and reactive data
|
||||
*/
|
||||
export function useShoppingListState() {
|
||||
const shoppingList = ref<ShoppingListOut | null>(null);
|
||||
const loadingCounter = ref(1);
|
||||
const recipeReferenceLoading = ref(false);
|
||||
const preserveItemOrder = ref(false);
|
||||
|
||||
// UI state
|
||||
const edit = ref(false);
|
||||
const threeDot = ref(false);
|
||||
const reorderLabelsDialog = ref(false);
|
||||
const createEditorOpen = ref(false);
|
||||
|
||||
// Dialog states
|
||||
const state = reactive({
|
||||
checkAllDialog: false,
|
||||
uncheckAllDialog: false,
|
||||
deleteCheckedDialog: false,
|
||||
});
|
||||
|
||||
// Hydrate listItems from shoppingList.value?.listItems
|
||||
const listItems = reactive({
|
||||
unchecked: [] as ShoppingListItemOut[],
|
||||
checked: [] as ShoppingListItemOut[],
|
||||
});
|
||||
|
||||
function sortCheckedItems(a: ShoppingListItemOut, b: ShoppingListItemOut) {
|
||||
if (a.updatedAt! === b.updatedAt!) {
|
||||
return ((a.position || 0) > (b.position || 0)) ? -1 : 1;
|
||||
}
|
||||
return a.updatedAt! < b.updatedAt! ? 1 : -1;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => shoppingList.value?.listItems,
|
||||
(items) => {
|
||||
listItems.unchecked = (items?.filter(item => !item.checked) ?? []);
|
||||
listItems.checked = (items?.filter(item => item.checked)
|
||||
.sort(sortCheckedItems) ?? []);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const recipeMap = computed(() => new Map(
|
||||
(shoppingList.value?.recipeReferences?.map(ref => ref.recipe) ?? [])
|
||||
.map(recipe => [recipe.id || "", recipe])),
|
||||
);
|
||||
|
||||
const recipeList = computed(() => Array.from(recipeMap.value.values()));
|
||||
|
||||
return {
|
||||
shoppingList,
|
||||
loadingCounter,
|
||||
recipeReferenceLoading,
|
||||
preserveItemOrder,
|
||||
edit,
|
||||
threeDot,
|
||||
reorderLabelsDialog,
|
||||
createEditorOpen,
|
||||
state,
|
||||
listItems,
|
||||
recipeMap,
|
||||
recipeList,
|
||||
sortCheckedItems,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
import type { ShoppingListItemOut } from "~/lib/api/types/household";
|
||||
import { useShoppingListState } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-state";
|
||||
import { useShoppingListData } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-data";
|
||||
import { useShoppingListSorting } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-sorting";
|
||||
import { useShoppingListLabels } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-labels";
|
||||
import { useShoppingListCopy } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-copy";
|
||||
import { useShoppingListCrud } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-crud";
|
||||
import { useShoppingListRecipes } from "~/composables/shopping-list-page/sub-composables/use-shopping-list-recipes";
|
||||
|
||||
/**
|
||||
* Main composable that orchestrates all shopping list page functionality
|
||||
*/
|
||||
export function useShoppingListPage(listId: string) {
|
||||
// Initialize state
|
||||
const state = useShoppingListState();
|
||||
const {
|
||||
shoppingList,
|
||||
loadingCounter,
|
||||
recipeReferenceLoading,
|
||||
preserveItemOrder,
|
||||
listItems,
|
||||
sortCheckedItems,
|
||||
} = state;
|
||||
|
||||
// Initialize sorting functionality
|
||||
const sorting = useShoppingListSorting();
|
||||
const { groupAndSortListItemsByFood, sortListItems, updateItemsByLabel } = sorting;
|
||||
|
||||
// Track items organized by label
|
||||
const itemsByLabel = ref<{ [key: string]: ShoppingListItemOut[] }>({});
|
||||
|
||||
function updateListItemOrder() {
|
||||
if (!shoppingList.value) return;
|
||||
|
||||
if (!preserveItemOrder.value) {
|
||||
groupAndSortListItemsByFood(shoppingList.value);
|
||||
}
|
||||
else {
|
||||
sortListItems(shoppingList.value);
|
||||
}
|
||||
|
||||
const labeledItems = updateItemsByLabel(shoppingList.value);
|
||||
if (labeledItems) {
|
||||
itemsByLabel.value = labeledItems;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize data management
|
||||
const dataManager = useShoppingListData(listId, shoppingList, loadingCounter);
|
||||
const { isOffline, refresh: baseRefresh, startPolling, stopPolling, shoppingListItemActions } = dataManager;
|
||||
|
||||
const refresh = () => baseRefresh(updateListItemOrder);
|
||||
|
||||
// Initialize shopping list labels
|
||||
const labels = useShoppingListLabels(shoppingList);
|
||||
|
||||
// Initialize copy functionality
|
||||
const copyManager = useShoppingListCopy();
|
||||
|
||||
// Initialize CRUD operations
|
||||
const crud = useShoppingListCrud(
|
||||
shoppingList,
|
||||
loadingCounter,
|
||||
listItems,
|
||||
shoppingListItemActions,
|
||||
refresh,
|
||||
sortCheckedItems,
|
||||
updateListItemOrder,
|
||||
);
|
||||
|
||||
// Initialize recipe management
|
||||
const recipes = useShoppingListRecipes(
|
||||
shoppingList,
|
||||
loadingCounter,
|
||||
recipeReferenceLoading,
|
||||
refresh,
|
||||
);
|
||||
|
||||
// Handle item reordering by label
|
||||
function updateIndexUncheckedByLabel(labelName: string, labeledUncheckedItems: ShoppingListItemOut[]) {
|
||||
if (!itemsByLabel.value[labelName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update this label's item order
|
||||
itemsByLabel.value[labelName] = labeledUncheckedItems;
|
||||
|
||||
// reset list order of all items
|
||||
const allUncheckedItems: ShoppingListItemOut[] = [];
|
||||
for (const labelKey in itemsByLabel.value) {
|
||||
allUncheckedItems.push(...itemsByLabel.value[labelKey]);
|
||||
}
|
||||
|
||||
// since the user has manually reordered the list, we should preserve this order
|
||||
preserveItemOrder.value = true;
|
||||
|
||||
// save changes
|
||||
listItems.unchecked = allUncheckedItems;
|
||||
listItems.checked = shoppingList.value?.listItems?.filter(item => item.checked) || [];
|
||||
crud.updateUncheckedListItems();
|
||||
}
|
||||
|
||||
// Dialog helpers
|
||||
function openCheckAll() {
|
||||
if (shoppingList.value?.listItems?.some(item => !item.checked)) {
|
||||
state.state.checkAllDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function openUncheckAll() {
|
||||
if (shoppingList.value?.listItems?.some(item => item.checked)) {
|
||||
state.state.uncheckAllDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function openDeleteChecked() {
|
||||
if (shoppingList.value?.listItems?.some(item => item.checked)) {
|
||||
state.state.deleteCheckedDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
state.state.checkAllDialog = false;
|
||||
crud.checkAllItems();
|
||||
}
|
||||
|
||||
function uncheckAll() {
|
||||
state.state.uncheckAllDialog = false;
|
||||
crud.uncheckAllItems();
|
||||
}
|
||||
|
||||
function deleteChecked() {
|
||||
state.state.deleteCheckedDialog = false;
|
||||
crud.deleteCheckedItems();
|
||||
}
|
||||
|
||||
// Copy functionality wrapper
|
||||
function copyListItems(copyType: "plain" | "markdown") {
|
||||
copyManager.copyListItems(itemsByLabel.value, copyType);
|
||||
}
|
||||
|
||||
// Label reordering helpers
|
||||
function toggleReorderLabelsDialog() {
|
||||
crud.toggleReorderLabelsDialog(state.reorderLabelsDialog);
|
||||
}
|
||||
|
||||
async function saveLabelOrder() {
|
||||
await crud.saveLabelOrder(() => {
|
||||
const labeledItems = updateItemsByLabel(shoppingList.value!);
|
||||
if (labeledItems) {
|
||||
itemsByLabel.value = labeledItems;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Lifecycle management
|
||||
onMounted(() => {
|
||||
startPolling(updateListItemOrder);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stopPolling();
|
||||
});
|
||||
|
||||
return {
|
||||
itemsByLabel,
|
||||
isOffline,
|
||||
|
||||
// Sub-composables
|
||||
...state,
|
||||
...labels,
|
||||
...crud,
|
||||
...recipes,
|
||||
|
||||
// Specialized functions
|
||||
updateIndexUncheckedByLabel,
|
||||
copyListItems,
|
||||
|
||||
// Dialog actions
|
||||
openCheckAll,
|
||||
openUncheckAll,
|
||||
openDeleteChecked,
|
||||
checkAll,
|
||||
uncheckAll,
|
||||
deleteChecked,
|
||||
|
||||
// Label management
|
||||
toggleReorderLabelsDialog,
|
||||
saveLabelOrder,
|
||||
|
||||
// Data refresh
|
||||
refresh,
|
||||
};
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
import type { Composer } from "vue-i18n";
|
||||
import { useReadOnlyStore, useStore } from "../partials/use-store-factory";
|
||||
import type { RecipeCookBook } from "~/lib/api/types/cookbook";
|
||||
import type { ReadCookBook } from "~/lib/api/types/cookbook";
|
||||
import { usePublicExploreApi, useUserApi } from "~/composables/api";
|
||||
|
||||
const store: Ref<RecipeCookBook[]> = ref([]);
|
||||
const store: Ref<ReadCookBook[]> = ref([]);
|
||||
const loading = ref(false);
|
||||
const publicLoading = ref(false);
|
||||
|
||||
export const useCookbookStore = function (i18n?: Composer) {
|
||||
const api = useUserApi(i18n);
|
||||
return useStore<RecipeCookBook>(store, loading, api.cookbooks);
|
||||
return useStore<ReadCookBook>(store, loading, api.cookbooks);
|
||||
};
|
||||
|
||||
export const usePublicCookbookStore = function (groupSlug: string, i18n?: Composer) {
|
||||
const api = usePublicExploreApi(groupSlug, i18n).explore;
|
||||
return useReadOnlyStore<RecipeCookBook>(store, publicLoading, api.cookbooks);
|
||||
return useReadOnlyStore<ReadCookBook>(store, publicLoading, api.cookbooks);
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Svenska (Swedish)",
|
||||
value: "sv-SE",
|
||||
progress: 50,
|
||||
progress: 52,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Pусский (Russian)",
|
||||
value: "ru-RU",
|
||||
progress: 37,
|
||||
progress: 38,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Português do Brasil (Brazilian Portuguese)",
|
||||
value: "pt-BR",
|
||||
progress: 36,
|
||||
progress: 40,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
@ -105,7 +105,7 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Lietuvių (Lithuanian)",
|
||||
value: "lt-LT",
|
||||
progress: 27,
|
||||
progress: 26,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
@ -153,13 +153,13 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Galego (Galician)",
|
||||
value: "gl-ES",
|
||||
progress: 38,
|
||||
progress: 39,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
name: "Français (French)",
|
||||
value: "fr-FR",
|
||||
progress: 50,
|
||||
progress: 52,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
@ -219,7 +219,7 @@ export const LOCALES = [
|
|||
{
|
||||
name: "Dansk (Danish)",
|
||||
value: "da-DK",
|
||||
progress: 39,
|
||||
progress: 40,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { AutoFormItems } from "~/types/auto-forms";
|
|||
export const useCommonSettingsForm = () => {
|
||||
const i18n = useI18n();
|
||||
|
||||
const commonSettingsForm: AutoFormItems = [
|
||||
const commonSettingsForm = computed<AutoFormItems>(() => [
|
||||
{
|
||||
section: i18n.t("profile.group-settings"),
|
||||
label: i18n.t("group.enable-public-access"),
|
||||
|
@ -21,7 +21,7 @@ export const useCommonSettingsForm = () => {
|
|||
type: fieldTypes.BOOLEAN,
|
||||
rules: ["required"],
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
return {
|
||||
commonSettingsForm,
|
||||
|
|
|
@ -33,7 +33,6 @@ export interface UserRecipePreferences {
|
|||
|
||||
export interface UserShoppingListPreferences {
|
||||
viewAllLists: boolean;
|
||||
viewByLabel: boolean;
|
||||
}
|
||||
|
||||
export interface UserTimelinePreferences {
|
||||
|
@ -129,7 +128,6 @@ export function useShoppingListPreferences(): Ref<UserShoppingListPreferences> {
|
|||
"shopping-list-preferences",
|
||||
{
|
||||
viewAllLists: false,
|
||||
viewByLabel: true,
|
||||
},
|
||||
{ mergeDefaults: true },
|
||||
// we cast to a Ref because by default it will return an optional type ref
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useAsyncValidator } from "~/composables/use-validators";
|
||||
import type { VForm } from "~/types/vuetify";
|
||||
import type { VForm } from "~/types/auto-forms";
|
||||
import { usePublicApi } from "~/composables/api/api-client";
|
||||
|
||||
const domAccountForm = ref<VForm | null>(null);
|
||||
|
@ -13,12 +13,14 @@ const advancedOptions = ref(false);
|
|||
export const useUserRegistrationForm = () => {
|
||||
const i18n = useI18n();
|
||||
|
||||
function safeValidate(form: Ref<VForm | null>) {
|
||||
if (form.value && form.value.validate) {
|
||||
return form.value.validate();
|
||||
}
|
||||
async function safeValidate(form: Ref<VForm | null>) {
|
||||
if (!form.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const result = await form.value.validate();
|
||||
return result.valid;
|
||||
}
|
||||
// ================================================================
|
||||
// Provide Group Details
|
||||
const publicApi = usePublicApi();
|
||||
|
@ -45,11 +47,15 @@ export const useUserRegistrationForm = () => {
|
|||
email,
|
||||
advancedOptions,
|
||||
validate: async () => {
|
||||
if (!(validUsername.value && validEmail.value)) {
|
||||
if (!validUsername.value || !validEmail.value) {
|
||||
await Promise.all([validateUsername(), validateEmail()]);
|
||||
}
|
||||
|
||||
return (safeValidate(domAccountForm as Ref<VForm>) && validUsername.value && validEmail.value);
|
||||
if (!validUsername.value || !validEmail.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await safeValidate(domAccountForm as Ref<VForm>);
|
||||
},
|
||||
reset: () => {
|
||||
accountDetails.username.value = "";
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nuwe kennisgewing",
|
||||
"event-notifiers": "Gebeurteniskennisgewers",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (oorgeslaan indien leeg)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Aktiveer kennisgewer",
|
||||
"what-events": "Op watter gebeurtenisse moet hierdie kennisgewing inteken?",
|
||||
"user-events": "Gebruikersgebeurtenisse",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Merker gebeurtenisse",
|
||||
"category-events": "Kategorie Gebeurtenisse",
|
||||
"when-a-new-user-joins-your-group": "Wanneer 'n nuwe gebruiker by jou groep aansluit",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Add",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Groep besonderhede",
|
||||
"group-details-description": "Voordat jy 'n rekening skep, moet jy eers 'n groep skep. Jy sal die enigste lid van die groep wees, maar jy kan later ander nooi. Lede van jou groep kan maaltydplanne, inkopielyste, resepte en meer deel!",
|
||||
"use-seed-data": "Gebruik voorbeelddata",
|
||||
"use-seed-data-description": "Mealie bevat 'n versameling bestanddele, eenhede en etikette wat gebruik kan word om jou groep met nuttige data te vul om jou resepte te organiseer.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Rekening besonderhede"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "إشعار جديد",
|
||||
"event-notifiers": "إشعار الحدث",
|
||||
"apprise-url-skipped-if-blank": "الرابط Apprise (يتم تجاهله إذا ما كان فارغً)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "تفعيل الإشعارات",
|
||||
"what-events": "ما هي الأحداث التي يجب على هذا المخدم أن يستجيب لها؟",
|
||||
"user-events": "أحداث المستخدمين",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "أحداث الوسم",
|
||||
"category-events": "أحداث الفئة",
|
||||
"when-a-new-user-joins-your-group": "عندما ينضم مستخدم جديد إلى مجموعتك",
|
||||
"recipe-events": "وصفات المناسبات"
|
||||
"recipe-events": "وصفات المناسبات",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "أضف",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "مكونات إضافية",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "البحث عن الوصفات",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "تفاصيل المجموعة",
|
||||
"group-details-description": "قبل إنشاء حساب ستحتاج إلى إنشاء مجموعة. المجموعة الخاصة بك سوف تحتوي عليك فقط، ولكن ستتمكن من دعوة الآخرين لاحقاً. يمكن لأعضاء مجموعتك مشاركة خطط الوجبات وقوائم التسوق والوصفات، والمزيد!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie يأتي بمجموعة من الأطعمة والوحدات والعلامات التي يمكن استخدامها لتزويد مجموعتك ببيانات مفيدة لتنظيم وصفاتك.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "تفاصيل الحساب"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Ново известие",
|
||||
"event-notifiers": "Известия за събитие",
|
||||
"apprise-url-skipped-if-blank": "URL за известяване (пропуска се ако е празно)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Включи известията",
|
||||
"what-events": "За кои събития трябва да се получават известия?",
|
||||
"user-events": "Потребителски събития",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "История на етикетите",
|
||||
"category-events": "Събития за категория",
|
||||
"when-a-new-user-joins-your-group": "Когато потребител се присъедини към твоята потребителска група",
|
||||
"recipe-events": "Събития на рецептата"
|
||||
"recipe-events": "Събития на рецептата",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Добави",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Подробности за групата",
|
||||
"group-details-description": "Преди да създадете акаунт, ще трябва да създадете група. Вашата група ще съдържа само Вас, но ще можете да поканите други по-късно. Членовете във вашата група могат да споделят планове за хранене, списъци за пазаруване, рецепти и други!",
|
||||
"use-seed-data": "Използвай предварителни данни",
|
||||
"use-seed-data-description": "Mealie се доставя с колекция от продукти, мерни единици и етикети за попълване на Вашата група с полезни данни за организиране на рецептите.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Подробни данни за акаунта"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nova notificació",
|
||||
"event-notifiers": "Notificacions d'esdeveniments",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (si es deixa buit, s'ignorarà)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Habilita la notificació",
|
||||
"what-events": "Què esdeveniments vols que utilitzen aquest notificador?",
|
||||
"user-events": "Esdeveniments d'usuari",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Esdeveniments de les etiquetes",
|
||||
"category-events": "Esdeveniments de les categories",
|
||||
"when-a-new-user-joins-your-group": "Quan un nou usuari s'afegeix al grup",
|
||||
"recipe-events": "Esdeveniments de receptes"
|
||||
"recipe-events": "Esdeveniments de receptes",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Afegeix",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingredients addicionals",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Cercador de receptes",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalls del grup",
|
||||
"group-details-description": "Abans de crear un compte heu de crear un grup. Al grup només hi serà vostè, però després podeu convidar d'altres. Els membres d'un grup poden compartir menús, llistes de la compra, receptes i molt més!",
|
||||
"use-seed-data": "Afegiu dades predeterminades",
|
||||
"use-seed-data-description": "Mealie ve configurat amb una col·lecció d'aliments, unitats i etiquetes que poden ser emprades pel vostre grup per a ajudar-vos a organitzar les vostres receptes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalls del compte"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nové oznámení",
|
||||
"event-notifiers": "Notifikace událostí",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (přeskočeno pokud je prázdné)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Povolit notifikaci",
|
||||
"what-events": "K jakým událostem by se měl tento oznamovatel přihlásit?",
|
||||
"user-events": "Uživatelské události",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Události tagu",
|
||||
"category-events": "Události kategorie",
|
||||
"when-a-new-user-joins-your-group": "Když se nový uživatel připojí do vaší skupiny",
|
||||
"recipe-events": "Události receptu"
|
||||
"recipe-events": "Události receptu",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Přidat",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Další ingredience",
|
||||
"upload-another-image": "Nahrát další obrázek",
|
||||
"upload-images": "Nahrát obrázky",
|
||||
"upload-more-images": "Nahrát více obrázků"
|
||||
"upload-more-images": "Nahrát více obrázků",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Vyhledávač receptů",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Podrobnosti o skupině",
|
||||
"group-details-description": "Než vytvoříte svůj účet, musíte vytvořit skupinu. Vaše skupina bude obsahovat pouze vás, ale později budete moct přizvat jiné uživatele. Členové vaší skupiny mohou sdílet jídelníčky, nákupní seznamy, recepty a další!",
|
||||
"use-seed-data": "Použít Seed Data",
|
||||
"use-seed-data-description": "Mealie obsahuje kolekci potravin, jednotek a popisků, které můžete použít ve své skupině pro organizování svých receptů.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Podrobnosti účtu"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Ny notifikation",
|
||||
"event-notifiers": "Notifikation om begivenheder",
|
||||
"apprise-url-skipped-if-blank": "Informations link (sprunget over hvis ladet være tomt)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Aktiver Notifikationer",
|
||||
"what-events": "Hvilke begivenheder skal denne anmelder abonnere på?",
|
||||
"user-events": "Brugerhændelser",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tagbegivenheder",
|
||||
"category-events": "Kategoribegivenheder",
|
||||
"when-a-new-user-joins-your-group": "Når en ny bruger slutter sig til din gruppe",
|
||||
"recipe-events": "Hændelser for opskrifter"
|
||||
"recipe-events": "Hændelser for opskrifter",
|
||||
"label-events": "Navn på begivenheder"
|
||||
},
|
||||
"general": {
|
||||
"add": "Tilføj",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Yderligere ingredienser",
|
||||
"upload-another-image": "Upload et andet billede",
|
||||
"upload-images": "Upload billeder",
|
||||
"upload-more-images": "Upload flere billeder"
|
||||
"upload-more-images": "Upload flere billeder",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Opskriftssøger",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Gruppeoplysninger",
|
||||
"group-details-description": "Før du opretter en konto, skal du oprette en gruppe. Din gruppe vil kun indeholde dig, men du vil kunne invitere andre senere. Medlemmer i din gruppe kan dele madplaner, indkøbslister, opskrifter og meget mere!",
|
||||
"use-seed-data": "Anved standard data",
|
||||
"use-seed-data-description": "Mealie indeholder som standard en samling af fødevarer, enheder og etiketter, som du kan bruge til at oprette og organisere dine opskrifter.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Kontodetaljer"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Neue Benachrichtigung",
|
||||
"event-notifiers": "Ereignis-Benachrichtigungen",
|
||||
"apprise-url-skipped-if-blank": "Apprise-URL (wird übersprungen, wenn leer)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Benachrichtigen aktivieren",
|
||||
"what-events": "Welche Ereignisse soll diese Benachrichtigung abonnieren?",
|
||||
"user-events": "Benutzer-Ereignisse",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Schlagwort-Ereignisse",
|
||||
"category-events": "Kategorie-Ereignisse",
|
||||
"when-a-new-user-joins-your-group": "Wenn ein neuer Benutzer deiner Gruppe beitritt",
|
||||
"recipe-events": "Rezept-Ereignisse"
|
||||
"recipe-events": "Rezept-Ereignisse",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Hinzufügen",
|
||||
|
@ -672,11 +674,13 @@
|
|||
"not-linked-ingredients": "Zusätzliche Zutaten",
|
||||
"upload-another-image": "Weiteres Bild hochladen",
|
||||
"upload-images": "Bilder hochladen",
|
||||
"upload-more-images": "Weitere Bilder hochladen"
|
||||
"upload-more-images": "Weitere Bilder hochladen",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Rezept-Suche",
|
||||
"recipe-finder-description": "Suche nach Rezepten basierend auf den Zutaten, die du zur Hand hast. Sie können auch nach verfügbaren Werkzeugen filtern und eine maximale Anzahl an fehlenden Zutaten oder Werkzeugen festlegen.",
|
||||
"recipe-finder-description": "Suche nach Rezepten basierend auf den Zutaten, die du zur Hand hast. Du kannst auch nach verfügbaren Werkzeugen filtern und eine maximale Anzahl an fehlenden Zutaten oder Werkzeugen festlegen.",
|
||||
"selected-ingredients": "Ausgewählte Zutaten",
|
||||
"no-ingredients-selected": "Keine Zutaten ausgewählt",
|
||||
"missing": "Fehlend",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Gruppendetails",
|
||||
"group-details-description": "Bevor du ein Konto erstellst, musst du eine Gruppe erstellen. Deine Gruppe wird nur dich enthalten, aber du kannst andere später einladen. Mitglieder in deiner Gruppe können Essenspläne, Einkaufslisten, Rezepte und vieles mehr teilen!",
|
||||
"use-seed-data": "Musterdaten",
|
||||
"use-seed-data-description": "Mealie enthält eine Sammlung von Lebensmitteln, Maßeinheiten und Kategorien, die verwendet werden können, um deine Gruppe mit hilfreichen Daten für die Organisation deiner Rezepte zu füllen.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Kontoinformationen"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Νέα ειδοποίηση",
|
||||
"event-notifiers": "Ειδοποιητές Συμβάντος",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (παραλείπεται αν είναι κενό)",
|
||||
"apprise-url-is-left-intentionally-blank": "Δεδομένου ότι οι διευθύνσεις URL Apprise περιέχουν συνήθως ευαίσθητες πληροφορίες, το πεδίο αυτό παραμένει σκόπιμα κενό κατά την επεξεργασία. Αν θέλετε να ενημερώσετε το URL, παρακαλώ εισάγετε το νέο εδώ, αλλιώς αφήστε το κενό για να διατηρήσετε την τρέχουσα διεύθυνση URL.",
|
||||
"enable-notifier": "Ενεργοποίηση ειδοποιητή",
|
||||
"what-events": "Σε ποια συμβάντα θα πρέπει να εγγραφεί αυτός ο ειδοποιητής;",
|
||||
"user-events": "Συμβάντα Χρήστη",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Συμβάντα ετικέτας",
|
||||
"category-events": "Συμβάντα κατηγορίας",
|
||||
"when-a-new-user-joins-your-group": "Οταν ένας νέος χρήστης ενταχθεί στην ομάδα σας",
|
||||
"recipe-events": "Συμβάντα συνταγών"
|
||||
"recipe-events": "Συμβάντα συνταγών",
|
||||
"label-events": "Ετικέτα συμβάντων"
|
||||
},
|
||||
"general": {
|
||||
"add": "Προσθήκη",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Πρόσθετα συστατικά",
|
||||
"upload-another-image": "Ανέβασμα άλλης εικόνας",
|
||||
"upload-images": "Ανέβασμα εικόνων",
|
||||
"upload-more-images": "Ανέβασμα περισσότερων εικόνων"
|
||||
"upload-more-images": "Ανέβασμα περισσότερων εικόνων",
|
||||
"set-as-cover-image": "Ορισμός ως εικόνα εξώφυλλου συνταγής",
|
||||
"cover-image": "Εικόνα εξώφυλλου"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Εύρεση συνταγών",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Λεπτομέρειες ομάδας",
|
||||
"group-details-description": "Πριν δημιουργήσετε ένα λογαριασμό θα πρέπει να δημιουργήσετε μια ομάδα. Η ομάδα σας θα περιέχει μόνο εσάς, αλλά θα μπορείτε να προσκαλέσετε άλλους αργότερα. Μέλη της ομάδας σας μπορούν να μοιραστούν προγράμματα γευμάτων, λίστες για ψώνια, συνταγές και πολλά άλλα!",
|
||||
"use-seed-data": "Χρήση δεδομένων από τροφοδοσία",
|
||||
"use-seed-data-description": "Το Mealie έρχεται με μια συλλογή Τροφίμων, Μονάδων και Ετικετών που μπορούν να χρησιμοποιηθούν για τη συμπλήρωση της ομάδας σας με χρήσιμα δεδομένα για την οργάνωση των συνταγών σας.",
|
||||
"use-seed-data-description": "Το Mealie έρχεται με μια συλλογή Τροφίμων, Μονάδων και Ετικετών που μπορούν να χρησιμοποιηθούν για τη συμπλήρωση της ομάδας σας με χρήσιμα δεδομένα για την οργάνωση των συνταγών σας. Αυτά είναι μεταφρασμένα στη γλώσσα που έχετε επιλέξει. Μπορείτε πάντα να προσθέσετε ή να τροποποιήσετε αυτά τα δεδομένα αργότερα.",
|
||||
"account-details": "Λεπτομέρειες λογαριασμού"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "New Notification",
|
||||
"event-notifiers": "Event Notifiers",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (skipped if blank)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Enable Notifier",
|
||||
"what-events": "What events should this notifier subscribe to?",
|
||||
"user-events": "User Events",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tag Events",
|
||||
"category-events": "Category Events",
|
||||
"when-a-new-user-joins-your-group": "When a new user joins your group",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Add",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "New Notification",
|
||||
"event-notifiers": "Event Notifiers",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (skipped if blank)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Enable Notifier",
|
||||
"what-events": "What events should this notifier subscribe to?",
|
||||
"user-events": "User Events",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tag Events",
|
||||
"category-events": "Category Events",
|
||||
"when-a-new-user-joins-your-group": "When a new user joins your group",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Add",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nueva notificación",
|
||||
"event-notifiers": "Notificaciones de eventos",
|
||||
"apprise-url-skipped-if-blank": "URL de Apprise (omitida si está en blanco)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Habilitar notificador",
|
||||
"what-events": "¿A qué eventos debe suscribirse este notificador?",
|
||||
"user-events": "Eventos de los usuarios",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Eventos de etiqueta",
|
||||
"category-events": "Eventos de Categoría",
|
||||
"when-a-new-user-joins-your-group": "Cuando un nuevo usuario se une a tu grupo",
|
||||
"recipe-events": "Eventos de receta"
|
||||
"recipe-events": "Eventos de receta",
|
||||
"label-events": "Eventos de etiqueta"
|
||||
},
|
||||
"general": {
|
||||
"add": "Agregar",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingredientes adicionales",
|
||||
"upload-another-image": "Subir otra imagen",
|
||||
"upload-images": "Subir imágenes",
|
||||
"upload-more-images": "Subir más imágenes"
|
||||
"upload-more-images": "Subir más imágenes",
|
||||
"set-as-cover-image": "Establecer como imagen de portada de receta",
|
||||
"cover-image": "Imagen de portada"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Buscador de recetas",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalles del grupo",
|
||||
"group-details-description": "Antes de crear una cuenta, debe crear un grupo. En el grupo sólo estará usted, pero puede invitar a otros más tarde. Los miembros de un grupo pueden compartir menús, listas de la compra, recetas y más...",
|
||||
"use-seed-data": "Utilizar datos de ejemplo",
|
||||
"use-seed-data-description": "Mealie incluye una colección de alimentos, unidades y etiquetas, que puede utilizar como ejemplo en su grupo, para ayudarle a organizar sus recetas.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Información de la cuenta"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Uus teade",
|
||||
"event-notifiers": "Sündmuste märguanded",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (kui on tühi, jäetakse vahele)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Luba teavitaja",
|
||||
"what-events": "Millised sündmused peaks see teavitaja tellimaa?",
|
||||
"user-events": "Kasutaja sündmused",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Märksõna sündmused",
|
||||
"category-events": "Kategooria sündmused",
|
||||
"when-a-new-user-joins-your-group": "Kui uus kasutaja liitub sinu grupiga",
|
||||
"recipe-events": "Retsepti sündmused"
|
||||
"recipe-events": "Retsepti sündmused",
|
||||
"label-events": "Sildista sündmused"
|
||||
},
|
||||
"general": {
|
||||
"add": "Lisa",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Lisa-koostisosad",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Retsepti otsing",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Grupi detailid",
|
||||
"group-details-description": "Sa pead looma grupi enne konto loomist. Sinu grupis oled vaid sina, kuid sa saad kutsuda teisi sinna hiljem. Su grupi liikmed saavad jagada toitumisplaane, ostunimekirju, retsepte ja muud!",
|
||||
"use-seed-data": "Kasuta baasandmete infot.",
|
||||
"use-seed-data-description": "Mealsiga on kaasas toiduainete, ühikute ja siltide kogu, mida saate kasutada oma rühma täitmiseks kasuliku teabega retseptide korraldamiseks.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Konto üksikasjad"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Uusi ilmoitus",
|
||||
"event-notifiers": "Tapahtumien ilmoitukset",
|
||||
"apprise-url-skipped-if-blank": "Ilmoitusverkko-osoite (voi jättää tyhjäksi)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Ota ilmoittaja käyttöön",
|
||||
"what-events": "Mistä tapahtumista tulisi ilmoittaa?",
|
||||
"user-events": "Käyttäjän tapahtumat",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Valitse tapahtumat",
|
||||
"category-events": "Luokkatapahtumat",
|
||||
"when-a-new-user-joins-your-group": "Kun ryhmääsi liittyy uusi jäsen",
|
||||
"recipe-events": "Reseptitapahtumat"
|
||||
"recipe-events": "Reseptitapahtumat",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Lisää",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Muut ainesosat",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Reseptin etsijä",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Ryhmän tiedot",
|
||||
"group-details-description": "Ennen kuin luot tilin, sinun on luotava ryhmä. Ryhmässäsi on vain sinä, mutta voit kutsua muita myöhemmin. Ryhmäsi jäsenet voivat jakaa ateriasuunnitelmia, ostoslistoja, reseptejä ja paljon muuta!",
|
||||
"use-seed-data": "Käytä pohjatietoja",
|
||||
"use-seed-data-description": "Mealien mukana toimitetaan kokoelma elintarvikkeita, yksiköitä ja tarroja, joiden avulla voit täyttää ryhmäsi hyödyllisillä tiedoilla reseptien järjestämiseen.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Tilitiedot"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nouvelle notification",
|
||||
"event-notifiers": "Notifications d'événements",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (ignoré si vide)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activer la notification",
|
||||
"what-events": "À quels événements cette notification doit-elle s'abonner ?",
|
||||
"user-events": "Evénements utilisateur",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Événements des mots-clés",
|
||||
"category-events": "Événements de catégories",
|
||||
"when-a-new-user-joins-your-group": "Lorsqu'un nouvel utilisateur rejoint votre groupe",
|
||||
"recipe-events": "Événements de recette"
|
||||
"recipe-events": "Événements de recette",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Ajouter",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Commentaire",
|
||||
"comments": "Commentaires",
|
||||
"delete-confirmation": "Voulez-vous vraiment supprimer cette recette ?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Vous êtes sur le point de supprimer une recette qui n'est pas la vôtre en utilisant les permissions d'administrateur. Êtes-vous sûr(e) ?",
|
||||
"delete-recipe": "Supprimer la recette",
|
||||
"description": "Description",
|
||||
"disable-amount": "Désactiver les quantités des ingrédients",
|
||||
|
@ -587,7 +589,7 @@
|
|||
"api-extras-description": "Les suppléments des recettes sont une fonctionnalité clé de l’API Mealie. Ils permettent de créer des paires JSON clé/valeur personnalisées dans une recette, qui peuvent être référencées depuis des applications tierces. Ces clés peuvent être utilisées par exemple pour déclencher des tâches automatisées ou des messages personnalisés à transmettre à l’appareil souhaité.",
|
||||
"message-key": "Clé de message",
|
||||
"parse": "Analyser",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"ingredients-not-parsed-description": "Il semble que vos ingrédients ne soient pas encore analysés. Cliquez sur le bouton \"{parse}\" ci-dessous pour analyser vos ingrédients en aliments structurés.",
|
||||
"attach-images-hint": "Ajouter des images en les glissant-déposant dans l'éditeur",
|
||||
"drop-image": "Déposer l'image",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Activez les quantités d'ingrédients pour utiliser cette fonctionnalité",
|
||||
|
@ -664,15 +666,17 @@
|
|||
"no-unit": "Pas d'unité",
|
||||
"missing-unit": "Créer une unité manquante : {unit}",
|
||||
"missing-food": "Créer un aliment manquant : {food}",
|
||||
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||
"this-unit-could-not-be-parsed-automatically": "Cette unité n'a pas pu être analysée automatiquement",
|
||||
"this-food-could-not-be-parsed-automatically": "Cet aliment n'a pas pu être analysé automatiquement",
|
||||
"no-food": "Aucun aliment"
|
||||
},
|
||||
"reset-servings-count": "Réinitialiser le nombre de portions",
|
||||
"not-linked-ingredients": "Ingrédients supplémentaires",
|
||||
"upload-another-image": "Télécharger une autre image",
|
||||
"upload-images": "Télécharger des images",
|
||||
"upload-more-images": "Télécharger d'autres images"
|
||||
"upload-more-images": "Télécharger d'autres images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recherche de recette",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Détails du groupe",
|
||||
"group-details-description": "Avant de créer un compte, vous devrez créer un groupe. Votre groupe ne contiendra que vous, mais vous pourrez inviter d’autres personnes plus tard. Les membres de votre groupe peuvent partager leur menu de la semaine, leurs listes d’achat, leurs recettes et plus encore !",
|
||||
"use-seed-data": "Utiliser l'initialisation de données",
|
||||
"use-seed-data-description": "Mealie inclut avec une liste d’aliments, d’unités et d’étiquettes qui peut être utilisée pour initialiser votre groupe avec des données utiles pour organiser vos recettes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Détails du compte"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nouvelle notification",
|
||||
"event-notifiers": "Notifications d'événements",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (ignoré si vide)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activer la notification",
|
||||
"what-events": "À quels événements cette notification doit-elle s'abonner ?",
|
||||
"user-events": "Événements de l'utilisateur",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Événements des mots-clés",
|
||||
"category-events": "Événements de catégories",
|
||||
"when-a-new-user-joins-your-group": "Lorsqu'un nouvel utilisateur rejoint votre groupe",
|
||||
"recipe-events": "Événements de recette"
|
||||
"recipe-events": "Événements de recette",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Ajouter",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Commentaire",
|
||||
"comments": "Commentaires",
|
||||
"delete-confirmation": "Êtes-vous sûr(e) de vouloir supprimer cette recette?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Vous êtes sur le point de supprimer une recette qui n'est pas la vôtre en utilisant les permissions d'administrateur. Êtes-vous sûr(e) ?",
|
||||
"delete-recipe": "Supprimer la recette",
|
||||
"description": "Description",
|
||||
"disable-amount": "Désactiver les quantités d'ingrédients",
|
||||
|
@ -587,7 +589,7 @@
|
|||
"api-extras-description": "Les suppléments des recettes sont une fonctionnalité clé de l’API Mealie. Ils permettent de créer des paires JSON clé/valeur personnalisées dans une recette, qui peuvent être référencées depuis des applications tierces. Ces clés peuvent être utilisées par exemple pour déclencher des tâches automatisées ou des messages personnalisés à transmettre à l’appareil souhaité.",
|
||||
"message-key": "Clé de message",
|
||||
"parse": "Analyser",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"ingredients-not-parsed-description": "Il semble que vos ingrédients ne soient pas encore analysés. Cliquez sur le bouton \"{parse}\" ci-dessous pour analyser vos ingrédients en aliments structurés.",
|
||||
"attach-images-hint": "Ajouter des images en les glissant-déposant dans l'éditeur",
|
||||
"drop-image": "Déposer l'image",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Activez les quantités d'ingrédients pour utiliser cette fonctionnalité",
|
||||
|
@ -664,15 +666,17 @@
|
|||
"no-unit": "Pas d'unité",
|
||||
"missing-unit": "Créer une unité manquante : {unit}",
|
||||
"missing-food": "Créer un aliment manquant : {food}",
|
||||
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||
"this-unit-could-not-be-parsed-automatically": "Cette unité n'a pas pu être analysée automatiquement",
|
||||
"this-food-could-not-be-parsed-automatically": "Cet aliment n'a pas pu être analysé automatiquement",
|
||||
"no-food": "Aucun aliment"
|
||||
},
|
||||
"reset-servings-count": "Réinitialiser le nombre de portions",
|
||||
"not-linked-ingredients": "Ingrédients supplémentaires",
|
||||
"upload-another-image": "Télécharger une autre image",
|
||||
"upload-images": "Télécharger des images",
|
||||
"upload-more-images": "Télécharger d'autres images"
|
||||
"upload-more-images": "Télécharger d'autres images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recherche de recette",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Détails du groupe",
|
||||
"group-details-description": "Avant de créer un compte, vous devrez créer un groupe. Votre groupe ne contiendra que vous, mais vous pourrez inviter d’autres personnes plus tard. Les membres de votre groupe peuvent partager leur menu de la semaine, leurs listes d’achat, leurs recettes et plus encore !",
|
||||
"use-seed-data": "Utiliser l'initialisation de données",
|
||||
"use-seed-data-description": "Mealie inclut avec une liste d’aliments, d’unités et d’étiquettes qui peut être utilisée pour initialiser votre groupe avec des données utiles pour organiser vos recettes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Détails du compte"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nouvelle notification",
|
||||
"event-notifiers": "Notifications d'événements",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (ignoré si vide)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activer la notification",
|
||||
"what-events": "À quels événements cette notification doit-elle s'abonner ?",
|
||||
"user-events": "Événements utilisateur",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Événements des mots-clés",
|
||||
"category-events": "Événements de catégories",
|
||||
"when-a-new-user-joins-your-group": "Lorsqu'un nouvel utilisateur rejoint votre groupe",
|
||||
"recipe-events": "Événements de recette"
|
||||
"recipe-events": "Événements de recette",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Ajouter",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingrédients supplémentaires",
|
||||
"upload-another-image": "Télécharger une autre image",
|
||||
"upload-images": "Télécharger des images",
|
||||
"upload-more-images": "Télécharger d'autres images"
|
||||
"upload-more-images": "Télécharger d'autres images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recherche de recette",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Détails du groupe",
|
||||
"group-details-description": "Avant de créer un compte, vous devrez créer un groupe. Votre groupe ne contiendra que vous, mais vous pourrez inviter d’autres personnes plus tard. Les membres de votre groupe peuvent partager leur menu de la semaine, leurs listes d’achat, leurs recettes et plus encore !",
|
||||
"use-seed-data": "Utiliser l'initialisation de données",
|
||||
"use-seed-data-description": "Mealie inclut avec une liste d’aliments, d’unités et d’étiquettes qui peut être utilisée pour initialiser votre groupe avec des données utiles pour organiser vos recettes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Détails du compte"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nova Notificación",
|
||||
"event-notifiers": "Notificadores de Eventos",
|
||||
"apprise-url-skipped-if-blank": "URL de Apprise (omitido se está en branco)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activar o Notificador",
|
||||
"what-events": "A que eventos debería subscribirse este notificador?",
|
||||
"user-events": "Eventos de Usuario",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Eventos de Etiquetas",
|
||||
"category-events": "Eventos de Categorías",
|
||||
"when-a-new-user-joins-your-group": "Cando un novo usuario se une ao teu grupo",
|
||||
"recipe-events": "Eventos de Receitas"
|
||||
"recipe-events": "Eventos de Receitas",
|
||||
"label-events": "Rotular Eventos"
|
||||
},
|
||||
"general": {
|
||||
"add": "Engadir",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Comentario",
|
||||
"comments": "Comentarios",
|
||||
"delete-confirmation": "Estás seguro de que queres eliminar esta receita?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Estás a piques de eliminar unha receita que non é tua usando permisos de administrador. Tes certeza?",
|
||||
"delete-recipe": "Eliminar Receita",
|
||||
"description": "Descrición",
|
||||
"disable-amount": "Desactivar as Cantidades de Ingredientes",
|
||||
|
@ -580,14 +582,14 @@
|
|||
"made-this": "Eu fixen isto",
|
||||
"how-did-it-turn-out": "Que tal ficou?",
|
||||
"user-made-this": "{user} fixo isto",
|
||||
"added-to-timeline": "Added to timeline",
|
||||
"failed-to-add-to-timeline": "Failed to add to timeline",
|
||||
"failed-to-update-recipe": "Failed to update recipe",
|
||||
"added-to-timeline-but-failed-to-add-image": "Added to timeline, but failed to add image",
|
||||
"added-to-timeline": "Adicionado ao histórico",
|
||||
"failed-to-add-to-timeline": "Falla ao adicionar ao histórico",
|
||||
"failed-to-update-recipe": "Falla ao atualizar a receita",
|
||||
"added-to-timeline-but-failed-to-add-image": "Adicionado ao histórico, mas non foi posíbel adicionar a imaxe",
|
||||
"api-extras-description": "Os extras de receitas son unha característica clave da API de Mealie. Permítenche crear pares de clave/valor JSON personalizados dentro dunha receita, para facer referencia desde aplicacións de terceiros. Podes usar estas teclas para proporcionar información, por exemplo, para activar automatizacións ou mensaxes personalizadas para transmitir ao dispositivo que desexes.",
|
||||
"message-key": "Chave de Mensaxen",
|
||||
"parse": "Interpretar",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"ingredients-not-parsed-description": "Parece que os teus ingredientes ainda non foron procesados. Clique no boton \"{parse}\" abaixo para converte-los en alimentos estruturados.",
|
||||
"attach-images-hint": "Anexe imaxens arrastrando e soltandoas no editor",
|
||||
"drop-image": "Arrastrar imaxen",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Ative cantidades de ingredientes para usar esta funcionalidade",
|
||||
|
@ -638,7 +640,7 @@
|
|||
"bulk-import-process-has-failed": "Erro no proceso de importación en masa",
|
||||
"report-deletion-failed": "Erro ao eliminar relatorio",
|
||||
"recipe-debugger": "Depurador de Receitas",
|
||||
"recipe-debugger-description": "Copie o URL da receita que quer depurar e pégueo aqui. O URL será lido polo lector de receitas e os resultados serán mostrados. Se non ves negún dato devolto, a páxina que está a tentar ler non é suportada polo Mealie ou pola sua biblioteca de 'scrapping'.",
|
||||
"recipe-debugger-description": "Copie o URL da receita que quer depurar e pégueo aqui. O URL será lido polo lector de receitas e os resultados serán mostrados. Se non ve nengún dato devolto, a páxina que está a tentar ler non é suportada polo Mealie ou pola sua biblioteca de 'scrapping'.",
|
||||
"use-openai": "Utilizar OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Utilize o OpenAI para analisar os resultados en vez de depender da biblioteca de scrapers. Ao crear unha receita através dun URL, isto é feito automaticamente se a biblioteca de scrapers falla, mas pode provala manualmente aqui.",
|
||||
"debug": "Depurar",
|
||||
|
@ -664,19 +666,21 @@
|
|||
"no-unit": "Sen unidades",
|
||||
"missing-unit": "Crear a unidade que falta: {unit}",
|
||||
"missing-food": "Crear a comida que falta: {food}",
|
||||
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||
"this-unit-could-not-be-parsed-automatically": "Non foi posíbel procesar automaticamente esta unidade",
|
||||
"this-food-could-not-be-parsed-automatically": "Non foi posíbel procesar automaticamente este alimento",
|
||||
"no-food": "Sen Comida"
|
||||
},
|
||||
"reset-servings-count": "Reiniciar Contador de Porcións",
|
||||
"not-linked-ingredients": "Ingredientes Adicionais",
|
||||
"upload-another-image": "Cargar outra imaxen",
|
||||
"upload-images": "Cargar imaxens",
|
||||
"upload-more-images": "Cargar mais imaxens"
|
||||
"upload-more-images": "Cargar mais imaxens",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Localizador de Receitas",
|
||||
"recipe-finder-description": "Procure receitas con base nos ingredientes que teñas a man. Pode tamén filtrar polas ferramentas disponíveis e definir un número máximo de ingredientes ou ferramentas que faltan.",
|
||||
"recipe-finder-description": "Procure receitas con base nos ingredientes que teña a man. Pode tamén filtrar polas ferramentas disponíbeis e definir un número máximo de ingredientes ou ferramentas que faltan.",
|
||||
"selected-ingredients": "Ingredientes Selecionados",
|
||||
"no-ingredients-selected": "Nengun ingrediente selecionado",
|
||||
"missing": "En falta",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalles do Grupo",
|
||||
"group-details-description": "Antes de crear unha conta é necesario crear un grupo. Será o único membro do seu grupo, mas poderá convidar outros mais tarde. Os membros do seu grupo poden compartir menús, listas de compras, receitas e moito mais!",
|
||||
"use-seed-data": "Utilizar datos xerados",
|
||||
"use-seed-data-description": "O Mealie ven cunha coleción de Alimentos, Unidades e Rótulos que poden ser usados para preencher o seu grupo con datos úteis para organizar as suas receitas.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalles da Conta"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "התראה חדשה",
|
||||
"event-notifiers": "מנגנוני התרעה על אירועים",
|
||||
"apprise-url-skipped-if-blank": "כתובת Apprise (דלג אם ריק)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "הפעלת מתריע",
|
||||
"what-events": "לאילו אירועים לרשום את מתריע זה?",
|
||||
"user-events": "אירועי משתמש",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "אירועי תגיות",
|
||||
"category-events": "אירועי קטגוריות",
|
||||
"when-a-new-user-joins-your-group": "כאשר משתמש חדש מצטרף לקבוצה",
|
||||
"recipe-events": "אירועי מתכון"
|
||||
"recipe-events": "אירועי מתכון",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "הוספה",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "מרכיבים נוספים",
|
||||
"upload-another-image": "העלאת תמונה נוספת",
|
||||
"upload-images": "העלאת תמונות",
|
||||
"upload-more-images": "העלאת תמונות נוספות"
|
||||
"upload-more-images": "העלאת תמונות נוספות",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "מצא מתכון",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "פרטי הקבוצה",
|
||||
"group-details-description": "לפני יצירת חשבון יש צורך ליצור קבוצה. הקבוצה תכיל רק אותך אבל תוכל להזמין אחרים בשלב מאוחר יותר. חברים בקבוצה יכולים לשתף תוכנית ארוחות, רשימות קניות, מתכונים ועוד!",
|
||||
"use-seed-data": "השתמש בנתוני האכלוס",
|
||||
"use-seed-data-description": "Mealie מגיעה עם אוסף של מאכלים, יחידות מדידה ותוויות שניתן להשתמש לאכלוס הקבוצות עם מידע שימושי לארגון המתכונים.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "פרטי חשבון"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nova Obavijest",
|
||||
"event-notifiers": "Obavještavatelji Događaja",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (preskočeno ako je prazno)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Omogući obavještavanje",
|
||||
"what-events": "Na koje događaje bi ovaj obavještavatelj trebao biti pretplaćen?",
|
||||
"user-events": "Događaji Korisnika",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Događaji Oznaka",
|
||||
"category-events": "Događaji Kategorija",
|
||||
"when-a-new-user-joins-your-group": "Kada se novi korisnik pridruži vašoj grupi",
|
||||
"recipe-events": "Događaji recepta"
|
||||
"recipe-events": "Događaji recepta",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Dodaj",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalji o Grupi",
|
||||
"group-details-description": "Prije nego što kreirate korisnički račun, morat ćete stvoriti grupu. Vaša grupa će sadržavati samo vas, ali kasnije ćete moći pozvati druge članove. Članovi vaše grupe mogu dijeliti planove obroka, popise za kupovinu, recepte i još mnogo toga!",
|
||||
"use-seed-data": "Koristi Pridržane Podatke",
|
||||
"use-seed-data-description": "Mealie dolazi s kolekcijom hrane, jedinica i oznaka koje se mogu koristiti za popunjavanje vaše grupe korisnim podacima za organiziranje vaših recepata.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalji Računa"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Új értesítés",
|
||||
"event-notifiers": "Esemény értesítők",
|
||||
"apprise-url-skipped-if-blank": "Értesítendő URL (kihagy, ha üres)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Értesítés engedélyezése",
|
||||
"what-events": "Milyen eseményekre figyeljen ez az értesítés?",
|
||||
"user-events": "Felhasználói Események",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Címke események",
|
||||
"category-events": "Kategória események",
|
||||
"when-a-new-user-joins-your-group": "Amikor egy új felhasználó csatlakozik a csoportodba",
|
||||
"recipe-events": "Recept esemény"
|
||||
"recipe-events": "Recept esemény",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Hozzáadás",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Kiegészítő hozzávalók",
|
||||
"upload-another-image": "Másik kép feltöltése",
|
||||
"upload-images": "Képek feltöltése",
|
||||
"upload-more-images": "További képek feltöltése"
|
||||
"upload-more-images": "További képek feltöltése",
|
||||
"set-as-cover-image": "Beállítás a recept borítóképének",
|
||||
"cover-image": "Borítókép"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Receptkereső",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Csoport részletek",
|
||||
"group-details-description": "Mielőtt létrehozna egy fiókot, létre kell hoznia egy csoportot. A csoportban csak ön lesz, de később másokat is meghívhat. A csoport tagjai menüterveket, bevásárlólistákat, recepteket és még sok mást is megoszthatnak egymással!",
|
||||
"use-seed-data": "Mintaadatok használata",
|
||||
"use-seed-data-description": "Mealie az alapanyagok, a mennyiségi egységek és a címkék gyűjteményét tartalmazza, amelyek megoszthatók a csoporttal és hasznos adataival segítségül szolgálhat a receptek szervezéséhez.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "A fiók részletei"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Ný tilkynning",
|
||||
"event-notifiers": "Viðburðar tilkynningar",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (sleppt ef tómt)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Virkja tilkynningar",
|
||||
"what-events": "Hvaða viðburði ætti þessi tilkynnir að vera áskrifandi að?",
|
||||
"user-events": "Notenda viðburðir",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Merki viðburðir",
|
||||
"category-events": "Flokka viðburðir",
|
||||
"when-a-new-user-joins-your-group": "Þegar nýr notandi bætist við í þinn hóp",
|
||||
"recipe-events": "Uppskriftar viðburðir"
|
||||
"recipe-events": "Uppskriftar viðburðir",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Bæta við",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nuova Notifica",
|
||||
"event-notifiers": "Notifiche Evento",
|
||||
"apprise-url-skipped-if-blank": "Url di Apprise (ignorato se vuoto)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Abilita Notificatore",
|
||||
"what-events": "Quali eventi dovrebbe sottoscrivere questo notificatore?",
|
||||
"user-events": "Eventi Utente",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tag Eventi",
|
||||
"category-events": "Categoria Eventi",
|
||||
"when-a-new-user-joins-your-group": "Quando un nuovo utente entra nel tuo gruppo",
|
||||
"recipe-events": "Eventi di ricette"
|
||||
"recipe-events": "Eventi di ricette",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Aggiungi",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingredienti Aggiuntivi",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Trova ricette",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Dettagli Gruppo",
|
||||
"group-details-description": "Prima di creare un account, è necessario creare un gruppo. Il gruppo conterrà solo voi, ma potrete invitare altre persone in seguito. I membri del gruppo possono condividere piani alimentari, liste della spesa, ricette e molto altro!",
|
||||
"use-seed-data": "Utilizzo Dati Generati",
|
||||
"use-seed-data-description": "Mealie viene fornito con una raccolta di alimenti, unità ed etichette che possono essere utilizzate per popolare il tuo gruppo con dati utili per organizzare le tue ricette.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Dettagli dell'Account"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "新着通知",
|
||||
"event-notifiers": "イベント通知",
|
||||
"apprise-url-skipped-if-blank": "通知用URL (空欄の場合はスキップ)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "通知を有効にする",
|
||||
"what-events": "この通知はどのイベントを購読すべきですか?",
|
||||
"user-events": "ユーザーイベント",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "タグイベント",
|
||||
"category-events": "カテゴリイベント",
|
||||
"when-a-new-user-joins-your-group": "新しいユーザーがグループに参加したとき",
|
||||
"recipe-events": "レシピイベント"
|
||||
"recipe-events": "レシピイベント",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "追加",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "追加の材料",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "レシピ検索",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "グループの詳細",
|
||||
"group-details-description": "アカウントを作成する前に、グループを作成する必要があります。グループにはあなたしか含まれませんが、後で他の人を招待できます。グループのメンバーは、食事計画、買い物リスト、レシピなどを共有できます!",
|
||||
"use-seed-data": "シードデータを使用",
|
||||
"use-seed-data-description": "Mealieには、レシピを整理するために役立つデータをグループに追加するために使用できる、食品、単位、ラベルのコレクションが付属しています。",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "アカウントの詳細"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "새 알림",
|
||||
"event-notifiers": "이벤트 알림이",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (비워두면 생략합니다)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "알림 활성화",
|
||||
"what-events": "이 알리미는 어떤 이벤트를 구독해야 합니까?",
|
||||
"user-events": "사용자 이벤트",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tag 이벤트",
|
||||
"category-events": "카테고리 이벤트",
|
||||
"when-a-new-user-joins-your-group": "새로운 사용자가 그룹에 가입하면",
|
||||
"recipe-events": "레시피 이벤트"
|
||||
"recipe-events": "레시피 이벤트",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "추가",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Naujas pranešimas",
|
||||
"event-notifiers": "Įvykių pranešimai",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (praleidžiama, jei tuščia)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Įjungti pranešiklį",
|
||||
"what-events": "Kokie įvykiai turėtų būti sekami?",
|
||||
"user-events": "Naudotojų įvykiai",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Žymų įvykiai",
|
||||
"category-events": "Kategorijų įvykiai",
|
||||
"when-a-new-user-joins-your-group": "Kai prie jūsų grupės prisijungia naujas naudotojas",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Pridėti",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Grupės informacija",
|
||||
"group-details-description": "Prieš kurdami paskyrą turite sukurti grupę. Jūsų grupėje būsite tik jūs, tačiau vėliau galėsite pakviesti ir kitus. Jūsų grupės nariai galės dalintis maitinimo planais, pirkinių sąrašais, receptais ir kita!",
|
||||
"use-seed-data": "Naudoti pradinius duomenis",
|
||||
"use-seed-data-description": "\"Mealie\" sistemoje jau yra pradinis duomenų rinkinys su produktais, vienetais ir etiketėmis. Jį galite panaudoti savo grupės užpildymui naudinga informacija, kuri padės organizuoti jūsų receptus.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Paskyros informacija"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Jauns paziņojums",
|
||||
"event-notifiers": "Notikumu paziņotāji",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (izlaists, ja tukšs)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Iespējot paziņotāju",
|
||||
"what-events": "Kādus notikumus šim paziņotājam vajadzētu abonēt?",
|
||||
"user-events": "Lietotāju notikumi",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Atzīmēt notikumus",
|
||||
"category-events": "Kategorija Notikumi",
|
||||
"when-a-new-user-joins-your-group": "Kad jūsu grupai pievienojas jauns lietotājs",
|
||||
"recipe-events": "Recepšu notikumi"
|
||||
"recipe-events": "Recepšu notikumi",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Pievienot",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Grupas informācija",
|
||||
"group-details-description": "Pirms konta izveides jums būs jāizveido grupa. Jūsu grupā būs tikai jūs, bet vēlāk varēsiet uzaicināt citus. Jūsu grupas dalībnieki var dalīties maltīšu plānos, iepirkumu sarakstos, receptēs un daudz ko citu!",
|
||||
"use-seed-data": "Izmantojiet sēklu datus",
|
||||
"use-seed-data-description": "Mealie piegādā kopā ar pārtikas produktu, vienību un etiķešu kolekciju, ko var izmantot, lai papildinātu grupu ar noderīgiem datiem recepšu sakārtošanai.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Konta informācija"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nieuwe melding",
|
||||
"event-notifiers": "Meldingen van gebeurtenissen",
|
||||
"apprise-url-skipped-if-blank": "URL van Apprise (overgeslagen als veld leeg is)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activeer melding",
|
||||
"what-events": "Op welke gebeurtenissen moet deze melding zich abonneren?",
|
||||
"user-events": "Gebeurtenissen van gebruiker",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Label-gebeurtenissen",
|
||||
"category-events": "Categorie-gebeurtenissen",
|
||||
"when-a-new-user-joins-your-group": "Als een nieuwe gebruiker zich bij je groep aansluit",
|
||||
"recipe-events": "Recept gebeurtenissen"
|
||||
"recipe-events": "Recept gebeurtenissen",
|
||||
"label-events": "Label gebeurtenissen"
|
||||
},
|
||||
"general": {
|
||||
"add": "Voeg toe",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Extra ingrediënten",
|
||||
"upload-another-image": "Een andere afbeelding uploaden",
|
||||
"upload-images": "Afbeelding uploaden",
|
||||
"upload-more-images": "Meer afbeeldingen uploaden"
|
||||
"upload-more-images": "Meer afbeeldingen uploaden",
|
||||
"set-as-cover-image": "Als recept omslagfoto instellen",
|
||||
"cover-image": "Omslagfoto"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recept zoeker",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Groepsdetails",
|
||||
"group-details-description": "Voordat je een account aanmaakt moet je eerst een groep aanmaken. Jij bent het enige lid van de groep, maar je kunt later anderen uitnodigen. Leden van je groep kunnen maaltijdplannen, boodschappenlijstjes, recepten en nog veel meer delen!",
|
||||
"use-seed-data": "Gebruik voorbeeldgegevens",
|
||||
"use-seed-data-description": "Mealie bevat een verzameling ingrediënten, eenheden en labels die gebruikt kunnen worden om je groep te vullen met handige gegevens voor het organiseren van je recepten.",
|
||||
"use-seed-data-description": "Mealie komt standaard met lijsten voor Voedsel, Eenheden en Labels. Die gebruik je om je recepten handig in te delen. Of om je groep handige informatie te geven. Ze zijn vertaald in de taal die je voor Mealie hebt ingesteld. Je kunt deze lijsten altijd aanvullen of aanpassen.",
|
||||
"account-details": "Accountgegevens"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nytt varsel",
|
||||
"event-notifiers": "Hendelsesvarsler",
|
||||
"apprise-url-skipped-if-blank": "Apprise-URL (hoppes over hvis tom)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Aktiver varslingsagenten",
|
||||
"what-events": "Hvilke hendelser skal denne varslingsagenten abonnere på?",
|
||||
"user-events": "Brukerhendelser",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Emneordhendelser",
|
||||
"category-events": "Kategorihendelser",
|
||||
"when-a-new-user-joins-your-group": "Når en ny bruker blir med i gruppen din",
|
||||
"recipe-events": "Oppskriftshendelser"
|
||||
"recipe-events": "Oppskriftshendelser",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Legg til",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Kommentar",
|
||||
"comments": "Kommentarer",
|
||||
"delete-confirmation": "Er du sikker på at du vil slette denne oppskriften?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Du er i ferd med å slette en oppskrift som ikke er din ved å bruke administratortillatelser. Er du sikker?",
|
||||
"delete-recipe": "Slett oppskrift",
|
||||
"description": "Beskrivelse",
|
||||
"disable-amount": "Deaktiver ingrediensmengde",
|
||||
|
@ -581,7 +583,7 @@
|
|||
"how-did-it-turn-out": "Hvordan ble det?",
|
||||
"user-made-this": "{user} har laget dette",
|
||||
"added-to-timeline": "Legg til tidslinje",
|
||||
"failed-to-add-to-timeline": "Failed to add to timeline",
|
||||
"failed-to-add-to-timeline": "Kunne ikke legge til på tidslinjen",
|
||||
"failed-to-update-recipe": "Kunne ikke oppdatere oppskriften",
|
||||
"added-to-timeline-but-failed-to-add-image": "Lagt til i tidslinjen, men klarte ikke å legge til bilde",
|
||||
"api-extras-description": "Ekstramaterialer til oppskrifter er en viktig funksjon i Mealie API-en. De lar deg opprette egendefinerte JSON-nøkkel/verdi-par innenfor en oppskrift for å referere fra tredjepartsapplikasjoner. Du kan bruke disse nøklene til å gi informasjon for eksempel for å utløse automatiseringer eller egendefinerte meldinger som skal videreformidles til ønsket enhet.",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Tilleggsingredienser",
|
||||
"upload-another-image": "Last opp nytt bilde",
|
||||
"upload-images": "Last opp bilder",
|
||||
"upload-more-images": "Last opp flere bilder"
|
||||
"upload-more-images": "Last opp flere bilder",
|
||||
"set-as-cover-image": "Bruk som forsidebilde for oppskriften",
|
||||
"cover-image": "Forsidebilde"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Oppskriftsfinner",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Gruppedetaljer",
|
||||
"group-details-description": "Før du oppretter en konto må du opprette en gruppe. Gruppen din vil bare inneholde deg, men du vil kunne invitere andre senere. Medlemmer i gruppen din kan dele måltider, handlelister, oppskrifter med mer!",
|
||||
"use-seed-data": "Bruk tilføringsdata",
|
||||
"use-seed-data-description": "Mealie kommer med en samling av matvarer, enheter og etiketter som kan brukes til å fylle gruppen din med nyttige data for å organisere oppskriftene dine.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Kontodetaljer"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nowe powiadomienie",
|
||||
"event-notifiers": "Powiadomienia o zdarzeniach",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (pominięty, jeśli puste)",
|
||||
"apprise-url-is-left-intentionally-blank": "Ponieważ adresy URL Apprise zawierają zazwyczaj poufne informacje, pole to pozostaje celowo puste podczas edycji. Jeśli chcesz zaktualizować adres URL, wprowadź ten nowy tutaj, w przeciwnym razie pozostaw puste, aby zachować bieżący adres URL.",
|
||||
"enable-notifier": "Włącz Powiadomienie",
|
||||
"what-events": "Jakie zdarzenia powinien subskrybować ten powiadamiający?",
|
||||
"user-events": "Zdarzenia użytkownika",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Zdarzenia tagów",
|
||||
"category-events": "Wydarzenia kategorii",
|
||||
"when-a-new-user-joins-your-group": "Kiedy nowy użytkownik dołączy do Twojej grupy",
|
||||
"recipe-events": "Zdarzenia Przepisów"
|
||||
"recipe-events": "Zdarzenia Przepisów",
|
||||
"label-events": "Etykieta wydarzeń"
|
||||
},
|
||||
"general": {
|
||||
"add": "Dodaj",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Dodatkowe składniki",
|
||||
"upload-another-image": "Prześlij kolejny obraz",
|
||||
"upload-images": "Prześlij obraz",
|
||||
"upload-more-images": "Prześlij więcej obrazów"
|
||||
"upload-more-images": "Prześlij więcej obrazów",
|
||||
"set-as-cover-image": "Ustaw jako okładkę przepisu",
|
||||
"cover-image": "Okładka"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Wyszukiwarka przepisów",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Szczegóły grupy",
|
||||
"group-details-description": "Zanim utworzysz konto musisz stworzyć grupę. Twoja grupa zawierać będzie tylko Ciebie, ale będziesz istniała możlwiość zaproszenia do niej innych. Użytkownicy Twojej grupy mogą współdzielić plany posiłków, listy zakupów, przepisy i więcej!",
|
||||
"use-seed-data": "Użyj przykładowych danych",
|
||||
"use-seed-data-description": "Mealie dostarcza zestaw posiłków, jednostek i opisów które mogą zostać użyte do zapełnienia Twojej grupy przydatnymi danymi do ogranizacji Twoich przepisów.",
|
||||
"use-seed-data-description": "Wysyłka posiłków z kolekcją żywności, jednostek i etykiet, które mogą być użyte do wypełnienia Twojej grupy pomocnymi danymi do organizacji twoich przepisów. Są one tłumaczone na wybrany język. Zawsze możesz dodać lub zmodyfikować te dane później.",
|
||||
"account-details": "Szczegóły konta"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nova Notificação",
|
||||
"event-notifiers": "Notificações de Eventos",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (ignorado se estiver em branco)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Habilitar Notificador",
|
||||
"what-events": "A quais eventos este notificador deve subscrever?",
|
||||
"user-events": "Eventos do usuário",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Eventos de Etiqueta",
|
||||
"category-events": "Eventos de Categoria",
|
||||
"when-a-new-user-joins-your-group": "Quando um novo usuário entrar no seu grupo",
|
||||
"recipe-events": "Eventos da Receita"
|
||||
"recipe-events": "Eventos da Receita",
|
||||
"label-events": "Rotular Eventos"
|
||||
},
|
||||
"general": {
|
||||
"add": "Adicionar",
|
||||
|
@ -253,7 +255,7 @@
|
|||
"default-recipe-preferences": "Preferências padrões de receita",
|
||||
"group-preferences": "Preferências de Grupo",
|
||||
"private-group": "Grupo Privado",
|
||||
"private-group-description": "Setting your group to private will disable all public view options. This overrides any individual public view settings",
|
||||
"private-group-description": "Configurar seu grupo para privado irá desabilitar as opções de visualização pública. Isso substitui qualquer configuração pública individual.",
|
||||
"enable-public-access": "Ativar Acesso Público",
|
||||
"enable-public-access-description": "Tornar receitas do grupo públicas por padrão, e permitir a sua visualização por visitantes não logados",
|
||||
"allow-users-outside-of-your-group-to-see-your-recipes": "Permitir que usuários fora do seu grupo vejam suas receitas",
|
||||
|
@ -276,30 +278,30 @@
|
|||
"admin-group-management": "Gerenciamento de Grupos Administrativos",
|
||||
"admin-group-management-text": "As alterações a este grupo serão refletidas imediatamente.",
|
||||
"group-id-value": "ID do grupo: {0}",
|
||||
"total-households": "Total Households",
|
||||
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
|
||||
"total-households": "Total de Familiares",
|
||||
"you-must-select-a-group-before-selecting-a-household": "Você deve selecionar um grupo antes de selecionar uma família"
|
||||
},
|
||||
"household": {
|
||||
"household": "Casa",
|
||||
"households": "Casas",
|
||||
"user-household": "User Household",
|
||||
"create-household": "Create Household",
|
||||
"household-name": "Household Name",
|
||||
"household-group": "Household Group",
|
||||
"household-management": "Household Management",
|
||||
"manage-households": "Manage Households",
|
||||
"admin-household-management": "Admin Household Management",
|
||||
"admin-household-management-text": "Changes to this household will be reflected immediately.",
|
||||
"household-id-value": "Household Id: {0}",
|
||||
"private-household": "Private Household",
|
||||
"private-household-description": "Setting your household to private will disable all public view options. This overrides any individual public view settings",
|
||||
"lock-recipe-edits-from-other-households": "Lock recipe edits from other households",
|
||||
"lock-recipe-edits-from-other-households-description": "When enabled only users in your household can edit recipes created by your household",
|
||||
"household-recipe-preferences": "Household Recipe Preferences",
|
||||
"default-recipe-preferences-description": "These are the default settings when a new recipe is created in your household. These can be changed for individual recipes in the recipe settings menu.",
|
||||
"allow-users-outside-of-your-household-to-see-your-recipes": "Allow users outside of your household to see your recipes",
|
||||
"allow-users-outside-of-your-household-to-see-your-recipes-description": "When enabled you can use a public share link to share specific recipes without authorizing the user. When disabled, you can only share recipes with users who are in your household or with a pre-generated private link",
|
||||
"household-preferences": "Household Preferences"
|
||||
"user-household": "Família do Usuário",
|
||||
"create-household": "Criar Família",
|
||||
"household-name": "Nome da Família",
|
||||
"household-group": "Grupo Familiar",
|
||||
"household-management": "Gerenciamento Familiar",
|
||||
"manage-households": "Gerenciar Família",
|
||||
"admin-household-management": "Administrador de Gerenciamento Familiar",
|
||||
"admin-household-management-text": "Mudanças a esta família serão aplicadas imediatamente.",
|
||||
"household-id-value": "Id Familiar: {0}",
|
||||
"private-household": "Família Privada",
|
||||
"private-household-description": "Configurar sua família como privado desativará todas as opções de visualização pública. Isso substitui as configurações de visualização pública individual",
|
||||
"lock-recipe-edits-from-other-households": "Bloquear edições de receitas de outras famílias",
|
||||
"lock-recipe-edits-from-other-households-description": "Quando ativado apenas os usuários da sua família podem editar receitas criadas por sua família",
|
||||
"household-recipe-preferences": "Preferências de Receita da Família",
|
||||
"default-recipe-preferences-description": "Estas são as configurações padrão quando uma nova receita é criada em sua família. Elas podem ser alteradas para receitas individuais no menu de configurações de receitas.",
|
||||
"allow-users-outside-of-your-household-to-see-your-recipes": "Permitir que os usuários fora de sua família vejam suas receitas",
|
||||
"allow-users-outside-of-your-household-to-see-your-recipes-description": "Quando ativado, você pode usar um link de compartilhamento público para compartilhar receitas específicas sem autorizar o usuário. Quando desativado, você só pode compartilhar receitas com usuários que estão na sua família ou com um link privado pré-gerado",
|
||||
"household-preferences": "Preferências Familiares"
|
||||
},
|
||||
"meal-plan": {
|
||||
"create-a-new-meal-plan": "Criar um novo plano de refeições",
|
||||
|
@ -321,10 +323,10 @@
|
|||
"mealplan-settings": "Configurações de Plano de Refeições",
|
||||
"mealplan-update-failed": "Falha ao atualizar Plano de Refeições",
|
||||
"mealplan-updated": "Plano de Refeições atualizado",
|
||||
"mealplan-households-description": "If no household is selected, recipes can be added from any household",
|
||||
"any-category": "Any Category",
|
||||
"any-tag": "Any Tag",
|
||||
"any-household": "Any Household",
|
||||
"mealplan-households-description": "Se nenhuma família for selecionada, as receitas podem ser adicionadas por qualquer família",
|
||||
"any-category": "Qualquer Categoria",
|
||||
"any-tag": "Qualquer Etiqueta",
|
||||
"any-household": "Qualquer Família",
|
||||
"no-meal-plan-defined-yet": "Nenhum Plano de Refeições definido ainda",
|
||||
"no-meal-planned-for-today": "Nenhuma refeição planejada para hoje",
|
||||
"numberOfDays-hint": "Número de dias ao carregar a página",
|
||||
|
@ -357,7 +359,7 @@
|
|||
"for-type-meal-types": "para {0} tipos de refeição",
|
||||
"meal-plan-rules": "Regras de Plano de Refeições",
|
||||
"new-rule": "Nova Regra",
|
||||
"meal-plan-rules-description": "You can create rules for auto selecting recipes for your meal plans. These rules are used by the server to determine the random pool of recipes to select from when creating meal plans. Note that if rules have the same day/type constraints then the rule filters will be merged. In practice, it's unnecessary to create duplicate rules, but it's possible to do so.",
|
||||
"meal-plan-rules-description": "Você pode criar regras para selecionar receitas automaticamente para seus Planos de Refeição. Essas regras são usadas pelo servidor para determinar o conjunto aleatório de receitas a serem selecionadas ao criar os planos de refeição. Observe que se as regras tiverem as mesmas restrições de dia/tipo, os filtros de regras serão mesclados. Na prática, não é necessário criar regras duplicadas, mas é possível fazê-lo.",
|
||||
"new-rule-description": "Ao criar uma nova regra para um Plano de Refeições, você pode restringir a regra a ser aplicada a um dia específico da semana e/ou a um tipo específico de refeição. Para aplicar uma regra a todos os dias ou a todos os tipos de refeições, você pode definir a regra para \"Qualquer\", que será aplicada a todos os valores possíveis para o dia e/ou o tipo de refeição.",
|
||||
"recipe-rules": "Regras das receitas",
|
||||
"applies-to-all-days": "Aplica-se diariamente",
|
||||
|
@ -432,7 +434,7 @@
|
|||
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Cole os dados da sua receita. Cada linha será tratado como um item em uma lista",
|
||||
"recipe-markup-specification": "Especificação da Receita",
|
||||
"recipe-url": "URL da Receita",
|
||||
"recipe-html-or-json": "Recipe HTML or JSON",
|
||||
"recipe-html-or-json": "HMTL ou JSON da Receita",
|
||||
"upload-a-recipe": "Enviar uma Receita",
|
||||
"upload-individual-zip-file": "Enviar um arquivo .zip individual exportado a partir de outra instância do Mealie.",
|
||||
"url-form-hint": "Copie e cole um link do seu site de receita favorito",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Comentário",
|
||||
"comments": "Comentários",
|
||||
"delete-confirmation": "Você tem certeza que deseja apagar esta receita?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Você está prestes a excluir uma receita que não é sua usando permissões de administrador. Tem certeza?",
|
||||
"delete-recipe": "Excluir Receita",
|
||||
"description": "Descrição",
|
||||
"disable-amount": "Desativa Quantidade de Ingredientes",
|
||||
|
@ -527,7 +529,7 @@
|
|||
"sugar-content": "Açúcares",
|
||||
"title": "Título",
|
||||
"total-time": "Tempo Total",
|
||||
"trans-fat-content": "Trans-fat",
|
||||
"trans-fat-content": "Gordura trans",
|
||||
"unable-to-delete-recipe": "Não foi possível apagar a receita",
|
||||
"unsaturated-fat-content": "Gorduras não saturadas",
|
||||
"no-recipe": "Nenhuma Receita",
|
||||
|
@ -548,8 +550,8 @@
|
|||
"failed-to-add-recipe-to-mealplan": "Falha ao adicionar a receita ao plano de refeições",
|
||||
"failed-to-add-to-list": "Falha ao adicionar à lista",
|
||||
"yield": "Rendimento",
|
||||
"yields-amount-with-text": "Yields {amount} {text}",
|
||||
"yield-text": "Yield Text",
|
||||
"yields-amount-with-text": "Produtos {amount}{text}",
|
||||
"yield-text": "Texto do Produto",
|
||||
"quantity": "Quantidade",
|
||||
"choose-unit": "Escolher unidades",
|
||||
"press-enter-to-create": "Pressione Enter para criar",
|
||||
|
@ -580,14 +582,14 @@
|
|||
"made-this": "Eu Fiz Isso",
|
||||
"how-did-it-turn-out": "Como que ficou?",
|
||||
"user-made-this": "{user} fez isso",
|
||||
"added-to-timeline": "Added to timeline",
|
||||
"failed-to-add-to-timeline": "Failed to add to timeline",
|
||||
"failed-to-update-recipe": "Failed to update recipe",
|
||||
"added-to-timeline-but-failed-to-add-image": "Added to timeline, but failed to add image",
|
||||
"added-to-timeline": "Adicionado à linha do tempo",
|
||||
"failed-to-add-to-timeline": "Falha ao adicionar à linha do tempo",
|
||||
"failed-to-update-recipe": "Falha ao atualizar receita",
|
||||
"added-to-timeline-but-failed-to-add-image": "Adicionado à linha do tempo, mas não foi possível adicionar imagem",
|
||||
"api-extras-description": "Extras de receitas são atributos-chave da API do Mealie. Assim, você pode criar pares chave/valor JSON personalizados dentro de uma receita, referenciando aplicações de terceiros. Você pode usar as chaves para fornecer informações, como por ex. ativar automações ou mensagens que serão enviadas a seus dispositivos.",
|
||||
"message-key": "Chave de mensagem",
|
||||
"parse": "Analisar",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"ingredients-not-parsed-description": "Parece que seus ingredientes ainda não foram analisados. Clique no botão \"{parse}\" abaixo para analisar seus ingredientes em alimentos estruturados.",
|
||||
"attach-images-hint": "Anexe imagens arrastando e soltando-as no editor",
|
||||
"drop-image": "Arrastar imagem",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Ative quantidades de ingredientes para usar esta funcionalidade",
|
||||
|
@ -604,7 +606,7 @@
|
|||
"import-with-zip": "Importar a partir de .zip",
|
||||
"create-recipe-from-an-image": "Create Recipe from an Image",
|
||||
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
|
||||
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
|
||||
"crop-and-rotate-the-image": "Corte e gire a imagem para que apenas o texto esteja visível e esteja na posição correta.",
|
||||
"create-from-images": "Criar a partir de imagens",
|
||||
"should-translate-description": "Traduza a receita para o meu idioma",
|
||||
"please-wait-image-procesing": "Por favor aguarde, a imagem está sendo processada. Isto pode levar algum tempo.",
|
||||
|
@ -618,13 +620,13 @@
|
|||
"scrape-recipe-have-a-lot-of-recipes": "Tem muitas receitas a extrair de uma vez?",
|
||||
"scrape-recipe-suggest-bulk-importer": "Tente o importador em massa",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Tem dados HTML ou JSON brutos?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "You can import from raw data directly",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Você pode importar diretamente de dados brutos",
|
||||
"import-original-keywords-as-tags": "Importar palavras-chave originais como marcadores",
|
||||
"stay-in-edit-mode": "Permanecer no modo de edição",
|
||||
"import-from-zip": "Importar do .zip",
|
||||
"import-from-zip-description": "Importar uma única receita exportada de outra instância Mealie.",
|
||||
"import-from-html-or-json": "Import from HTML or JSON",
|
||||
"import-from-html-or-json-description": "Import a single recipe from raw HTML or JSON. This is useful if you have a recipe from a site that Mealie can't scrape normally, or from some other external source.",
|
||||
"import-from-html-or-json": "Importar de HTML ou JSON",
|
||||
"import-from-html-or-json-description": "Importe uma única receita de HTML ou JSON. Isso é útil se você tiver uma receita de um site que a Mealie não consegue extrair normalmente, ou de alguma outra fonte externa.",
|
||||
"json-import-format-description-colon": "Para importar via JSON, ele deve estar em formato válido:",
|
||||
"json-editor": "Editor de JSON",
|
||||
"zip-files-must-have-been-exported-from-mealie": "Os arquivos .zip devem ter sido exportados do Mealie",
|
||||
|
@ -643,9 +645,9 @@
|
|||
"recipe-debugger-use-openai-description": "Usar OpenAI para analisar os resultados ao invés de depender da biblioteca de extração. Criando uma receita via URL, isso é feito automaticamente se essa biblioteca, mas você pode testar manualmente aqui.",
|
||||
"debug": "Depurar",
|
||||
"tree-view": "Visualização em árvore",
|
||||
"recipe-servings": "Recipe Servings",
|
||||
"recipe-servings": "Porções da Receita",
|
||||
"recipe-yield": "Rendimento da Receita",
|
||||
"recipe-yield-text": "Recipe Yield Text",
|
||||
"recipe-yield-text": "Texto de Produção da Receita",
|
||||
"unit": "Unidade",
|
||||
"upload-image": "Enviar imagem",
|
||||
"screen-awake": "Manter a tela ligada",
|
||||
|
@ -664,15 +666,17 @@
|
|||
"no-unit": "Sem unidades",
|
||||
"missing-unit": "Criar unidade ausente: {unit}",
|
||||
"missing-food": "Criar comida ausente: {food}",
|
||||
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||
"this-unit-could-not-be-parsed-automatically": "Esta unidade não pôde ser analisada automaticamente",
|
||||
"this-food-could-not-be-parsed-automatically": "Este alimento não pôde ser analisado automaticamente",
|
||||
"no-food": "Sem Comida"
|
||||
},
|
||||
"reset-servings-count": "Reset Servings Count",
|
||||
"reset-servings-count": "Redefinir Contagem de Porções",
|
||||
"not-linked-ingredients": "Ingredientes adicionais",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-another-image": "Carregar outra imagem",
|
||||
"upload-images": "Carregar imagens",
|
||||
"upload-more-images": "Carregar mais imagens",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Localizador de Receitas",
|
||||
|
@ -681,15 +685,15 @@
|
|||
"no-ingredients-selected": "Nenhum ingrediente selecionado",
|
||||
"missing": "Ausente",
|
||||
"no-recipes-found": "Nenhuma receita encontrada",
|
||||
"no-recipes-found-description": "Try adding more ingredients to your search or adjusting your filters",
|
||||
"include-ingredients-on-hand": "Include Ingredients On Hand",
|
||||
"include-tools-on-hand": "Include Tools On Hand",
|
||||
"max-missing-ingredients": "Max Missing Ingredients",
|
||||
"max-missing-tools": "Max Missing Tools",
|
||||
"no-recipes-found-description": "Tente adicionar mais ingredientes à sua busca ou ajuste seus filtros",
|
||||
"include-ingredients-on-hand": "Incluir Ingredientes Manualmente",
|
||||
"include-tools-on-hand": "Incluir Utensílios Manualmente",
|
||||
"max-missing-ingredients": "Máximo de Ingredientes Faltando",
|
||||
"max-missing-tools": "Máximo de Utensílios Faltando",
|
||||
"selected-tools": "Ferramentas Selecionadas",
|
||||
"other-filters": "Outros Filtros",
|
||||
"ready-to-make": "Ready to Make",
|
||||
"almost-ready-to-make": "Almost Ready to Make"
|
||||
"ready-to-make": "Pronto Para Fazer",
|
||||
"almost-ready-to-make": "Quase Pronto Para Fazer"
|
||||
},
|
||||
"search": {
|
||||
"advanced-search": "Pesquisa avançada",
|
||||
|
@ -1040,7 +1044,7 @@
|
|||
"administrator": "Administrador",
|
||||
"user-can-invite-other-to-group": "O usuário pode convidar outros para o grupo",
|
||||
"user-can-manage-group": "Usuário pode gerenciar o grupo",
|
||||
"user-can-manage-household": "User can manage household",
|
||||
"user-can-manage-household": "O usuário pode gerenciar a família",
|
||||
"user-can-organize-group-data": "Usuário pode organizar dados do grupo",
|
||||
"enable-advanced-features": "Ativar recursos avançados",
|
||||
"it-looks-like-this-is-your-first-time-logging-in": "Parece que este é seu primeiro login.",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalhes do Grupo",
|
||||
"group-details-description": "Antes de criar uma conta é necessário criar um grupo. O seu grupo só conterá você, mas você poderá convidar os outros mais tarde. Os membros do seu grupo podem compartilhar planos de refeição, listas de compras, receitas e muito mais!",
|
||||
"use-seed-data": "Usar dados semeados",
|
||||
"use-seed-data-description": "O Mealie é fornecido com uma coleção de alimentos, unidades e rótulos que podem ser usados para preencher seu grupo com dados úteis para organizar suas receitas.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalhes da Conta"
|
||||
},
|
||||
"validation": {
|
||||
|
@ -1300,8 +1304,8 @@
|
|||
"debug-openai-services-description": "Use esta página para depurar serviços OpenAI. Você pode testar a sua conexão OpenAI e ver os resultados aqui. Se você tiver os serviços de imagem ativados, você também pode fornecer uma imagem.",
|
||||
"run-test": "Executar teste",
|
||||
"test-results": "Resultados do teste",
|
||||
"group-delete-note": "Groups with users or households cannot be deleted",
|
||||
"household-delete-note": "Households with users cannot be deleted"
|
||||
"group-delete-note": "Grupos com usuários ou famílias não podem ser excluídos",
|
||||
"household-delete-note": "Famílias com usuários não podem ser excluídas"
|
||||
},
|
||||
"profile": {
|
||||
"welcome-user": "👋 Bem-vindo(a), {0}!",
|
||||
|
@ -1313,8 +1317,8 @@
|
|||
"account-summary-description": "Aqui está um resumo das informações do seu grupo.",
|
||||
"group-statistics": "Estatísticas do Grupo",
|
||||
"group-statistics-description": "Suas Estatísticas em Grupo fornecem algumas informações sobre como você está usando o Mealie.",
|
||||
"household-statistics": "Household Statistics",
|
||||
"household-statistics-description": "Your Household Statistics provide some insight how you're using Mealie.",
|
||||
"household-statistics": "Estatísticas da Família",
|
||||
"household-statistics-description": "Suas Estatísticas da Família fornecem algumas dicas de como você está usando o Mealie.",
|
||||
"storage-capacity": "Capacidade de armazenamento",
|
||||
"storage-capacity-description": "Sua capacidade de armazenamento é um cálculo das imagens e arquivos que você carregou.",
|
||||
"personal": "Pessoal",
|
||||
|
@ -1324,13 +1328,13 @@
|
|||
"api-tokens-description": "Gerencie seus Tokens de API para acessar de aplicações externas.",
|
||||
"group-description": "Esses itens são compartilhados dentro do seu grupo. Ao editar um deles vai mudá-lo para todo o grupo!",
|
||||
"group-settings": "Configurações do Grupo",
|
||||
"group-settings-description": "Manage your common group settings, like privacy settings.",
|
||||
"household-description": "These items are shared within your household. Editing one of them will change it for the whole household!",
|
||||
"household-settings": "Household Settings",
|
||||
"household-settings-description": "Manage your household settings, like mealplan and privacy settings.",
|
||||
"group-settings-description": "Gerencie suas configurações comuns de grupo, como configurações de privacidade.",
|
||||
"household-description": "Esses itens são compartilhados dentro de sua família. Editar um deles irá alterá-lo para toda a família!",
|
||||
"household-settings": "Configurações da Família",
|
||||
"household-settings-description": "Gerencie suas configurações familiares, como planos de refeição e configurações de privacidade.",
|
||||
"cookbooks-description": "Gerencie uma coleção de categorias de receita e gere páginas para elas.",
|
||||
"members": "Membros",
|
||||
"members-description": "See who's in your household and manage their permissions.",
|
||||
"members-description": "Ver quem está na sua família e gerenciar suas permissões.",
|
||||
"webhooks-description": "Setup webhooks that trigger on days that you have have mealplan scheduled.",
|
||||
"notifiers": "Notificadores",
|
||||
"notifiers-description": "Configure e-mails e notificações push que desencadeiam eventos específicos.",
|
||||
|
@ -1355,9 +1359,9 @@
|
|||
},
|
||||
"cookbook": {
|
||||
"cookbooks": "Livros de Receita",
|
||||
"description": "Cookbooks are another way to organize recipes by creating cross sections of recipes, organizers, and other filters. Creating a cookbook will add an entry to the side-bar and all the recipes with the filters chosen will be displayed in the cookbook.",
|
||||
"hide-cookbooks-from-other-households": "Hide Cookbooks from Other Households",
|
||||
"hide-cookbooks-from-other-households-description": "When enabled, only cookbooks from your household will appear on the sidebar",
|
||||
"description": "Livros de receitas são outra maneira de criar sessões cruzadas de receitas, organizadores e outros filtros. Criar um livro de receitas adicionará um acesso à barra lateral e todas as receitas com filtros selecionados serão exibidos no livro de receitas.",
|
||||
"hide-cookbooks-from-other-households": "Ocultar Livros de Receitas de Outras Famílias",
|
||||
"hide-cookbooks-from-other-households-description": "Quando ativo, apenas livros de receitas da sua família aparecerão na barra lateral",
|
||||
"public-cookbook": "Livro de Receitas público",
|
||||
"public-cookbook-description": "Cookbooks públicos podem ser compartilhados com usuários que não sejam não-mealiee serão exibidos na sua página de grupos.",
|
||||
"filter-options": "Opções de filtro",
|
||||
|
@ -1367,7 +1371,7 @@
|
|||
"require-all-tools": "Exigir todas as ferramentas",
|
||||
"cookbook-name": "Nome do Livro de Receitas",
|
||||
"cookbook-with-name": "Livro de Receitas {0}",
|
||||
"household-cookbook-name": "{0} Cookbook {1}",
|
||||
"household-cookbook-name": "{0} Livro de Receitas {1}",
|
||||
"create-a-cookbook": "Criar um Livro de Receitas",
|
||||
"cookbook": "Livro de Receitas"
|
||||
},
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nova Notificação",
|
||||
"event-notifiers": "Notificadores de eventos",
|
||||
"apprise-url-skipped-if-blank": "URL da Apprise (ignorado se vazio)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Ativar Notificador",
|
||||
"what-events": "Que eventos este notificador deve subscrever?",
|
||||
"user-events": "Eventos do utilizador",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Eventos de Etiquetagem",
|
||||
"category-events": "Eventos de Categoria",
|
||||
"when-a-new-user-joins-your-group": "Quando um novo utilizador entra no seu grupo",
|
||||
"recipe-events": "Eventos de receita"
|
||||
"recipe-events": "Eventos de receita",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Adicionar",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingredientes Adicionais",
|
||||
"upload-another-image": "Carregar outra imagem",
|
||||
"upload-images": "Carregar imagens",
|
||||
"upload-more-images": "Carregar mais imagens"
|
||||
"upload-more-images": "Carregar mais imagens",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Localizador de Receitas",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detalhes do Grupo",
|
||||
"group-details-description": "Antes de criar uma conta é necessário criar um grupo. Será o único membro do seu grupo, mas poderá convidar outros mais tarde. Os membros do seu grupo podem partilhar planos de refeição, listas de compras, receitas e muito mais!",
|
||||
"use-seed-data": "Utilizar dados gerados",
|
||||
"use-seed-data-description": "O Mealie vem com uma coleção de Alimentos, Unidades e Rótulos que podem ser usados para popular o seu grupo com dados úteis para organizar as suas receitas.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalhes da Conta"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Notificare nouă",
|
||||
"event-notifiers": "Notificatori de evenimente",
|
||||
"apprise-url-skipped-if-blank": "URL Apprise (ignorat daca e gol)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Activare notificator",
|
||||
"what-events": "La ce evenimente ar trebui să se înscrie acest notificator?",
|
||||
"user-events": "Evenimente Utilizator",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Etichetele de Evenimente",
|
||||
"category-events": "Categorie de Evenimente",
|
||||
"when-a-new-user-joins-your-group": "Când un utilizator nou se alătură grupului tău",
|
||||
"recipe-events": "Evenimente rețetă"
|
||||
"recipe-events": "Evenimente rețetă",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Adaugă",
|
||||
|
@ -587,6 +589,7 @@
|
|||
"api-extras-description": "Recipes extras sunt o caracteristică cheie a API-ului Mealie. Îți permit să creezi perechi personalizate de cheie/valoare JSON într-o rețetă, ca să faci referire la aplicații terțe. Puteți utiliza aceste chei pentru a furniza informații, de exemplu pentru a declanșa automatizări sau mesaje personalizate pentru a transmite dispozitivul dorit.",
|
||||
"message-key": "Cheie mesaj",
|
||||
"parse": "Parsează",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"attach-images-hint": "Atașează imagini trăgându-le cu mouse-ul și plasându-le în editor",
|
||||
"drop-image": "Trage imaginea",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Activaţi cantităţile de ingrediente pentru a utiliza această funcționalitate",
|
||||
|
@ -671,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ingrediente suplimentare",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Căutător de rețete",
|
||||
|
@ -1164,7 +1169,7 @@
|
|||
"group-details": "Detalii grup",
|
||||
"group-details-description": "Înainte de a crea un cont, va trebui să creezi un grup. Grupul tău va conține inițial doar pe tine, dar vei putea invita și alte persoane ulterior. Membrii din grupul tău vor putea să partajeze planuri de mese, liste de cumpărături, rețete și multe altele!",
|
||||
"use-seed-data": "Utilizează setul de date a populării",
|
||||
"use-seed-data-description": "Mealie vine cu o colecție de Alimente, Unități, și Etichete care pot fi utilizate pentru a popula grupul tău cu date utile pentru organizarea rețetelor.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detalii Cont"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Новое уведомление",
|
||||
"event-notifiers": "Уведомления о событии",
|
||||
"apprise-url-skipped-if-blank": "URL-адрес (пропущен, если пусто)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Включить уведомления",
|
||||
"what-events": "На какие события следует настроить уведомления?",
|
||||
"user-events": "События пользователя",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "События тегов",
|
||||
"category-events": "События категорий",
|
||||
"when-a-new-user-joins-your-group": "Когда новый пользователь присоединяется к вашей группе",
|
||||
"recipe-events": "События Рецепта"
|
||||
"recipe-events": "События Рецепта",
|
||||
"label-events": "Ярлыки событий"
|
||||
},
|
||||
"general": {
|
||||
"add": "Добавить",
|
||||
|
@ -645,7 +647,7 @@
|
|||
"tree-view": "В виде дерева",
|
||||
"recipe-servings": "Порции",
|
||||
"recipe-yield": "Количество порций",
|
||||
"recipe-yield-text": "Recipe Yield Text",
|
||||
"recipe-yield-text": "Количество порций рецепта",
|
||||
"unit": "Единица измерения",
|
||||
"upload-image": "Загрузить изображение",
|
||||
"screen-awake": "Держать экран включенным",
|
||||
|
@ -654,25 +656,27 @@
|
|||
"recipe-actions": "Действия с рецептом",
|
||||
"parser": {
|
||||
"ingredient-parser": "Разделитель ингредиентов",
|
||||
"explanation": "To use the ingredient parser, click the 'Parse All' button to start the process. Once the processed ingredients are available, you can review the items and verify that they were parsed correctly. The model's confidence score is displayed on the right of the item title. This score is an average of all the individual scores and may not always be completely accurate.",
|
||||
"explanation": "Чтобы использовать парсер ингредиентов, нажмите кнопку «Обработать все». Как только обработанные ингредиенты будут доступны, Вы можете просмотреть элементы и убедиться, что они были обработаны правильно. Показатель достоверности модели отображается справа от названия элемента. Этот показатель рассчитывается как среднее всех индивидуальных результатов и не всегда полностью точен.",
|
||||
"alerts-explainer": "Оповещение появится если подходящие продукты или единица измерения найдены, но не занесены в базу данных.",
|
||||
"select-parser": "Выбрать Разделитель",
|
||||
"natural-language-processor": "Обработчик естественного языка",
|
||||
"brute-parser": "Brute Parser",
|
||||
"brute-parser": "Грубый Парсер",
|
||||
"openai-parser": "OpenAI Parser",
|
||||
"parse-all": "Обработать все",
|
||||
"no-unit": "Без единиц",
|
||||
"missing-unit": "Создать недостающую единицу: {unit}",
|
||||
"missing-food": "Создать недостающую еду: {food}",
|
||||
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||
"this-unit-could-not-be-parsed-automatically": "Эта единица не может быть обработана автоматически",
|
||||
"this-food-could-not-be-parsed-automatically": "Этот продукт не может быть обработан автоматически",
|
||||
"no-food": "Нет еды"
|
||||
},
|
||||
"reset-servings-count": "Сбросить количество порций",
|
||||
"not-linked-ingredients": "Дополнительные ингредиенты",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-another-image": "Загрузите другое изображение",
|
||||
"upload-images": "Загрузить изображения",
|
||||
"upload-more-images": "Загрузить больше изображений"
|
||||
"upload-more-images": "Загрузить больше изображений",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Поиск рецептов",
|
||||
|
@ -682,8 +686,8 @@
|
|||
"missing": "Отсутствует",
|
||||
"no-recipes-found": "Рецепты не найдены",
|
||||
"no-recipes-found-description": "Попробуйте добавить больше ингредиентов для поиска или измените настройки фильтров",
|
||||
"include-ingredients-on-hand": "Include Ingredients On Hand",
|
||||
"include-tools-on-hand": "Include Tools On Hand",
|
||||
"include-ingredients-on-hand": "Включать ингредиенты в наличии, под рукой",
|
||||
"include-tools-on-hand": "Включать инструменты в наличии, под рукой",
|
||||
"max-missing-ingredients": "Максимальное количество отсутствующих ингредиентов",
|
||||
"max-missing-tools": "Максимальное количество отсутствующих инструментов",
|
||||
"selected-tools": "Выбранные инструменты",
|
||||
|
@ -1072,7 +1076,7 @@
|
|||
"example-food-singular": "пр. Луковица",
|
||||
"example-food-plural": "пр. Луковиц",
|
||||
"label-overwrite-warning": "Это назначит выбранную метку всем выбранным продуктам и потенциально перезапишет существующие метки.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"on-hand-checkbox-label": "Установка этого флага сделает этот продукт неотмеченным по умолчанию при добавлении рецепта в список покупок."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Заполняет базу данных рядовыми единицами измерений на основе выбранного языка.",
|
||||
|
@ -1125,9 +1129,9 @@
|
|||
"source-unit-will-be-deleted": "Первая единица измерения будет удалена"
|
||||
},
|
||||
"recipe-actions": {
|
||||
"recipe-actions-data": "Recipe Actions Data",
|
||||
"new-recipe-action": "New Recipe Action",
|
||||
"edit-recipe-action": "Edit Recipe Action",
|
||||
"recipe-actions-data": "Данные действий рецепта",
|
||||
"new-recipe-action": "Новое действие с рецептом",
|
||||
"edit-recipe-action": "Редактировать действие рецепта",
|
||||
"action-type": "Тип Действия"
|
||||
},
|
||||
"create-alias": "Создать псевдоним",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Сведения о группе",
|
||||
"group-details-description": "Прежде чем создать учетную запись, вам нужно создать группу. В вашей группе будете только вы, но вы сможете пригласить других позже. Участники группы могут обмениваться планами питания, списками покупок, рецептами и многим другим!",
|
||||
"use-seed-data": "Использовать дефолтные значения",
|
||||
"use-seed-data-description": "Mealie идёт с коллекцией продуктов, единиц измерения и меток, которые могут быть использованы для заполнения вашей группы полезными данными для организации ваших рецептов.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Параметры учетной записи"
|
||||
},
|
||||
"validation": {
|
||||
|
@ -1290,18 +1294,18 @@
|
|||
"first-time-setup": "Первоначальная Настройка",
|
||||
"welcome-to-mealie-get-started": "Добро пожаловать в Mealie! Давайте начнем",
|
||||
"already-set-up-bring-to-homepage": "Я уже готов, просто открой домашнюю страницу",
|
||||
"common-settings-for-new-sites": "Here are some common settings for new sites",
|
||||
"common-settings-for-new-sites": "Ниже приведены общие настройки для новых сайтов",
|
||||
"setup-complete": "Настройка завершена!",
|
||||
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
|
||||
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
|
||||
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."
|
||||
"here-are-a-few-things-to-help-you-get-started": "Вот несколько вещей, которые помогут Вам начать работу с Mealie",
|
||||
"restore-from-v1-backup": "У вас есть резервная копия предыдущего экземпляра Mealie v1? Вы можете восстановить ее здесь.",
|
||||
"manage-profile-or-get-invite-link": "Управляйте своим профилем или получите ссылку-приглашение, чтобы поделиться ею с другими."
|
||||
},
|
||||
"debug-openai-services": "Отладка OpenAI сервисов",
|
||||
"debug-openai-services-description": "Use this page to debug OpenAI services. You can test your OpenAI connection and see the results here. If you have image services enabled, you can also provide an image.",
|
||||
"debug-openai-services-description": "Используйте эту страницу для отладки служб OpenAI. Вы можете проверить подключение к OpenAI и посмотреть результаты здесь. Если у Вас включены службы изображений, Вы также можете предоставить изображение.",
|
||||
"run-test": "Запустить тест",
|
||||
"test-results": "Результаты тестов",
|
||||
"group-delete-note": "Groups with users or households cannot be deleted",
|
||||
"household-delete-note": "Households with users cannot be deleted"
|
||||
"group-delete-note": "Группы, в которых есть пользователи или домохозяйства, не могут быть удалены",
|
||||
"household-delete-note": "Домохозяйства, в которых есть пользователи, не могут быть удалены"
|
||||
},
|
||||
"profile": {
|
||||
"welcome-user": "👋 Добро пожаловать, {0}!",
|
||||
|
@ -1314,7 +1318,7 @@
|
|||
"group-statistics": "Статистика группы",
|
||||
"group-statistics-description": "Статистика вашей группы дает некоторую информацию о том, как вы используете Mealie.",
|
||||
"household-statistics": "Статистика домохозяйства",
|
||||
"household-statistics-description": "Your Household Statistics provide some insight how you're using Mealie.",
|
||||
"household-statistics-description": "Статистика Вашего домохозяйства дает Вам некоторое представление о том, как Вы используете Mealie.",
|
||||
"storage-capacity": "Емкость хранилища",
|
||||
"storage-capacity-description": "Указанный размер хранилища - это подсчёт размера изображений и приложений рецептов загруженных вами.",
|
||||
"personal": "Личное",
|
||||
|
@ -1324,8 +1328,8 @@
|
|||
"api-tokens-description": "Управляйте вашими API-токенами для доступа сторонних приложений.",
|
||||
"group-description": "Эти элементы доступны внутри вашей группы. Редактирование одного из них изменит их для всей группы!",
|
||||
"group-settings": "Настройки группы",
|
||||
"group-settings-description": "Manage your common group settings, like privacy settings.",
|
||||
"household-description": "These items are shared within your household. Editing one of them will change it for the whole household!",
|
||||
"group-settings-description": "Управляйте общими настройками группы, такими как настройки конфиденциальности.",
|
||||
"household-description": "Эти элементы доступны внутри Вашего домохозяйства. Редактирование одного из них изменит их для всего домохозяйства!",
|
||||
"household-settings": "Настройки домохозяйства",
|
||||
"household-settings-description": "Управляйте настройками вашего домохозяйства, такими как настройки плана питания и конфиденциальности.",
|
||||
"cookbooks-description": "Управление коллекцией категорий рецептов и созданием страниц для них.",
|
||||
|
@ -1355,9 +1359,9 @@
|
|||
},
|
||||
"cookbook": {
|
||||
"cookbooks": "Книги рецептов",
|
||||
"description": "Cookbooks are another way to organize recipes by creating cross sections of recipes, organizers, and other filters. Creating a cookbook will add an entry to the side-bar and all the recipes with the filters chosen will be displayed in the cookbook.",
|
||||
"description": "Книги рецептов – это еще один способ организовать рецепты путем создания разделов рецептов, органайзеров и других фильтров. Создание книги рецептов добавит запись в боковую панель, и все рецепты с выбранными фильтрами будут отображаться в книге рецептов.",
|
||||
"hide-cookbooks-from-other-households": "Скрыть книги рецептов от других домохозяйств",
|
||||
"hide-cookbooks-from-other-households-description": "When enabled, only cookbooks from your household will appear on the sidebar",
|
||||
"hide-cookbooks-from-other-households-description": "Если эта функция включена, на боковой панели будут отображаться только книги рецептов из Вашего домохозяйства",
|
||||
"public-cookbook": "Публичные книги рецептов",
|
||||
"public-cookbook-description": "Публичными книгами рецептов можно делиться с людьми без аккаунта в Mealie, и они будут отображаться на странице вашей группы.",
|
||||
"filter-options": "Параметры фильтрации",
|
||||
|
@ -1385,13 +1389,13 @@
|
|||
"is-less-than-or-equal-to": "меньше или равно"
|
||||
},
|
||||
"relational-keywords": {
|
||||
"is": "is",
|
||||
"is-not": "is not",
|
||||
"is": "соответствует",
|
||||
"is-not": "не соответствует",
|
||||
"is-one-of": "один из",
|
||||
"is-not-one-of": "не один из",
|
||||
"contains-all-of": "содержит все",
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
"is-like": "содержит",
|
||||
"is-not-like": "не содержит"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Nové upozornenie",
|
||||
"event-notifiers": "Upozornenia udalostí",
|
||||
"apprise-url-skipped-if-blank": "Informačná URL (preskočená, ak je prázdna)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Zapnúť notifikátor",
|
||||
"what-events": "Pre ktoré udalosti si želáte zapnúť notifikátor?",
|
||||
"user-events": "Udalosti používateľa",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Udalosti štítkov",
|
||||
"category-events": "Udalosti kategórií",
|
||||
"when-a-new-user-joins-your-group": "Keď sa k vašej skupine pripojí nový používateľ",
|
||||
"recipe-events": "Udalosti receptov"
|
||||
"recipe-events": "Udalosti receptov",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Pridať",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ďalšie suroviny",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Nahrať obrázky",
|
||||
"upload-more-images": "Nahrať ďalšie obrázky"
|
||||
"upload-more-images": "Nahrať ďalšie obrázky",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Hľadač receptov",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Podrobnosti o skupine",
|
||||
"group-details-description": "Pred vytvorením účtu musíte vytvoriť skupinu. Vaša skupina bude obsahovať iba vás, ale neskôr budete môcť pozvať ostatných. Členovia vašej skupiny môžu zdieľať stravovacie plány, nákupné zoznamy, recepty a ďalšie!",
|
||||
"use-seed-data": "Použiť predvolené dáta",
|
||||
"use-seed-data-description": "Mealie prichádza so zbierkou potravín, jednotiek a štítkov, ktoré možno použiť na naplnenie vašej skupiny užitočnými údajmi na organizáciu vašich receptov.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Detaily účtu"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Novo obvestilo",
|
||||
"event-notifiers": "Obvestila o dogodkih",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (preskočeno, če je prazno)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Vključi obvestila",
|
||||
"what-events": "Katere dogodke naj spremlja obveščevalni sistem?",
|
||||
"user-events": "Dogodki uporabnika",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Dogodki značk",
|
||||
"category-events": "Dogodki kategorij",
|
||||
"when-a-new-user-joins-your-group": "Ko se novi uporabnik pridruži tvoji skupini",
|
||||
"recipe-events": "Dogodki receptov"
|
||||
"recipe-events": "Dogodki receptov",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Dodaj",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Dodatne sestavine",
|
||||
"upload-another-image": "Naloži drugo sliko",
|
||||
"upload-images": "Naloži slike",
|
||||
"upload-more-images": "Naloži več slik"
|
||||
"upload-more-images": "Naloži več slik",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Iskalnik receptov",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Detajli skupine",
|
||||
"group-details-description": "Preden kreirate račun, morate kreirati skupino. V skupini boste sprva samo vi, vendar imate možnost povabiti še ostale člane. Člani v vaši skupini lahko delijo načrte obrokov, nakupovalne sezname, recepte in še več!",
|
||||
"use-seed-data": "Uporabi privzete podatke",
|
||||
"use-seed-data-description": "Meali vključuje zbirko jedi, enot in oznak, ki se lahko uporabno uporabijo v vaši skupini za organizacijo receptov.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Podatki o računu"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Ново обавештење",
|
||||
"event-notifiers": "Обавештавач о догађају",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (прескочено ако је празно)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Омогући обавештење",
|
||||
"what-events": "На које догађаје би требао да се претплати овај обавештавач?",
|
||||
"user-events": "Догађаји корисника",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Догађаји ознаке",
|
||||
"category-events": "Догађаји категорије",
|
||||
"when-a-new-user-joins-your-group": "Када се нови корисник придружи вашој групи",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Add",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Пре него што креирате налог, морате креирати групу. Ваша група ће садржавати само вас, али касније ћете моћи позвати друге. Чланови ваше групе могу делити јеловнике, спискове за куповину, рецепте и још много тога!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Ny avisering",
|
||||
"event-notifiers": "Händelseavisering",
|
||||
"apprise-url-skipped-if-blank": "Apprise-URL (hoppa över om tom)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Aktivera avisering",
|
||||
"what-events": "Vilka händelser ska denna avisering prenumerera på?",
|
||||
"user-events": "Användarhändelser",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tagga händelser",
|
||||
"category-events": "Kategorihändelser",
|
||||
"when-a-new-user-joins-your-group": "När en ny användare går med i din grupp",
|
||||
"recipe-events": "Recepthändelser"
|
||||
"recipe-events": "Recepthändelser",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Lägg till",
|
||||
|
@ -472,7 +474,7 @@
|
|||
"comment": "Kommentar",
|
||||
"comments": "Kommentarer",
|
||||
"delete-confirmation": "Är du säker på att du vill ta bort detta recept?",
|
||||
"admin-delete-confirmation": "You're about to delete a recipe that isn't yours using admin permissions. Are you sure?",
|
||||
"admin-delete-confirmation": "Du är på väg att ta bort ett recept som inte är ditt med administratörsbehörigheter. Är du säker?",
|
||||
"delete-recipe": "Radera recept",
|
||||
"description": "Beskrivning",
|
||||
"disable-amount": "Inaktivera ingredienser mängder",
|
||||
|
@ -587,7 +589,7 @@
|
|||
"api-extras-description": "Recept API-tillägg är en viktig funktion i Mealie's API. Med hjälp av dem kan du skapa anpassade JSON-nyckel/värdepar i ett recept, som du kan referera till från tredjepartsapplikationer. Du kan använda dessa nycklar för att tillhandahålla information, till exempel för att trigga automatiseringar eller anpassade meddelanden som ska vidarebefordras till önskad enhet.",
|
||||
"message-key": "Meddelandenyckel",
|
||||
"parse": "Läs in",
|
||||
"ingredients-not-parsed-description": "It looks like your ingredients aren't parsed yet. Click the \"{parse}\" button below to parse your ingredients into structured foods.",
|
||||
"ingredients-not-parsed-description": "Det verkar som om dina ingredienser inte är tolkade ännu. Klicka på knappen \"{parse}\" nedan för att tolka dina ingredienser till strukturerade livsmedel.",
|
||||
"attach-images-hint": "Bifoga bilder genom att dra och släppa dem i redigeraren",
|
||||
"drop-image": "Släpp bild",
|
||||
"enable-ingredient-amounts-to-use-this-feature": "Aktivera ingrediensmängd för att använda denna funktion",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ytterligare ingredienser",
|
||||
"upload-another-image": "Ladda upp en annan bild",
|
||||
"upload-images": "Ladda upp bilder",
|
||||
"upload-more-images": "Ladda upp fler bilder"
|
||||
"upload-more-images": "Ladda upp fler bilder",
|
||||
"set-as-cover-image": "Använd som receptbild",
|
||||
"cover-image": "Receptbild"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Sök recept",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Gruppuppgifter",
|
||||
"group-details-description": "Innan du skapar ett konto måste du skapa en grupp. Din grupp kommer bara att innehålla dig, men du kommer att kunna bjuda in andra senare. Medlemmarna i din grupp kan dela måltidsplaner, inköpslistor, recept och mycket mer!",
|
||||
"use-seed-data": "Använd exempeldata",
|
||||
"use-seed-data-description": "Mealie innehåller en samling av livsmedel, enheter och etiketter som kan användas för att fylla din grupp med användbara data för att organisera dina recept.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Kontouppgifter"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Yeni bildirim",
|
||||
"event-notifiers": "Etkinlik Bildirimleri",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL'si (boşsa geçilir)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Bildiriciyi Etkinleştir",
|
||||
"what-events": "Bu bildirimci hangi olaylara abone olmalıdır?",
|
||||
"user-events": "Kullanıcı Etkinlikleri",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Etiket Etkinlikleri",
|
||||
"category-events": "Kategori Etkinlikleri",
|
||||
"when-a-new-user-joins-your-group": "Grubunuza yeni bir kullanıcı katıldığında",
|
||||
"recipe-events": "Tarif Etkinlikleri"
|
||||
"recipe-events": "Tarif Etkinlikleri",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Ekle",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Ek Malzemeler",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Tarif Bulucu",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Grup Detayları",
|
||||
"group-details-description": "Hesap oluşturmadan önce bir grup oluşturmanız gerekir. Grubunuzda yalnızca siz yer alacaksınız ancak daha sonra başkalarını da davet edebileceksiniz. Grubunuzdaki üyeler yemek planlarını, alışveriş listelerini, tarifleri ve daha fazlasını paylaşabilir!",
|
||||
"use-seed-data": "Tohum Verisi Kullan",
|
||||
"use-seed-data-description": "Mealie, grubunuzu tariflerinizi düzenlemenize yardımcı olacak yararlı verilerle doldurmak için kullanılabilecek bir Yiyecek, Birim ve Etiket koleksiyonuyla birlikte gelir.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Hesap Detayları"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Нове сповіщення",
|
||||
"event-notifiers": "Сповіщувачі",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (пропущено якщо порожній)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Увімкнути сповіщувач",
|
||||
"what-events": "На які події цей сповіщувач має бути підписаний?",
|
||||
"user-events": "Події користувача",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Події міток",
|
||||
"category-events": "Події категорій",
|
||||
"when-a-new-user-joins-your-group": "Коли новий користувач приєднується до групи",
|
||||
"recipe-events": "Події рецепту"
|
||||
"recipe-events": "Події рецепту",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Додати",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Додаткові продукти",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Шукач рецептів",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Деталі групи",
|
||||
"group-details-description": "Перед створенням облікового запису вам потрібно створити групу. Спочатку ваша група буде містити тільки вас, але ви зможете запрошувати інших пізніше. Учасники вашої групи можуть обмінюватися планами харчування, списками покупок, рецептами і багато чим іншим!",
|
||||
"use-seed-data": "Використати початкові дані",
|
||||
"use-seed-data-description": "Mealie має вбудований набір продуктів, одиниць виміру, та етикеток що можуть бути додані до вашої групи для допомоги в організації рецептів.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Деталі акаунта"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "Thông báo mới",
|
||||
"event-notifiers": "Event Notifiers",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (skipped if blank)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "Enable Notifier",
|
||||
"what-events": "What events should this notifier subscribe to?",
|
||||
"user-events": "User Events",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "Tag Events",
|
||||
"category-events": "Category Events",
|
||||
"when-a-new-user-joins-your-group": "When a new user joins your group",
|
||||
"recipe-events": "Recipe Events"
|
||||
"recipe-events": "Recipe Events",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Thêm",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "新通知",
|
||||
"event-notifiers": "事件通知器",
|
||||
"apprise-url-skipped-if-blank": "Apprise URL (如果为空则跳过)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "打开消息通知",
|
||||
"what-events": "该通知器需要订阅哪些事件?",
|
||||
"user-events": "用户事件",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "标签事件",
|
||||
"category-events": "分类事件",
|
||||
"when-a-new-user-joins-your-group": "当新用户加入您的群组时",
|
||||
"recipe-events": "食谱事件"
|
||||
"recipe-events": "食谱事件",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "添加",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "食谱搜索",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "群组详情",
|
||||
"group-details-description": "在你创建账户之前,需要先创建一个群组。此时群组将只包含你自己,但稍后你便可邀请其他人。 你的群组成员可以分享食谱、饮食计划、购物清单等!",
|
||||
"use-seed-data": "使用初始数据",
|
||||
"use-seed-data-description": "Mealie附带一套现成的“食品”、“单位”、“标签”数据,可以帮助你的群组管理食谱。",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "账户详情"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"new-notification": "新通知",
|
||||
"event-notifiers": "事件通知",
|
||||
"apprise-url-skipped-if-blank": "Apprise 網址(空白則略過)",
|
||||
"apprise-url-is-left-intentionally-blank": "Since Apprise URLs typically contain sensitive information, this field is left intentionally blank while editing. If you wish to update the URL, please enter the new one here, otherwise leave it blank to keep the current URL.",
|
||||
"enable-notifier": "啟用通知功能",
|
||||
"what-events": "要訂閱哪些事件通知?",
|
||||
"user-events": "用戶相關事件",
|
||||
|
@ -79,7 +80,8 @@
|
|||
"tag-events": "標籤事件",
|
||||
"category-events": "類別事件",
|
||||
"when-a-new-user-joins-your-group": "當新用戶加入您的群組時",
|
||||
"recipe-events": "食譜事件"
|
||||
"recipe-events": "食譜事件",
|
||||
"label-events": "Label Events"
|
||||
},
|
||||
"general": {
|
||||
"add": "Add",
|
||||
|
@ -672,7 +674,9 @@
|
|||
"not-linked-ingredients": "Additional Ingredients",
|
||||
"upload-another-image": "Upload another image",
|
||||
"upload-images": "Upload images",
|
||||
"upload-more-images": "Upload more images"
|
||||
"upload-more-images": "Upload more images",
|
||||
"set-as-cover-image": "Set as recipe cover image",
|
||||
"cover-image": "Cover image"
|
||||
},
|
||||
"recipe-finder": {
|
||||
"recipe-finder": "Recipe Finder",
|
||||
|
@ -1165,7 +1169,7 @@
|
|||
"group-details": "Group Details",
|
||||
"group-details-description": "Before you create an account you'll need to create a group. Your group will only contain you, but you'll be able to invite others later. Members in your group can share meal plans, shopping lists, recipes, and more!",
|
||||
"use-seed-data": "Use Seed Data",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes.",
|
||||
"use-seed-data-description": "Mealie ships with a collection of Foods, Units, and Labels that can be used to populate your group with helpful data for organizing your recipes. These are translated into the language you currently have selected. You can always add to or modify this data later.",
|
||||
"account-details": "Account Details"
|
||||
},
|
||||
"validation": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients";
|
||||
import { RecipeCookBook } from "~/lib/api/types/cookbook";
|
||||
import { ReadCookBook } from "~/lib/api/types/cookbook";
|
||||
import { ApiRequestInstance } from "~/lib/api/types/non-generated";
|
||||
|
||||
const prefix = "/api";
|
||||
|
@ -10,7 +10,7 @@ const routes = {
|
|||
cookbooksGroupSlugCookbookId: (groupSlug: string | number, cookbookId: string | number) => `${exploreGroupSlug(groupSlug)}/cookbooks/${cookbookId}`,
|
||||
};
|
||||
|
||||
export class PublicCookbooksApi extends BaseCRUDAPIReadOnly<RecipeCookBook> {
|
||||
export class PublicCookbooksApi extends BaseCRUDAPIReadOnly<ReadCookBook> {
|
||||
constructor(requests: ApiRequestInstance, groupSlug: string) {
|
||||
super(
|
||||
requests,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
@ -117,6 +117,7 @@ export interface CustomPageBase {
|
|||
export interface RecipeCategoryResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
|
@ -149,18 +150,21 @@ export interface RecipeSummary {
|
|||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
@ -41,65 +41,6 @@ export interface QueryFilterJSONPart {
|
|||
value?: string | string[] | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
slug?: string | null;
|
||||
position?: number;
|
||||
public?: boolean;
|
||||
queryFilterString?: string;
|
||||
groupId: string;
|
||||
householdId: string;
|
||||
id: string;
|
||||
queryFilter?: QueryFilterJSON;
|
||||
recipes: RecipeSummary[];
|
||||
}
|
||||
export interface RecipeSummary {
|
||||
id?: string | null;
|
||||
userId?: string;
|
||||
householdId?: string;
|
||||
groupId?: string;
|
||||
name?: string | null;
|
||||
slug?: string;
|
||||
image?: unknown;
|
||||
recipeServings?: number;
|
||||
recipeYieldQuantity?: number;
|
||||
recipeYield?: string | null;
|
||||
totalTime?: string | null;
|
||||
prepTime?: string | null;
|
||||
cookTime?: string | null;
|
||||
performTime?: string | null;
|
||||
description?: string | null;
|
||||
recipeCategory?: RecipeCategory[] | null;
|
||||
tags?: RecipeTag[] | null;
|
||||
tools?: RecipeTool[];
|
||||
rating?: number | null;
|
||||
orgURL?: string | null;
|
||||
dateAdded?: string | null;
|
||||
dateUpdated?: string | null;
|
||||
createdAt?: string | null;
|
||||
updatedAt?: string | null;
|
||||
lastMade?: string | null;
|
||||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface SaveCookBook {
|
||||
name: string;
|
||||
description?: string;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
@ -70,6 +70,9 @@ export interface GroupEventNotifierOptions {
|
|||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
labelCreated?: boolean;
|
||||
labelUpdated?: boolean;
|
||||
labelDeleted?: boolean;
|
||||
}
|
||||
export interface GroupEventNotifierOptionsOut {
|
||||
testMessage?: boolean;
|
||||
|
@ -94,6 +97,9 @@ export interface GroupEventNotifierOptionsOut {
|
|||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
labelCreated?: boolean;
|
||||
labelUpdated?: boolean;
|
||||
labelDeleted?: boolean;
|
||||
id: string;
|
||||
}
|
||||
export interface GroupEventNotifierOptionsSave {
|
||||
|
@ -119,6 +125,9 @@ export interface GroupEventNotifierOptionsSave {
|
|||
categoryCreated?: boolean;
|
||||
categoryUpdated?: boolean;
|
||||
categoryDeleted?: boolean;
|
||||
labelCreated?: boolean;
|
||||
labelUpdated?: boolean;
|
||||
labelDeleted?: boolean;
|
||||
notifierId: string;
|
||||
}
|
||||
export interface GroupEventNotifierOut {
|
||||
|
@ -166,6 +175,7 @@ export interface GroupRecipeActionOut {
|
|||
export interface GroupRecipeActionPayload {
|
||||
action: GroupRecipeActionOut;
|
||||
content: unknown;
|
||||
recipeScale: number;
|
||||
}
|
||||
export interface HouseholdCreate {
|
||||
groupId?: string | null;
|
||||
|
@ -587,18 +597,21 @@ export interface RecipeSummary {
|
|||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
*/
|
||||
|
||||
import type { HouseholdSummary } from "./household";
|
||||
|
||||
export type PlanEntryType = "breakfast" | "lunch" | "dinner" | "side";
|
||||
export type PlanRulesDay = "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday" | "unset";
|
||||
export type PlanRulesType = "breakfast" | "lunch" | "dinner" | "side" | "unset";
|
||||
|
@ -44,9 +42,6 @@ export interface PlanRulesOut {
|
|||
householdId: string;
|
||||
id: string;
|
||||
queryFilter?: QueryFilterJSON;
|
||||
categories?: RecipeCategory[];
|
||||
tags?: RecipeTag[];
|
||||
households?: HouseholdSummary[];
|
||||
}
|
||||
export interface QueryFilterJSON {
|
||||
parts?: QueryFilterJSONPart[];
|
||||
|
@ -108,18 +103,21 @@ export interface RecipeSummary {
|
|||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
|
|
|
@ -19,6 +19,7 @@ export interface AssignCategories {
|
|||
export interface CategoryBase {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
}
|
||||
export interface AssignSettings {
|
||||
|
@ -40,6 +41,7 @@ export interface AssignTags {
|
|||
export interface TagBase {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
}
|
||||
export interface CategoryIn {
|
||||
|
@ -48,8 +50,8 @@ export interface CategoryIn {
|
|||
export interface CategoryOut {
|
||||
name: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
groupId: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface CategorySave {
|
||||
name: string;
|
||||
|
@ -97,11 +99,13 @@ export interface CreateRecipeBulk {
|
|||
}
|
||||
export interface RecipeCategory {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeTag {
|
||||
id?: string | null;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
|
@ -223,7 +227,7 @@ export interface Recipe {
|
|||
groupId?: string;
|
||||
name?: string | null;
|
||||
slug?: string;
|
||||
image?: string;
|
||||
image?: unknown;
|
||||
recipeServings?: number;
|
||||
recipeYieldQuantity?: number;
|
||||
recipeYield?: string | null;
|
||||
|
@ -255,6 +259,7 @@ export interface Recipe {
|
|||
}
|
||||
export interface RecipeTool {
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
|
@ -293,6 +298,7 @@ export interface UserBase {
|
|||
export interface RecipeCategoryResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
|
@ -399,6 +405,7 @@ export interface RecipeSuggestionResponseItem {
|
|||
export interface RecipeTagResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
|
@ -447,12 +454,14 @@ export interface RecipeToolOut {
|
|||
name: string;
|
||||
householdsWithTool?: string[];
|
||||
id: string;
|
||||
groupId: string;
|
||||
slug: string;
|
||||
}
|
||||
export interface RecipeToolResponse {
|
||||
name: string;
|
||||
householdsWithTool?: string[];
|
||||
id: string;
|
||||
groupId: string;
|
||||
slug: string;
|
||||
recipes?: RecipeSummary[];
|
||||
}
|
||||
|
@ -507,7 +516,7 @@ export interface ScrapeRecipeTest {
|
|||
url: string;
|
||||
useOpenAI?: boolean;
|
||||
}
|
||||
export interface SlugResponse { }
|
||||
export interface SlugResponse {}
|
||||
export interface TagIn {
|
||||
name: string;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
/* This file was automatically generated from pydantic models by running pydantic2ts.
|
||||
/* Do not modify it by hand - just update the pydantic models and then re-run the script
|
||||
|
@ -63,6 +63,7 @@ export interface GroupInDB {
|
|||
export interface CategoryBase {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
}
|
||||
export interface ReadWebhook {
|
||||
|
@ -197,7 +198,6 @@ export interface UserBase {
|
|||
canManage?: boolean;
|
||||
canManageHousehold?: boolean;
|
||||
canOrganize?: boolean;
|
||||
advancedOptions?: boolean;
|
||||
}
|
||||
export interface UserIn {
|
||||
id?: string | null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BaseCRUDAPI } from "../base/base-clients";
|
||||
import type { CreateCookBook, RecipeCookBook, UpdateCookBook } from "~/lib/api/types/cookbook";
|
||||
import type { CreateCookBook, ReadCookBook, UpdateCookBook } from "~/lib/api/types/cookbook";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
|
@ -8,7 +8,7 @@ const routes = {
|
|||
cookbooksId: (id: number) => `${prefix}/households/cookbooks/${id}`,
|
||||
};
|
||||
|
||||
export class CookbookAPI extends BaseCRUDAPI<CreateCookBook, RecipeCookBook, UpdateCookBook> {
|
||||
export class CookbookAPI extends BaseCRUDAPI<CreateCookBook, ReadCookBook, UpdateCookBook> {
|
||||
baseRoute: string = routes.cookbooks;
|
||||
itemRoute = routes.cookbooksId;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<v-container fill-height
|
||||
<v-container
|
||||
fill-height
|
||||
fluid
|
||||
class="d-flex justify-center align-center"
|
||||
width="1200px"
|
||||
|
@ -8,7 +9,8 @@
|
|||
'bg-off-white': !$vuetify.theme.current.dark,
|
||||
}"
|
||||
>
|
||||
<BaseWizard v-model="currentPage"
|
||||
<BaseWizard
|
||||
v-model="currentPage"
|
||||
:max-page-number="totalPages"
|
||||
:title="$t('admin.setup.first-time-setup')"
|
||||
:prev-button-show="activeConfig.showPrevButton"
|
||||
|
@ -20,13 +22,15 @@
|
|||
:is-submitting="isSubmitting"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<v-container v-if="currentPage === Pages.LANDING"
|
||||
<v-container
|
||||
v-if="currentPage === Pages.LANDING"
|
||||
class="mb-12"
|
||||
>
|
||||
<v-card-title class="text-h4 justify-center text-center">
|
||||
{{ $t('admin.setup.welcome-to-mealie-get-started') }}
|
||||
</v-card-title>
|
||||
<v-btn :to="groupSlug ? `/g/${groupSlug}` : '/login'"
|
||||
<v-btn
|
||||
:to="groupSlug ? `/g/${groupSlug}` : '/login'"
|
||||
rounded
|
||||
variant="outlined"
|
||||
color="grey-lighten-1"
|
||||
|
@ -36,35 +40,42 @@
|
|||
{{ $t('admin.setup.already-set-up-bring-to-homepage') }}
|
||||
</v-btn>
|
||||
</v-container>
|
||||
|
||||
<v-container v-if="currentPage === Pages.USER_INFO">
|
||||
<UserRegistrationForm />
|
||||
</v-container>
|
||||
|
||||
<v-container v-if="currentPage === Pages.PAGE_2">
|
||||
<v-card-title class="headline justify-center">
|
||||
<v-card-title class="headline justify-center pa-0">
|
||||
{{ $t('admin.setup.common-settings-for-new-sites') }}
|
||||
</v-card-title>
|
||||
<AutoForm v-model="commonSettings"
|
||||
<AutoForm
|
||||
v-model="commonSettings"
|
||||
:items="commonSettingsForm"
|
||||
/>
|
||||
</v-container>
|
||||
|
||||
<v-container v-if="currentPage === Pages.CONFIRM">
|
||||
<v-card-title class="headline justify-center">
|
||||
{{ $t("general.confirm-how-does-everything-look") }}
|
||||
</v-card-title>
|
||||
<v-list>
|
||||
<template v-for="(item, idx) in confirmationData">
|
||||
<v-list-item v-if="item.display"
|
||||
<v-list-item
|
||||
v-if="item.display"
|
||||
:key="idx"
|
||||
>
|
||||
<v-list-item-title> {{ item.text }} </v-list-item-title>
|
||||
<v-list-item-subtitle> {{ item.value }} </v-list-item-subtitle>
|
||||
<v-list-item-title>{{ item.text }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ item.value }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-divider v-if="idx !== confirmationData.length - 1"
|
||||
<v-divider
|
||||
v-if="idx !== confirmationData.length - 1"
|
||||
:key="`divider-${idx}`"
|
||||
/>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-container>
|
||||
|
||||
<v-container v-if="currentPage === Pages.END">
|
||||
<v-card-title class="text-h4 justify-center">
|
||||
{{ $t('admin.setup.setup-complete') }}
|
||||
|
@ -72,7 +83,8 @@
|
|||
<v-card-title class="text-h6 justify-center">
|
||||
{{ $t('admin.setup.here-are-a-few-things-to-help-you-get-started') }}
|
||||
</v-card-title>
|
||||
<div v-for="link, idx in setupCompleteLinks"
|
||||
<div
|
||||
v-for="link, idx in setupCompleteLinks"
|
||||
:key="idx"
|
||||
class="px-4 pt-4"
|
||||
>
|
||||
|
@ -82,7 +94,8 @@
|
|||
{{ link.section }}
|
||||
</v-card-text>
|
||||
</div>
|
||||
<v-btn :to="link.to"
|
||||
<v-btn
|
||||
:to="link.to"
|
||||
color="info"
|
||||
>
|
||||
{{ link.text }}
|
||||
|
|
|
@ -32,15 +32,30 @@
|
|||
lg="4"
|
||||
xl="3"
|
||||
>
|
||||
<v-col>
|
||||
<ImageCropper
|
||||
:img="imageUrl"
|
||||
cropper-height="100%"
|
||||
cropper-width="100%"
|
||||
:submitted="loading"
|
||||
class="mt-4"
|
||||
class="mt-4 mb-2"
|
||||
@save="(croppedImage) => updateUploadedImage(index, croppedImage)"
|
||||
@delete="clearImage(index)"
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
v-if="uploadedImages.length > 1"
|
||||
:disabled="loading || index === 0"
|
||||
color="primary"
|
||||
@click="() => setCoverImage(index)"
|
||||
>
|
||||
<v-icon start>
|
||||
{{ index === 0 ? $globals.icons.check : $globals.icons.fileImage }}
|
||||
</v-icon>
|
||||
|
||||
{{ index === 0 ? $t("recipe.cover-image") : $t("recipe.set-as-cover-image") }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
@ -106,11 +121,12 @@ export default defineNuxtComponent({
|
|||
}
|
||||
|
||||
function clearImage(index: number) {
|
||||
// Revoke _before_ splicing
|
||||
URL.revokeObjectURL(uploadedImagesPreviewUrls.value[index]);
|
||||
|
||||
uploadedImages.value = uploadedImages.value.filter((_, i) => i !== index);
|
||||
uploadedImageNames.value = uploadedImageNames.value.filter((_, i) => i !== index);
|
||||
uploadedImagesPreviewUrls.value = uploadedImagesPreviewUrls.value.filter((_, i) => i !== index);
|
||||
uploadedImages.value.splice(index, 1);
|
||||
uploadedImageNames.value.splice(index, 1);
|
||||
uploadedImagesPreviewUrls.value.splice(index, 1);
|
||||
}
|
||||
|
||||
async function createRecipe() {
|
||||
|
@ -119,6 +135,7 @@ export default defineNuxtComponent({
|
|||
}
|
||||
|
||||
state.loading = true;
|
||||
|
||||
const translateLanguage = shouldTranslate.value ? i18n.locale : undefined;
|
||||
const { data, error } = await api.recipes.createOneFromImages(uploadedImages.value, translateLanguage?.value);
|
||||
if (error || !data) {
|
||||
|
@ -135,6 +152,32 @@ export default defineNuxtComponent({
|
|||
uploadedImagesPreviewUrls.value[index] = URL.createObjectURL(croppedImage);
|
||||
}
|
||||
|
||||
function swapItem(array: any[], i: number, j: number) {
|
||||
if (i < 0 || j < 0 || i >= array.length || j >= array.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
|
||||
function swapImages(i: number, j: number) {
|
||||
swapItem(uploadedImages.value, i, j);
|
||||
swapItem(uploadedImageNames.value, i, j);
|
||||
swapItem(uploadedImagesPreviewUrls.value, i, j);
|
||||
}
|
||||
|
||||
// Put the intended cover image at the start of the array
|
||||
// The backend currently sets the first image as the cover image
|
||||
function setCoverImage(index: number) {
|
||||
if (index < 0 || index >= uploadedImages.value.length || index === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
swapImages(0, index);
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
domUrlForm,
|
||||
|
@ -145,6 +188,7 @@ export default defineNuxtComponent({
|
|||
clearImage,
|
||||
createRecipe,
|
||||
updateUploadedImage,
|
||||
setCoverImage,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
<v-text-field
|
||||
v-model="notifiers[index].appriseUrl"
|
||||
:label="$t('events.apprise-url-skipped-if-blank')"
|
||||
:hint="$t('events.apprise-url-is-left-intentionally-blank')"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="notifiers[index].enabled"
|
||||
|
@ -368,6 +369,24 @@ export default defineNuxtComponent({
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
text: i18n.t("events.label-events"),
|
||||
options: [
|
||||
{
|
||||
text: i18n.t("general.create") as string,
|
||||
key: "labelCreated",
|
||||
},
|
||||
{
|
||||
text: i18n.t("general.update") as string,
|
||||
key: "labelUpdated",
|
||||
},
|
||||
{
|
||||
text: i18n.t("general.delete") as string,
|
||||
key: "labelDeleted",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
|
|
|
@ -18,10 +18,20 @@
|
|||
{{ $t('user.it-looks-like-this-is-your-first-time-logging-in') }}
|
||||
</p>
|
||||
<p class="mb-1">
|
||||
<strong>{{ $t('user.username') }}:</strong> changeme@example.com
|
||||
<strong>{{ $t('user.username') }}: </strong>changeme@example.com
|
||||
<AppButtonCopy
|
||||
copy-text="changeme@example.com"
|
||||
color="info"
|
||||
btn-class="h-auto"
|
||||
/>
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
<strong>{{ $t('user.password') }}:</strong> MyPassword
|
||||
<strong>{{ $t('user.password') }}: </strong>MyPassword
|
||||
<AppButtonCopy
|
||||
copy-text="MyPassword"
|
||||
color="info"
|
||||
btn-class="h-auto"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
{{ $t('user.dont-want-to-see-this-anymore-be-sure-to-change-your-email') }}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
class="md-container"
|
||||
>
|
||||
<BaseDialog
|
||||
v-model="checkAllDialog"
|
||||
v-model="state.checkAllDialog"
|
||||
:title="$t('general.confirm')"
|
||||
can-confirm
|
||||
@confirm="checkAll"
|
||||
|
@ -15,7 +15,7 @@
|
|||
</BaseDialog>
|
||||
|
||||
<BaseDialog
|
||||
v-model="uncheckAllDialog"
|
||||
v-model="state.uncheckAllDialog"
|
||||
:title="$t('general.confirm')"
|
||||
can-confirm
|
||||
@confirm="uncheckAll"
|
||||
|
@ -26,7 +26,7 @@
|
|||
</BaseDialog>
|
||||
|
||||
<BaseDialog
|
||||
v-model="deleteCheckedDialog"
|
||||
v-model="state.deleteCheckedDialog"
|
||||
:title="$t('general.confirm')"
|
||||
can-confirm
|
||||
@confirm="deleteChecked"
|
||||
|
@ -90,11 +90,6 @@
|
|||
text: '',
|
||||
event: 'three-dot',
|
||||
children: [
|
||||
{
|
||||
icon: $globals.icons.tags,
|
||||
text: $t('shopping-list.toggle-label-sort'),
|
||||
event: 'sort-by-labels',
|
||||
},
|
||||
{
|
||||
icon: $globals.icons.tags,
|
||||
text: $t('shopping-list.reorder-labels'),
|
||||
|
@ -111,7 +106,6 @@
|
|||
@edit="edit = true"
|
||||
@three-dot="threeDot = true"
|
||||
@check="openCheckAll"
|
||||
@sort-by-labels="sortByLabels"
|
||||
@copy-plain="copyListItems('plain')"
|
||||
@copy-markdown="copyListItems('markdown')"
|
||||
@reorder-labels="toggleReorderLabelsDialog()"
|
||||
|
@ -159,40 +153,6 @@
|
|||
</BaseButton>
|
||||
</div>
|
||||
|
||||
<!-- View without Label grouping -->
|
||||
<div v-if="!preferences.viewByLabel">
|
||||
<VueDraggable
|
||||
v-model="listItems.unchecked"
|
||||
handle=".handle"
|
||||
:delay="250"
|
||||
:delay-on-touch-only="true"
|
||||
@start="loadingCounter += 1"
|
||||
@end="loadingCounter -= 1"
|
||||
@update:model-value="updateIndexUnchecked"
|
||||
>
|
||||
<v-lazy
|
||||
v-for="(item, index) in listItems.unchecked"
|
||||
:key="item.id"
|
||||
class="my-2"
|
||||
>
|
||||
<ShoppingListItem
|
||||
v-model="listItems.unchecked[index]"
|
||||
class="my-2 my-sm-0"
|
||||
:show-label="true"
|
||||
:labels="allLabels || []"
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
:recipes="recipeMap"
|
||||
@checked="saveListItem"
|
||||
@save="saveListItem"
|
||||
@delete="deleteListItem(item)"
|
||||
/>
|
||||
</v-lazy>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
|
||||
<!-- View By Label -->
|
||||
<div v-else>
|
||||
<div
|
||||
v-for="(value, key) in itemsByLabel"
|
||||
:key="key"
|
||||
|
@ -230,7 +190,6 @@
|
|||
>
|
||||
<ShoppingListItem
|
||||
v-model="value[index]"
|
||||
:show-label="false"
|
||||
:labels="allLabels || []"
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
|
@ -244,7 +203,6 @@
|
|||
</div>
|
||||
</v-expand-transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reorder Labels -->
|
||||
<BaseDialog
|
||||
|
@ -359,12 +317,12 @@
|
|||
</div>
|
||||
<v-divider class="my-4" />
|
||||
<RecipeList
|
||||
:recipes="Array.from(recipeMap.values())"
|
||||
:recipes="recipeList"
|
||||
show-description
|
||||
:disabled="isOffline"
|
||||
>
|
||||
<template
|
||||
v-for="(recipe, index) in recipeMap.values()"
|
||||
v-for="(recipe, index) in recipeList"
|
||||
#[`actions-${recipe.id}`]
|
||||
:key="'item-actions-decrease' + recipe.id"
|
||||
>
|
||||
|
@ -408,26 +366,14 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import { useIdle, useOnline, useToggle } from "@vueuse/core";
|
||||
import { useCopyList } from "~/composables/use-copy";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import MultiPurposeLabelSection from "~/components/Domain/ShoppingList/MultiPurposeLabelSection.vue";
|
||||
import ShoppingListItem from "~/components/Domain/ShoppingList/ShoppingListItem.vue";
|
||||
import type { ShoppingListItemOut, ShoppingListMultiPurposeLabelOut, ShoppingListOut } from "~/lib/api/types/household";
|
||||
import RecipeList from "~/components/Domain/Recipe/RecipeList.vue";
|
||||
import ShoppingListItemEditor from "~/components/Domain/ShoppingList/ShoppingListItemEditor.vue";
|
||||
import { useFoodStore, useLabelStore, useUnitStore } from "~/composables/store";
|
||||
import { useShoppingListItemActions } from "~/composables/use-shopping-list-item-actions";
|
||||
import { useShoppingListPreferences } from "~/composables/use-users/preferences";
|
||||
import { getTextColor } from "~/composables/use-text-color";
|
||||
import { uuid4 } from "~/composables/use-utils";
|
||||
|
||||
type CopyTypes = "plain" | "markdown";
|
||||
|
||||
interface PresentLabel {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
import { useShoppingListPage } from "~/composables/shopping-list-page/use-shopping-list-page";
|
||||
|
||||
export default defineNuxtComponent({
|
||||
components: {
|
||||
|
@ -437,809 +383,34 @@ export default defineNuxtComponent({
|
|||
RecipeList,
|
||||
ShoppingListItemEditor,
|
||||
},
|
||||
// middleware: "sidebase-auth",
|
||||
setup() {
|
||||
const { mdAndUp } = useDisplay();
|
||||
const i18n = useI18n();
|
||||
const $auth = useMealieAuth();
|
||||
const preferences = useShoppingListPreferences();
|
||||
|
||||
const isOffline = computed(() => useOnline().value === false);
|
||||
|
||||
useSeoMeta({
|
||||
title: i18n.t("shopping-list.shopping-list"),
|
||||
});
|
||||
|
||||
const { idle } = useIdle(5 * 60 * 1000); // 5 minutes
|
||||
const loadingCounter = ref(1);
|
||||
const recipeReferenceLoading = ref(false);
|
||||
const userApi = useUserApi();
|
||||
|
||||
const edit = ref(false);
|
||||
const threeDot = ref(false);
|
||||
const reorderLabelsDialog = ref(false);
|
||||
const preserveItemOrder = ref(false);
|
||||
|
||||
const route = useRoute();
|
||||
const groupSlug = computed(() => route.params.groupSlug as string || $auth.user.value?.groupSlug || "");
|
||||
const id = route.params.id as string;
|
||||
const shoppingListItemActions = useShoppingListItemActions(id);
|
||||
|
||||
const state = reactive({
|
||||
checkAllDialog: false,
|
||||
uncheckAllDialog: false,
|
||||
deleteCheckedDialog: false,
|
||||
});
|
||||
|
||||
// ===============================================================
|
||||
// Shopping List Actions
|
||||
|
||||
const shoppingList = ref<ShoppingListOut | null>(null);
|
||||
async function fetchShoppingList() {
|
||||
const data = await shoppingListItemActions.getList();
|
||||
return data;
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
loadingCounter.value += 1;
|
||||
try {
|
||||
await shoppingListItemActions.process();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
let newListValue: typeof shoppingList.value = null;
|
||||
try {
|
||||
newListValue = await fetchShoppingList();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
// only update the list with the new value if we're not loading, to prevent UI jitter
|
||||
if (loadingCounter.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent overwriting local changes with stale backend data when offline
|
||||
if (isOffline.value) {
|
||||
// Do not update shoppingList.value from backend when offline
|
||||
updateListItemOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not connected to the network, this will be null, so we don't want to clear the list
|
||||
if (newListValue) {
|
||||
shoppingList.value = newListValue;
|
||||
}
|
||||
|
||||
updateListItemOrder();
|
||||
}
|
||||
|
||||
function updateListItemOrder() {
|
||||
if (!preserveItemOrder.value) {
|
||||
groupAndSortListItemsByFood();
|
||||
}
|
||||
else {
|
||||
sortListItems();
|
||||
}
|
||||
updateItemsByLabel();
|
||||
}
|
||||
|
||||
// constantly polls for changes
|
||||
async function pollForChanges() {
|
||||
// pause polling if the user isn't active or we're busy
|
||||
if (idle.value || loadingCounter.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await refresh();
|
||||
|
||||
if (shoppingList.value) {
|
||||
attempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the refresh was unsuccessful, the shopping list will be null, so we increment the attempt counter
|
||||
attempts++;
|
||||
}
|
||||
|
||||
catch {
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// if we hit too many errors, stop polling
|
||||
if (attempts >= maxAttempts) {
|
||||
clearInterval(pollTimer);
|
||||
}
|
||||
}
|
||||
|
||||
// start polling
|
||||
loadingCounter.value -= 1;
|
||||
pollForChanges(); // populate initial list
|
||||
|
||||
// max poll time = pollFrequency * maxAttempts = 24 hours
|
||||
// we use a long max poll time since polling stops when the user is idle anyway
|
||||
const pollFrequency = 5000;
|
||||
const maxAttempts = 17280;
|
||||
let attempts = 0;
|
||||
|
||||
const pollTimer: ReturnType<typeof setInterval> = setInterval(() => {
|
||||
pollForChanges();
|
||||
}, pollFrequency);
|
||||
onUnmounted(() => {
|
||||
clearInterval(pollTimer);
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// List Item CRUD
|
||||
|
||||
// Hydrate listItems from shoppingList.value?.listItems
|
||||
const listItems = reactive({
|
||||
unchecked: [] as ShoppingListItemOut[],
|
||||
checked: [] as ShoppingListItemOut[],
|
||||
});
|
||||
|
||||
function sortCheckedItems(a: ShoppingListItemOut, b: ShoppingListItemOut) {
|
||||
if (a.updatedAt! === b.updatedAt!) {
|
||||
return ((a.position || 0) > (b.position || 0)) ? -1 : 1;
|
||||
}
|
||||
return a.updatedAt! < b.updatedAt! ? 1 : -1;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => shoppingList.value?.listItems,
|
||||
(items) => {
|
||||
listItems.unchecked = (items?.filter(item => !item.checked) ?? []);
|
||||
listItems.checked = (items?.filter(item => item.checked)
|
||||
.sort(sortCheckedItems) ?? []);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// =====================================
|
||||
// Collapsable Labels
|
||||
const labelOpenState = ref<{ [key: string]: boolean }>({});
|
||||
|
||||
const initializeLabelOpenStates = () => {
|
||||
if (!shoppingList.value?.listItems) return;
|
||||
|
||||
const existingLabels = new Set(Object.keys(labelOpenState.value));
|
||||
let hasChanges = false;
|
||||
|
||||
for (const item of shoppingList.value.listItems) {
|
||||
const labelName = item.label?.name || i18n.t("shopping-list.no-label");
|
||||
if (!existingLabels.has(labelName) && !(labelName in labelOpenState.value)) {
|
||||
labelOpenState.value[labelName] = true;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
labelOpenState.value = { ...labelOpenState.value };
|
||||
}
|
||||
};
|
||||
|
||||
const labelNames = computed(() => {
|
||||
return new Set(
|
||||
shoppingList.value?.listItems
|
||||
?.map(item => item.label?.name || i18n.t("shopping-list.no-label"))
|
||||
.filter(Boolean) ?? [],
|
||||
);
|
||||
});
|
||||
|
||||
watch(labelNames, initializeLabelOpenStates, { immediate: true });
|
||||
|
||||
function toggleShowLabel(key: string) {
|
||||
labelOpenState.value[key] = !labelOpenState.value[key];
|
||||
}
|
||||
|
||||
const [showChecked, toggleShowChecked] = useToggle(false);
|
||||
|
||||
// =====================================
|
||||
// Copy List Items
|
||||
|
||||
const copy = useCopyList();
|
||||
|
||||
function copyListItems(copyType: CopyTypes) {
|
||||
const text: string[] = [];
|
||||
|
||||
if (preferences.value.viewByLabel) {
|
||||
// if we're sorting by label, we want the copied text in subsections
|
||||
Object.entries(itemsByLabel.value).forEach(([label, items], idx) => {
|
||||
// for every group except the first, add a blank line
|
||||
if (idx) {
|
||||
text.push("");
|
||||
}
|
||||
|
||||
// add an appropriate heading for the label depending on the copy format
|
||||
text.push(formatCopiedLabelHeading(copyType, label));
|
||||
|
||||
// now add the appropriately formatted list items with the given label
|
||||
items.forEach(item => text.push(formatCopiedListItem(copyType, item)));
|
||||
});
|
||||
}
|
||||
else {
|
||||
// labels are toggled off, so just copy in the order they come in
|
||||
const items = shoppingList.value?.listItems?.filter(item => !item.checked);
|
||||
|
||||
items?.forEach((item) => {
|
||||
text.push(formatCopiedListItem(copyType, item));
|
||||
});
|
||||
}
|
||||
|
||||
copy.copyPlain(text);
|
||||
}
|
||||
|
||||
function formatCopiedListItem(copyType: CopyTypes, item: ShoppingListItemOut): string {
|
||||
const display = item.display || "";
|
||||
switch (copyType) {
|
||||
case "markdown":
|
||||
return `- [ ] ${display}`;
|
||||
default:
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
function formatCopiedLabelHeading(copyType: CopyTypes, label: string): string {
|
||||
switch (copyType) {
|
||||
case "markdown":
|
||||
return `# ${label}`;
|
||||
default:
|
||||
return `[${label}]`;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Check / Uncheck All
|
||||
function openCheckAll() {
|
||||
if (shoppingList.value?.listItems?.some(item => !item.checked)) {
|
||||
state.checkAllDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function checkAll() {
|
||||
state.checkAllDialog = false;
|
||||
let hasChanged = false;
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (!item.checked) {
|
||||
hasChanged = true;
|
||||
item.checked = true;
|
||||
}
|
||||
});
|
||||
if (hasChanged) {
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
}
|
||||
|
||||
function openUncheckAll() {
|
||||
if (shoppingList.value?.listItems?.some(item => item.checked)) {
|
||||
state.uncheckAllDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function uncheckAll() {
|
||||
state.uncheckAllDialog = false;
|
||||
let hasChanged = false;
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (item.checked) {
|
||||
hasChanged = true;
|
||||
item.checked = false;
|
||||
}
|
||||
});
|
||||
if (hasChanged) {
|
||||
listItems.unchecked = [...listItems.unchecked, ...listItems.checked];
|
||||
listItems.checked = [];
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
}
|
||||
|
||||
function openDeleteChecked() {
|
||||
if (shoppingList.value?.listItems?.some(item => item.checked)) {
|
||||
state.deleteCheckedDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
function deleteChecked() {
|
||||
const checked = shoppingList.value?.listItems?.filter(item => item.checked);
|
||||
|
||||
if (!checked || checked?.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
deleteListItems(checked);
|
||||
|
||||
loadingCounter.value -= 1;
|
||||
refresh();
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// List Item Context Menu
|
||||
|
||||
const contextActions = {
|
||||
delete: "delete",
|
||||
};
|
||||
|
||||
const contextMenu = [
|
||||
{ title: i18n.t("general.delete"), action: contextActions.delete },
|
||||
];
|
||||
|
||||
// =====================================
|
||||
// Labels, Units, Foods
|
||||
// TODO: Extract to Composable
|
||||
|
||||
const localLabels = ref<ShoppingListMultiPurposeLabelOut[]>();
|
||||
|
||||
const shoppingListPage = useShoppingListPage(id);
|
||||
const { store: allLabels } = useLabelStore();
|
||||
const { store: allUnits } = useUnitStore();
|
||||
const { store: allFoods } = useFoodStore();
|
||||
|
||||
function getLabelColor(item: ShoppingListItemOut | null) {
|
||||
return item?.label?.color;
|
||||
}
|
||||
|
||||
function sortByLabels() {
|
||||
preferences.value.viewByLabel = !preferences.value.viewByLabel;
|
||||
}
|
||||
|
||||
function toggleReorderLabelsDialog() {
|
||||
// stop polling and populate localLabels
|
||||
loadingCounter.value += 1;
|
||||
reorderLabelsDialog.value = !reorderLabelsDialog.value;
|
||||
localLabels.value = shoppingList.value?.labelSettings;
|
||||
}
|
||||
|
||||
function updateLabelOrder(labelSettings: ShoppingListMultiPurposeLabelOut[]) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
labelSettings.forEach((labelSetting, index) => {
|
||||
labelSetting.position = index;
|
||||
return labelSetting;
|
||||
});
|
||||
|
||||
localLabels.value = labelSettings;
|
||||
}
|
||||
|
||||
function cancelLabelOrder() {
|
||||
loadingCounter.value -= 1;
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
// restore original state
|
||||
localLabels.value = shoppingList.value.labelSettings;
|
||||
}
|
||||
|
||||
async function saveLabelOrder() {
|
||||
if (!shoppingList.value || !localLabels.value || (localLabels.value === shoppingList.value.labelSettings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
const { data } = await userApi.shopping.lists.updateLabelSettings(shoppingList.value.id, localLabels.value);
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
// update shoppingList labels using the API response
|
||||
shoppingList.value.labelSettings = (data as ShoppingListOut).labelSettings;
|
||||
updateItemsByLabel();
|
||||
}
|
||||
}
|
||||
|
||||
const presentLabels = computed(() => {
|
||||
const labels: PresentLabel[] = [];
|
||||
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (item.labelId && item.label) {
|
||||
labels.push({
|
||||
name: item.label.name,
|
||||
id: item.labelId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
});
|
||||
|
||||
const itemsByLabel = ref<{ [key: string]: ShoppingListItemOut[] }>({});
|
||||
|
||||
interface ListItemGroup {
|
||||
position: number;
|
||||
createdAt: string;
|
||||
items: ShoppingListItemOut[];
|
||||
}
|
||||
|
||||
function sortItems(a: ShoppingListItemOut | ListItemGroup, b: ShoppingListItemOut | ListItemGroup) {
|
||||
// Sort by position ASC, then by createdAt ASC
|
||||
const posA = a.position ?? 0;
|
||||
const posB = b.position ?? 0;
|
||||
if (posA !== posB) {
|
||||
return posA - posB;
|
||||
}
|
||||
const createdA = a.createdAt ?? "";
|
||||
const createdB = b.createdAt ?? "";
|
||||
if (createdA !== createdB) {
|
||||
return createdA < createdB ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function groupAndSortListItemsByFood() {
|
||||
if (!shoppingList.value?.listItems?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const checkedItemKey = "__checkedItem";
|
||||
const listItemGroupsMap = new Map<string, ListItemGroup>();
|
||||
listItemGroupsMap.set(checkedItemKey, { position: Number.MAX_SAFE_INTEGER, createdAt: "", items: [] });
|
||||
|
||||
// group items by checked status, food, or note
|
||||
shoppingList.value.listItems.forEach((item) => {
|
||||
const key = item.checked
|
||||
? checkedItemKey
|
||||
: item.food?.name
|
||||
? item.food.name
|
||||
: item.note || "";
|
||||
|
||||
const group = listItemGroupsMap.get(key);
|
||||
if (!group) {
|
||||
listItemGroupsMap.set(key, { position: item.position || 0, createdAt: item.createdAt || "", items: [item] });
|
||||
}
|
||||
else {
|
||||
group.items.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
const listItemGroups = Array.from(listItemGroupsMap.values());
|
||||
listItemGroups.sort(sortItems);
|
||||
|
||||
// sort group items, then aggregate them
|
||||
const sortedItems: ShoppingListItemOut[] = [];
|
||||
let nextPosition = 0;
|
||||
listItemGroups.forEach((listItemGroup) => {
|
||||
listItemGroup.items.sort(sortItems);
|
||||
listItemGroup.items.forEach((item) => {
|
||||
item.position = nextPosition;
|
||||
nextPosition += 1;
|
||||
sortedItems.push(item);
|
||||
});
|
||||
});
|
||||
|
||||
shoppingList.value.listItems = sortedItems;
|
||||
}
|
||||
|
||||
function sortListItems() {
|
||||
if (!shoppingList.value?.listItems?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
shoppingList.value.listItems.sort(sortItems);
|
||||
}
|
||||
|
||||
function updateItemsByLabel() {
|
||||
const items: { [prop: string]: ShoppingListItemOut[] } = {};
|
||||
const noLabelText = i18n.t("shopping-list.no-label");
|
||||
const noLabel = [] as ShoppingListItemOut[];
|
||||
|
||||
shoppingList.value?.listItems?.forEach((item) => {
|
||||
if (item.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.labelId) {
|
||||
if (item.label && item.label.name in items) {
|
||||
items[item.label.name].push(item);
|
||||
}
|
||||
else if (item.label) {
|
||||
items[item.label.name] = [item];
|
||||
}
|
||||
}
|
||||
else {
|
||||
noLabel.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
if (noLabel.length > 0) {
|
||||
items[noLabelText] = noLabel;
|
||||
}
|
||||
|
||||
// sort the map by label order
|
||||
const orderedLabelNames = shoppingList.value?.labelSettings?.map(labelSetting => labelSetting.label.name);
|
||||
if (!orderedLabelNames) {
|
||||
itemsByLabel.value = items;
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsSorted: { [prop: string]: ShoppingListItemOut[] } = {};
|
||||
if (noLabelText in items) {
|
||||
itemsSorted[noLabelText] = items[noLabelText];
|
||||
}
|
||||
|
||||
orderedLabelNames.forEach((labelName) => {
|
||||
if (labelName in items) {
|
||||
itemsSorted[labelName] = items[labelName];
|
||||
}
|
||||
});
|
||||
|
||||
itemsByLabel.value = itemsSorted;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Add/Remove Recipe References
|
||||
|
||||
const recipeMap = computed(() => new Map(
|
||||
(shoppingList.value?.recipeReferences?.map(ref => ref.recipe) ?? [])
|
||||
.map(recipe => [recipe.id || "", recipe])),
|
||||
);
|
||||
|
||||
async function addRecipeReferenceToList(recipeId: string) {
|
||||
if (!shoppingList.value || recipeReferenceLoading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
recipeReferenceLoading.value = true;
|
||||
const { data } = await userApi.shopping.lists.addRecipes(shoppingList.value.id, [{ recipeId }]);
|
||||
recipeReferenceLoading.value = false;
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
async function removeRecipeReferenceToList(recipeId: string) {
|
||||
if (!shoppingList.value || recipeReferenceLoading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
recipeReferenceLoading.value = true;
|
||||
const { data } = await userApi.shopping.lists.removeRecipe(shoppingList.value.id, recipeId);
|
||||
recipeReferenceLoading.value = false;
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (data) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// List Item CRUD
|
||||
|
||||
/*
|
||||
* saveListItem updates and update on the backend server. Additionally, if the item is
|
||||
* checked it will also append that item to the end of the list so that the unchecked items
|
||||
* are at the top of the list.
|
||||
*/
|
||||
function saveListItem(item: ShoppingListItemOut) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set a temporary updatedAt timestamp prior to refresh so it appears at the top of the checked items
|
||||
item.updatedAt = new Date().toISOString();
|
||||
|
||||
// make updates reflect immediately
|
||||
if (shoppingList.value.listItems) {
|
||||
shoppingList.value.listItems.forEach((oldListItem: ShoppingListItemOut, idx: number) => {
|
||||
if (oldListItem.id === item.id && shoppingList.value?.listItems) {
|
||||
shoppingList.value.listItems[idx] = item;
|
||||
}
|
||||
});
|
||||
// Immediately update checked/unchecked arrays for UI
|
||||
listItems.unchecked = shoppingList.value.listItems.filter(i => !i.checked);
|
||||
listItems.checked = shoppingList.value.listItems.filter(i => i.checked)
|
||||
.sort(sortCheckedItems);
|
||||
}
|
||||
|
||||
// Update the item if it's checked, otherwise updateUncheckedListItems will handle it
|
||||
if (item.checked) {
|
||||
shoppingListItemActions.updateItem(item);
|
||||
}
|
||||
|
||||
updateListItemOrder();
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
|
||||
function deleteListItem(item: ShoppingListItemOut) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
shoppingListItemActions.deleteItem(item);
|
||||
|
||||
// remove the item from the list immediately so the user sees the change
|
||||
if (shoppingList.value.listItems) {
|
||||
shoppingList.value.listItems = shoppingList.value.listItems.filter(itm => itm.id !== item.id);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Create New Item
|
||||
|
||||
const createEditorOpen = ref(false);
|
||||
const createListItemData = ref<ShoppingListItemOut>(listItemFactory());
|
||||
|
||||
function listItemFactory(): ShoppingListItemOut {
|
||||
return {
|
||||
id: uuid4(),
|
||||
shoppingListId: id,
|
||||
checked: false,
|
||||
position: shoppingList.value?.listItems?.length || 1,
|
||||
quantity: 0,
|
||||
note: "",
|
||||
labelId: undefined,
|
||||
unitId: undefined,
|
||||
foodId: undefined,
|
||||
} as ShoppingListItemOut;
|
||||
}
|
||||
|
||||
/* const newMeal = reactive({
|
||||
date: "",
|
||||
title: "",
|
||||
text: "",
|
||||
recipeId: undefined as string | undefined,
|
||||
entryType: "dinner" as PlanEntryType,
|
||||
existing: false,
|
||||
id: 0,
|
||||
groupId: "",
|
||||
userId: $auth.user.value?.id || "",
|
||||
}); */
|
||||
|
||||
function createListItem() {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!createListItemData.value.foodId && !createListItemData.value.note) {
|
||||
// don't create an empty item
|
||||
return;
|
||||
}
|
||||
|
||||
loadingCounter.value += 1;
|
||||
|
||||
// make sure it's inserted into the end of the list, which may have been updated
|
||||
createListItemData.value.position = shoppingList.value?.listItems?.length
|
||||
? (shoppingList.value.listItems.reduce((a, b) => (a.position || 0) > (b.position || 0) ? a : b).position || 0) + 1
|
||||
: 0;
|
||||
|
||||
createListItemData.value.createdAt = new Date().toISOString();
|
||||
createListItemData.value.updatedAt = createListItemData.value.createdAt;
|
||||
|
||||
updateListItemOrder();
|
||||
|
||||
shoppingListItemActions.createItem(createListItemData.value);
|
||||
loadingCounter.value -= 1;
|
||||
|
||||
if (shoppingList.value.listItems) {
|
||||
// add the item to the list immediately so the user sees the change
|
||||
shoppingList.value.listItems.push(createListItemData.value);
|
||||
updateListItemOrder();
|
||||
}
|
||||
createListItemData.value = listItemFactory();
|
||||
refresh();
|
||||
}
|
||||
|
||||
function updateIndexUnchecked(uncheckedItems: ShoppingListItemOut[]) {
|
||||
listItems.unchecked = uncheckedItems;
|
||||
listItems.checked = shoppingList.value?.listItems?.filter(item => item.checked) || [];
|
||||
|
||||
// since the user has manually reordered the list, we should preserve this order
|
||||
preserveItemOrder.value = true;
|
||||
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
|
||||
function updateIndexUncheckedByLabel(labelName: string, labeledUncheckedItems: ShoppingListItemOut[]) {
|
||||
if (!itemsByLabel.value[labelName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update this label's item order
|
||||
itemsByLabel.value[labelName] = labeledUncheckedItems;
|
||||
|
||||
// reset list order of all items
|
||||
const allUncheckedItems: ShoppingListItemOut[] = [];
|
||||
for (labelName in itemsByLabel.value) {
|
||||
allUncheckedItems.push(...itemsByLabel.value[labelName]);
|
||||
}
|
||||
|
||||
// since the user has manually reordered the list, we should preserve this order
|
||||
preserveItemOrder.value = true;
|
||||
|
||||
// save changes
|
||||
listItems.unchecked = allUncheckedItems;
|
||||
listItems.checked = shoppingList.value?.listItems?.filter(item => item.checked) || [];
|
||||
updateUncheckedListItems();
|
||||
}
|
||||
|
||||
function deleteListItems(items: ShoppingListItemOut[]) {
|
||||
if (!shoppingList.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
shoppingListItemActions.deleteItem(item);
|
||||
});
|
||||
// remove the items from the list immediately so the user sees the change
|
||||
if (shoppingList.value?.listItems) {
|
||||
const deletedItems = new Set(items.map(item => item.id));
|
||||
shoppingList.value.listItems = shoppingList.value.listItems.filter(itm => !deletedItems.has(itm.id));
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
function updateUncheckedListItems() {
|
||||
if (!shoppingList.value?.listItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set position for unchecked items
|
||||
listItems.unchecked.forEach((item: ShoppingListItemOut, idx: number) => {
|
||||
item.position = idx;
|
||||
shoppingListItemActions.updateItem(item);
|
||||
});
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
addRecipeReferenceToList,
|
||||
allLabels,
|
||||
contextMenu,
|
||||
copyListItems,
|
||||
createEditorOpen,
|
||||
createListItem,
|
||||
createListItemData,
|
||||
deleteChecked,
|
||||
openDeleteChecked,
|
||||
deleteListItem,
|
||||
edit,
|
||||
threeDot,
|
||||
getLabelColor,
|
||||
groupSlug,
|
||||
itemsByLabel,
|
||||
listItems,
|
||||
loadingCounter,
|
||||
preferences,
|
||||
presentLabels,
|
||||
recipeMap,
|
||||
removeRecipeReferenceToList,
|
||||
reorderLabelsDialog,
|
||||
toggleReorderLabelsDialog,
|
||||
localLabels,
|
||||
updateLabelOrder,
|
||||
cancelLabelOrder,
|
||||
saveLabelOrder,
|
||||
saveListItem,
|
||||
shoppingList,
|
||||
showChecked,
|
||||
sortByLabels,
|
||||
labelOpenState,
|
||||
toggleShowLabel,
|
||||
toggleShowChecked,
|
||||
uncheckAll,
|
||||
openUncheckAll,
|
||||
checkAll,
|
||||
openCheckAll,
|
||||
updateIndexUnchecked,
|
||||
updateIndexUncheckedByLabel,
|
||||
allLabels,
|
||||
allUnits,
|
||||
allFoods,
|
||||
getTextColor,
|
||||
isOffline,
|
||||
mdAndUp,
|
||||
...shoppingListPage,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
"""'Add label notifier CRUD bools'
|
||||
|
||||
Revision ID: e6bb583aac2d
|
||||
Revises: d7b3ce6fa31a
|
||||
Create Date: 2025-08-09 19:32:37.285172
|
||||
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "e6bb583aac2d"
|
||||
down_revision: str | None = "d7b3ce6fa31a"
|
||||
branch_labels: str | tuple[str, ...] | None = None
|
||||
depends_on: str | tuple[str, ...] | None = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("group_events_notifier_options", schema=None) as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"label_created", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false()
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"label_updated", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false()
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"label_deleted", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false()
|
||||
)
|
||||
)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("group_events_notifier_options", schema=None) as batch_op:
|
||||
batch_op.drop_column("label_deleted")
|
||||
batch_op.drop_column("label_updated")
|
||||
batch_op.drop_column("label_created")
|
||||
|
||||
# ### end Alembic commands ###
|
|
@ -46,6 +46,10 @@ class GroupEventNotifierOptionsModel(SqlAlchemyBase, BaseMixins):
|
|||
category_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
category_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
|
||||
label_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
label_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
label_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
pass
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"step-text": "Passos das receitas, assim como outros campos na página da receita, suportam sintaxe \"markdown\".\n\n**Adicione um link**\n\n[Meu Link](https://demo.mealie.io)\n"
|
||||
},
|
||||
"servings-text": {
|
||||
"makes": "Makes",
|
||||
"makes": "Produz",
|
||||
"serves": "Porções",
|
||||
"serving": "Porção",
|
||||
"servings": "Porções",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"serves": "Порций",
|
||||
"serving": "Порция",
|
||||
"servings": "Порции",
|
||||
"yield": "Выход",
|
||||
"yield": "Количество порций",
|
||||
"yields": "Можно получить"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -132,8 +132,8 @@
|
|||
"baby green": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "baby green",
|
||||
"plural_name": "baby greens"
|
||||
"name": "babysalat",
|
||||
"plural_name": "babysalater"
|
||||
},
|
||||
"pumpkin": {
|
||||
"aliases": [],
|
||||
|
@ -199,7 +199,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "romaine",
|
||||
"plural_name": "romaines"
|
||||
"plural_name": "romaine"
|
||||
},
|
||||
"beetroot": {
|
||||
"aliases": [],
|
||||
|
@ -339,46 +339,46 @@
|
|||
"chard": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chard",
|
||||
"plural_name": "chards"
|
||||
"name": "bladbede",
|
||||
"plural_name": "bladbeder"
|
||||
},
|
||||
"pimiento": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pimiento",
|
||||
"plural_name": "pimientoes"
|
||||
"name": "tapas peber",
|
||||
"plural_name": "tapas peber"
|
||||
},
|
||||
"spaghetti squash": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "spaghetti squash",
|
||||
"plural_name": "spaghetti squashes"
|
||||
"plural_name": "spaghetti squash"
|
||||
},
|
||||
"butter lettuce": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "butter lettuce",
|
||||
"plural_name": "butter lettuces"
|
||||
"name": "havesalat",
|
||||
"plural_name": "havesalater"
|
||||
},
|
||||
"hash brown": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hash brown",
|
||||
"plural_name": "hash browns"
|
||||
"name": "rösti",
|
||||
"plural_name": "rösti"
|
||||
},
|
||||
"napa cabbage": {
|
||||
"aliases": [
|
||||
"chinese leaves"
|
||||
"kinakål"
|
||||
],
|
||||
"description": "",
|
||||
"name": "napa cabbage",
|
||||
"plural_name": "napa cabbages"
|
||||
"name": "kinakål",
|
||||
"plural_name": "kinakål"
|
||||
},
|
||||
"celeriac": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "celeriac",
|
||||
"plural_name": "celeriacs"
|
||||
"name": "knoldselleri",
|
||||
"plural_name": "knoldselleri"
|
||||
},
|
||||
"water chestnut": {
|
||||
"aliases": [],
|
||||
|
@ -395,8 +395,8 @@
|
|||
"thai chile pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "thai chile pepper",
|
||||
"plural_name": "thai chile peppers"
|
||||
"name": "thai chili",
|
||||
"plural_name": "thai chilier"
|
||||
},
|
||||
"bok choy": {
|
||||
"aliases": [],
|
||||
|
@ -413,8 +413,8 @@
|
|||
"acorn squash": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "acorn squash",
|
||||
"plural_name": "acorn squashes"
|
||||
"name": "vintergræskar",
|
||||
"plural_name": "vintergræskar"
|
||||
},
|
||||
"corn cob": {
|
||||
"aliases": [],
|
||||
|
@ -431,32 +431,32 @@
|
|||
"pearl onion": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pearl onion",
|
||||
"plural_name": "pearl onions"
|
||||
"name": "perleløg",
|
||||
"plural_name": "perleløg"
|
||||
},
|
||||
"tenderstem broccoli": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "tenderstem broccoli",
|
||||
"plural_name": "tenderstem broccolis"
|
||||
"name": "broccoli",
|
||||
"plural_name": "broccoli"
|
||||
},
|
||||
"plantain": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "plantain",
|
||||
"plural_name": "plantains"
|
||||
"name": "madbanan",
|
||||
"plural_name": "madbananer"
|
||||
},
|
||||
"leaf lettuce": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "leaf lettuce",
|
||||
"plural_name": "leaf lettuces"
|
||||
"name": "pluksalat",
|
||||
"plural_name": "pluksalat"
|
||||
},
|
||||
"pepperoncini": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pepperoncini",
|
||||
"plural_name": "pepperoncinis"
|
||||
"name": "peberfrugt",
|
||||
"plural_name": "peberfrugt"
|
||||
},
|
||||
"baby bok choy": {
|
||||
"aliases": [],
|
||||
|
@ -468,39 +468,39 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "jicama",
|
||||
"plural_name": "jicamas"
|
||||
"plural_name": "jicama"
|
||||
},
|
||||
"endive": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "endive",
|
||||
"plural_name": "endives"
|
||||
"name": "julesalat",
|
||||
"plural_name": "julesalat"
|
||||
},
|
||||
"habanero pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "habanero pepper",
|
||||
"plural_name": "habanero peppers"
|
||||
"name": "habanero peber",
|
||||
"plural_name": "habanero peber"
|
||||
},
|
||||
"corn husk": {
|
||||
"aliases": [
|
||||
"maize"
|
||||
"majs"
|
||||
],
|
||||
"description": "",
|
||||
"name": "corn husk",
|
||||
"plural_name": "corn husks"
|
||||
"name": "majsblad",
|
||||
"plural_name": "majsblade"
|
||||
},
|
||||
"collard green": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "collard green",
|
||||
"plural_name": "collard greens"
|
||||
"name": "fodermarvkål",
|
||||
"plural_name": "fodermarvkål"
|
||||
},
|
||||
"french-fried onion": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "french-fried onion",
|
||||
"plural_name": "french-fried onions"
|
||||
"name": "ristet løg",
|
||||
"plural_name": "ristet løg"
|
||||
},
|
||||
"daikon": {
|
||||
"aliases": [],
|
||||
|
@ -660,7 +660,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "orange",
|
||||
"plural_name": "oranges"
|
||||
"plural_name": "appelsiner"
|
||||
},
|
||||
"raisin": {
|
||||
"aliases": [],
|
||||
|
@ -720,7 +720,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "granatæble",
|
||||
"plural_name": "pomegranates"
|
||||
"plural_name": "granatæble"
|
||||
},
|
||||
"watermelon": {
|
||||
"aliases": [],
|
||||
|
@ -785,116 +785,116 @@
|
|||
"prune": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "prune",
|
||||
"plural_name": "prunes"
|
||||
"name": "sveske",
|
||||
"plural_name": "sveske"
|
||||
},
|
||||
"cantaloupe": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cantaloupe",
|
||||
"plural_name": "cantaloupes"
|
||||
"name": "cantaloupe-melon",
|
||||
"plural_name": "cantaloupe-meloner"
|
||||
},
|
||||
"sultana": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sultana",
|
||||
"plural_name": "sultanas"
|
||||
"name": "vindrue",
|
||||
"plural_name": "vindruer"
|
||||
},
|
||||
"passion fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "passion fruit",
|
||||
"plural_name": "passion fruits"
|
||||
"name": "passionsfrugt",
|
||||
"plural_name": "passionsfrugt"
|
||||
},
|
||||
"papaya": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "papaya",
|
||||
"plural_name": "papayas"
|
||||
"plural_name": "papaya"
|
||||
},
|
||||
"tamarind": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "tamarind",
|
||||
"plural_name": "tamarinds"
|
||||
"plural_name": "tamarind"
|
||||
},
|
||||
"nectarine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "nectarine",
|
||||
"plural_name": "nectarines"
|
||||
"name": "nektarin",
|
||||
"plural_name": "nektariner"
|
||||
},
|
||||
"dried fig": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fig",
|
||||
"plural_name": "dried figs"
|
||||
"name": "tørret figen",
|
||||
"plural_name": "tørrede figner"
|
||||
},
|
||||
"chestnut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chestnut",
|
||||
"plural_name": "chestnuts"
|
||||
"name": "kastanje",
|
||||
"plural_name": "kastanier"
|
||||
},
|
||||
"meyer lemon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "meyer lemon",
|
||||
"plural_name": "meyer lemons"
|
||||
"name": "citron",
|
||||
"plural_name": "citroner"
|
||||
},
|
||||
"honeydew melon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "honeydew melon",
|
||||
"plural_name": "honeydew melons"
|
||||
"name": "honningmelon",
|
||||
"plural_name": "honningmeloner"
|
||||
},
|
||||
"dried fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fruit",
|
||||
"plural_name": "dried fruits"
|
||||
"name": "tørret frugt",
|
||||
"plural_name": "tørrede frugter"
|
||||
},
|
||||
"clementine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "clementine",
|
||||
"plural_name": "clementines"
|
||||
"name": "klementin",
|
||||
"plural_name": "klementiner"
|
||||
},
|
||||
"persimmon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "persimmon",
|
||||
"plural_name": "persimmons"
|
||||
"name": "daddelblomme",
|
||||
"plural_name": "daddelblommer"
|
||||
},
|
||||
"melon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "melon",
|
||||
"plural_name": "melons"
|
||||
"plural_name": "meloner"
|
||||
},
|
||||
"tangerine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "tangerine",
|
||||
"plural_name": "tangerines"
|
||||
"name": "madarin",
|
||||
"plural_name": "madariner"
|
||||
},
|
||||
"dried mango": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried mango",
|
||||
"plural_name": "dried mangoes"
|
||||
"name": "tørret mango",
|
||||
"plural_name": "tørret mango"
|
||||
},
|
||||
"dried apple": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried apple",
|
||||
"plural_name": "dried apples"
|
||||
"name": "tørret æble",
|
||||
"plural_name": "tørrede æbler"
|
||||
},
|
||||
"quince": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "quince",
|
||||
"plural_name": "quinces"
|
||||
"name": "kvæde",
|
||||
"plural_name": "kvæder"
|
||||
},
|
||||
"guava": {
|
||||
"aliases": [],
|
||||
|
@ -905,31 +905,31 @@
|
|||
"banana chip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "banana chip",
|
||||
"plural_name": "banana chips"
|
||||
"name": "banan chips",
|
||||
"plural_name": "banan chips"
|
||||
},
|
||||
"kumquat": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kumquat",
|
||||
"plural_name": "kumquats"
|
||||
"plural_name": "kumquat"
|
||||
},
|
||||
"jackfruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "jackfruit",
|
||||
"plural_name": "jackfruits"
|
||||
"name": "jackfrugt",
|
||||
"plural_name": "jackfrugter"
|
||||
},
|
||||
"dragon fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dragon fruit",
|
||||
"plural_name": "dragon fruits"
|
||||
"name": "drage frugt",
|
||||
"plural_name": "drage frugter"
|
||||
},
|
||||
"mixed fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mixed fruit",
|
||||
"name": "blandet frugt",
|
||||
"plural_name": "mixed fruits"
|
||||
},
|
||||
"asian pear": {
|
||||
|
@ -1055,7 +1055,7 @@
|
|||
"dried lemon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried lemon",
|
||||
"name": "tørret citron",
|
||||
"plural_name": "dried lemons"
|
||||
},
|
||||
"young jackfruit": {
|
||||
|
|
|
@ -4493,8 +4493,8 @@
|
|||
"ground turkey sausage": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "ground turkey sausage",
|
||||
"plural_name": "ground turkey sausages"
|
||||
"name": "Geräucherte Putenwurst",
|
||||
"plural_name": "Geräucherte Putenwurst"
|
||||
},
|
||||
"quail": {
|
||||
"aliases": [],
|
||||
|
@ -4607,8 +4607,8 @@
|
|||
"chicken andouille": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken andouille",
|
||||
"plural_name": "chicken andouilles"
|
||||
"name": "Hühner-Andouille",
|
||||
"plural_name": "Hühner-Andouille"
|
||||
},
|
||||
"chicken gizzard": {
|
||||
"aliases": [],
|
||||
|
@ -4625,8 +4625,8 @@
|
|||
"chicken italian sausage": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken italian sausage",
|
||||
"plural_name": "chicken italian sausages"
|
||||
"name": "Hähnchen-Salsiccia",
|
||||
"plural_name": "Hähnchen-Salsiccia"
|
||||
},
|
||||
"crispy chicken strip": {
|
||||
"aliases": [],
|
||||
|
@ -4643,20 +4643,20 @@
|
|||
"popcorn chicken": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "popcorn chicken",
|
||||
"plural_name": "popcorn chickens"
|
||||
"name": "Popcorn-Hähnchen",
|
||||
"plural_name": "Popcorn-Hähnchen"
|
||||
},
|
||||
"turkey kielbasa": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "turkey kielbasa",
|
||||
"plural_name": "turkey kielbasas"
|
||||
"name": "Truthahn-Kielbasa",
|
||||
"plural_name": "Truthahn-Kielbasa"
|
||||
},
|
||||
"chicken-apple sausage": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken-apple sausage",
|
||||
"plural_name": "chicken-apple sausages"
|
||||
"name": "Hähnchen-Apfel-Wurst",
|
||||
"plural_name": "Hähnchen-Apfel-Würsten"
|
||||
},
|
||||
"chicken foot": {
|
||||
"aliases": [],
|
||||
|
@ -4673,8 +4673,8 @@
|
|||
"deli chicken": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "deli chicken",
|
||||
"plural_name": "deli chickens"
|
||||
"name": "Delikatessen-Hähnchen",
|
||||
"plural_name": "Delikatessen-Hähnchen"
|
||||
},
|
||||
"smoked duck breast": {
|
||||
"aliases": [],
|
||||
|
@ -4709,8 +4709,8 @@
|
|||
"duck confit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "duck confit",
|
||||
"plural_name": "duck confits"
|
||||
"name": "Entenconfit",
|
||||
"plural_name": "Entenconfite"
|
||||
},
|
||||
"roast duck": {
|
||||
"aliases": [],
|
||||
|
@ -4740,13 +4740,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "geräucherte Putenflügel",
|
||||
"plural_name": "smoked turkey wings"
|
||||
"plural_name": "Geräucherte Truthahnflügel"
|
||||
},
|
||||
"chicken curry-cut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken curry-cut",
|
||||
"plural_name": "chicken curry-cuts"
|
||||
"name": "Curry-geschnittenes Hähnchen",
|
||||
"plural_name": "Curry-geschnittene Hähnchenteile"
|
||||
},
|
||||
"chicken schnitzel": {
|
||||
"aliases": [],
|
||||
|
@ -6095,8 +6095,8 @@
|
|||
"chipotle": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chipotle",
|
||||
"plural_name": "chipotles"
|
||||
"name": "Chipotle",
|
||||
"plural_name": "Chipotles"
|
||||
},
|
||||
"fenugreek": {
|
||||
"aliases": [],
|
||||
|
@ -6131,8 +6131,8 @@
|
|||
"dried parsley flake": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried parsley flake",
|
||||
"plural_name": "dried parsley flakes"
|
||||
"name": "Petersilie, gerebelt",
|
||||
"plural_name": "Petersilie, gerebelt"
|
||||
},
|
||||
"fenugreek seed": {
|
||||
"aliases": [],
|
||||
|
@ -6143,8 +6143,8 @@
|
|||
"kashmiri red chilli": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kashmiri red chilli",
|
||||
"plural_name": "kashmiri red chillis"
|
||||
"name": "Kashmiri Mirch",
|
||||
"plural_name": "Kashmiri Mirch"
|
||||
},
|
||||
"thai basil": {
|
||||
"aliases": [],
|
||||
|
@ -6167,8 +6167,8 @@
|
|||
"kaffir lime leaf": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kaffir lime leaf",
|
||||
"plural_name": "kaffir lime leaves"
|
||||
"name": "Kaffir-Limettenblatt",
|
||||
"plural_name": "Kaffir-Limettenblätter"
|
||||
},
|
||||
"chervil": {
|
||||
"aliases": [],
|
||||
|
@ -6192,7 +6192,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mexikanischer Oregano",
|
||||
"plural_name": "mexican oreganos"
|
||||
"plural_name": "mexikanischer Oregano"
|
||||
},
|
||||
"mace": {
|
||||
"aliases": [],
|
||||
|
@ -6233,8 +6233,8 @@
|
|||
"guajillo pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "guajillo pepper",
|
||||
"plural_name": "guajillo peppers"
|
||||
"name": "Guajillo-Chili",
|
||||
"plural_name": "Guajillo-Chilis"
|
||||
},
|
||||
"pink peppercorn": {
|
||||
"aliases": [],
|
||||
|
@ -6305,38 +6305,38 @@
|
|||
"achiote seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "achiote seed",
|
||||
"plural_name": "achiote seeds"
|
||||
"name": "Annatto-Samen",
|
||||
"plural_name": "Annatto-Samen"
|
||||
},
|
||||
"savory herb": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "savory herb",
|
||||
"plural_name": "savory herbs"
|
||||
"name": "Bohnenkraut",
|
||||
"plural_name": "Bohnenkraut"
|
||||
},
|
||||
"pandan leaf": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pandan leaf",
|
||||
"plural_name": "pandan leaves"
|
||||
"name": "Pandanblatt",
|
||||
"plural_name": "Pandanblätter"
|
||||
},
|
||||
"sorrel": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sorrel",
|
||||
"plural_name": "sorrels"
|
||||
"name": "Sauerampfer",
|
||||
"plural_name": "Sauerampfer"
|
||||
},
|
||||
"gochugaru": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "gochugaru",
|
||||
"plural_name": "gochugarus"
|
||||
"name": "Gochugaru",
|
||||
"plural_name": "Gochugaru"
|
||||
},
|
||||
"saigon cinnamon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "saigon cinnamon",
|
||||
"plural_name": "saigon cinnamons"
|
||||
"name": "vietnamesischer Zimt",
|
||||
"plural_name": "vietnamesischer Zimt"
|
||||
},
|
||||
"lemongrass paste": {
|
||||
"aliases": [],
|
||||
|
@ -6347,14 +6347,14 @@
|
|||
"shiso": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "shiso",
|
||||
"plural_name": "shisoes"
|
||||
"name": "Shiso",
|
||||
"plural_name": "Shiso"
|
||||
},
|
||||
"celery powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "celery powder",
|
||||
"plural_name": "celery powders"
|
||||
"name": "Sellerieknollenpulver",
|
||||
"plural_name": "Sellerieknollenpulver"
|
||||
},
|
||||
"black cumin": {
|
||||
"aliases": [],
|
||||
|
@ -6365,8 +6365,8 @@
|
|||
"anardana": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "anardana",
|
||||
"plural_name": "anardanas"
|
||||
"name": "Anardana",
|
||||
"plural_name": "Anardana"
|
||||
},
|
||||
"vietnamese mint": {
|
||||
"aliases": [],
|
||||
|
@ -6383,14 +6383,14 @@
|
|||
"espelette pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "espelette pepper",
|
||||
"plural_name": "espelette peppers"
|
||||
"name": "Piment d’Espelette",
|
||||
"plural_name": "Piment d’Espelette"
|
||||
},
|
||||
"lemon verbena": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Zitronenverbe",
|
||||
"plural_name": "lemon verbenas"
|
||||
"name": "Zitronenverbene",
|
||||
"plural_name": "Zitronenverbene"
|
||||
},
|
||||
"raw stevia": {
|
||||
"aliases": [],
|
||||
|
@ -6407,8 +6407,8 @@
|
|||
"summer savory": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "summer savory",
|
||||
"plural_name": "summer savories"
|
||||
"name": "Sommer-Bohnenkraut",
|
||||
"plural_name": "Sommer-Bohnenkräuter"
|
||||
},
|
||||
"fennel pollen": {
|
||||
"aliases": [],
|
||||
|
@ -6440,12 +6440,12 @@
|
|||
"Puderzucker"
|
||||
],
|
||||
"description": "",
|
||||
"name": "confectioners sugar",
|
||||
"plural_name": "confectioners sugars"
|
||||
"name": "Puderzucker",
|
||||
"plural_name": "Puderzucker"
|
||||
},
|
||||
"bar sugar": {
|
||||
"aliases": [
|
||||
"castor sugar"
|
||||
"Feinzucker"
|
||||
],
|
||||
"description": "",
|
||||
"name": "Rohrzucker",
|
||||
|
@ -6880,8 +6880,8 @@
|
|||
"hot honey": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hot honey",
|
||||
"plural_name": "hot honeys"
|
||||
"name": "heißer Honig",
|
||||
"plural_name": "heiße Honige"
|
||||
},
|
||||
"gula melaka": {
|
||||
"aliases": [],
|
||||
|
@ -6892,14 +6892,14 @@
|
|||
"elderberry syrup": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "elderberry syrup",
|
||||
"plural_name": "elderberry syrups"
|
||||
"name": "Holunderbeerensirup",
|
||||
"plural_name": "Holunderbeerensirupe"
|
||||
},
|
||||
"rosemary syrup": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "rosemary syrup",
|
||||
"plural_name": "rosemary syrups"
|
||||
"name": "Rosmarinsirup",
|
||||
"plural_name": "Rosmarinsirupe"
|
||||
},
|
||||
"dark chocolate syrup": {
|
||||
"aliases": [],
|
||||
|
@ -7030,7 +7030,7 @@
|
|||
"truffle honey": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "truffle honey",
|
||||
"name": "Trüffelhonig",
|
||||
"plural_name": "truffle honeys"
|
||||
}
|
||||
}
|
||||
|
@ -7651,7 +7651,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Mehl",
|
||||
"plural_name": "Mehle"
|
||||
"plural_name": "Mehl"
|
||||
},
|
||||
"vanilla extract": {
|
||||
"aliases": [
|
||||
|
@ -7704,7 +7704,7 @@
|
|||
],
|
||||
"description": "",
|
||||
"name": "Weizenvollkornmehl",
|
||||
"plural_name": "Weizenvollkornmehle"
|
||||
"plural_name": "Weizenvollkornmehl"
|
||||
},
|
||||
"almond flour": {
|
||||
"aliases": [],
|
||||
|
@ -7770,7 +7770,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Maismehl",
|
||||
"plural_name": "Maismehle"
|
||||
"plural_name": "Maismehl"
|
||||
},
|
||||
"cream of tartar": {
|
||||
"aliases": [],
|
||||
|
@ -7816,7 +7816,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Reismehl",
|
||||
"plural_name": "Reismehle"
|
||||
"plural_name": "Reismehl"
|
||||
},
|
||||
"desiccated coconut": {
|
||||
"aliases": [],
|
||||
|
@ -7840,7 +7840,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Kichererbsenmehl",
|
||||
"plural_name": "Kichererbsenmehle"
|
||||
"plural_name": "Kichererbsenmehl"
|
||||
},
|
||||
"xanthan gum": {
|
||||
"aliases": [],
|
||||
|
@ -7957,7 +7957,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Roggenmehl",
|
||||
"plural_name": "Roggenmehle"
|
||||
"plural_name": "Roggenmehl"
|
||||
},
|
||||
"psyllium husk": {
|
||||
"aliases": [],
|
||||
|
@ -8071,7 +8071,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Matzemehl",
|
||||
"plural_name": "Matzemehle"
|
||||
"plural_name": "Matzemehl"
|
||||
},
|
||||
"sago": {
|
||||
"aliases": [],
|
||||
|
@ -8089,7 +8089,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Maniokmehl",
|
||||
"plural_name": "Maniokmehle"
|
||||
"plural_name": "Maniokmehl"
|
||||
},
|
||||
"whipped cream stabilizer": {
|
||||
"aliases": [],
|
||||
|
@ -8143,13 +8143,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Quinoamehl",
|
||||
"plural_name": "Quinoamehle"
|
||||
"plural_name": "Quinoamehl"
|
||||
},
|
||||
"finger millet flour": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Fingerhirsemehl",
|
||||
"plural_name": "Fingerhirsemehle"
|
||||
"plural_name": "Fingerhirsemehl"
|
||||
},
|
||||
"fondant": {
|
||||
"aliases": [],
|
||||
|
@ -8173,13 +8173,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "weißes Maismehl",
|
||||
"plural_name": "weiße Maismehle"
|
||||
"plural_name": "weißes Maismehl"
|
||||
},
|
||||
"millet flour": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "Hirsemehl",
|
||||
"plural_name": "Hirsemehle"
|
||||
"plural_name": "Hirsemehl"
|
||||
},
|
||||
"mincemeat": {
|
||||
"aliases": [],
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -280,7 +280,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mélange de légumes",
|
||||
"plural_name": "mélange de légumes"
|
||||
"plural_name": "mélanges de légumes"
|
||||
},
|
||||
"poblano pepper": {
|
||||
"aliases": [],
|
||||
|
@ -378,7 +378,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "céleri-rave",
|
||||
"plural_name": "céleric-raves"
|
||||
"plural_name": "céleri-raves"
|
||||
},
|
||||
"water chestnut": {
|
||||
"aliases": [],
|
||||
|
@ -1151,8 +1151,8 @@
|
|||
"dried orange slice": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried orange slice",
|
||||
"plural_name": "dried orange slices"
|
||||
"name": "tranche d'orange séchée",
|
||||
"plural_name": "tranches d'orange séchées"
|
||||
},
|
||||
"loquat": {
|
||||
"aliases": [],
|
||||
|
@ -1335,8 +1335,8 @@
|
|||
"dried chinese mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried chinese mushroom",
|
||||
"plural_name": "dried chinese mushrooms"
|
||||
"name": "shiitake",
|
||||
"plural_name": "shiitakes"
|
||||
},
|
||||
"maitake": {
|
||||
"aliases": [],
|
||||
|
@ -1347,8 +1347,8 @@
|
|||
"trumpet mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "trumpet mushroom",
|
||||
"plural_name": "trumpet mushrooms"
|
||||
"name": "pleurote de panicaut",
|
||||
"plural_name": "pleurotes de panicaut"
|
||||
},
|
||||
"white truffle": {
|
||||
"aliases": [],
|
||||
|
@ -1437,14 +1437,14 @@
|
|||
"candy cap mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "candy cap mushroom",
|
||||
"plural_name": "candy cap mushrooms"
|
||||
"name": "Champignon Candy Cap",
|
||||
"plural_name": "Champignons Candy Cap"
|
||||
},
|
||||
"lion’s mane mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lion’s mane mushroom",
|
||||
"plural_name": "lion’s mane mushrooms"
|
||||
"name": "Champignon lion's mane",
|
||||
"plural_name": "Champignons lion's mane"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1745,7 +1745,7 @@
|
|||
"pine nut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pine nut",
|
||||
"name": "pignon de pin",
|
||||
"plural_name": "pine nuts"
|
||||
},
|
||||
"pistachio": {
|
||||
|
@ -2015,8 +2015,8 @@
|
|||
"cream cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cream cheese",
|
||||
"plural_name": "cream cheeses"
|
||||
"name": "mascarpone",
|
||||
"plural_name": "mascarpones"
|
||||
},
|
||||
"sharp cheddar": {
|
||||
"aliases": [],
|
||||
|
@ -2382,7 +2382,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "babybel",
|
||||
"plural_name": "babybels"
|
||||
"plural_name": "babybel"
|
||||
},
|
||||
"panela cheese": {
|
||||
"aliases": [],
|
||||
|
@ -2556,7 +2556,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "port-salut",
|
||||
"plural_name": "port saluts"
|
||||
"plural_name": "port-salut"
|
||||
},
|
||||
"derby cheese": {
|
||||
"aliases": [],
|
||||
|
@ -2637,8 +2637,8 @@
|
|||
"sour cream": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "crème fraiche",
|
||||
"plural_name": "crèmes fraiches"
|
||||
"name": "crème aigre",
|
||||
"plural_name": "crèmes aigres"
|
||||
},
|
||||
"buttermilk": {
|
||||
"aliases": [],
|
||||
|
@ -3035,14 +3035,14 @@
|
|||
"sheep’s milk yoghurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sheep’s milk yoghurt",
|
||||
"plural_name": "sheep’s milk yoghurts"
|
||||
"name": "yaourt au lait de brebis",
|
||||
"plural_name": "yaourts au lait de brebis"
|
||||
},
|
||||
"strawberry milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strawberry milk",
|
||||
"plural_name": "strawberry milks"
|
||||
"name": "lait à la fraise",
|
||||
"plural_name": "laits à la fraise"
|
||||
},
|
||||
"ayran": {
|
||||
"aliases": [],
|
||||
|
@ -3078,7 +3078,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lait de brebis",
|
||||
"plural_name": "sheep milks"
|
||||
"plural_name": "lait de brebis"
|
||||
},
|
||||
"starter culture": {
|
||||
"aliases": [],
|
||||
|
@ -3102,7 +3102,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lait vanillé",
|
||||
"plural_name": "vanilla milks"
|
||||
"plural_name": "laits à la vanille"
|
||||
},
|
||||
"yoplait whip": {
|
||||
"aliases": [],
|
||||
|
@ -3303,8 +3303,8 @@
|
|||
"soy yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "soy yogurt",
|
||||
"plural_name": "soy yogurts"
|
||||
"name": "yaourt au lait de soja",
|
||||
"plural_name": "yaourts au lait de soja"
|
||||
},
|
||||
"vegan mozzarella": {
|
||||
"aliases": [],
|
||||
|
@ -6665,7 +6665,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vanilla syrup",
|
||||
"plural_name": "vanilla syrups"
|
||||
"plural_name": "sirop de vanille"
|
||||
},
|
||||
"ginger syrup": {
|
||||
"aliases": [],
|
||||
|
@ -7655,12 +7655,12 @@
|
|||
},
|
||||
"vanilla extract": {
|
||||
"aliases": [
|
||||
"vanilla",
|
||||
"vanillas"
|
||||
"vanille",
|
||||
"vanilles"
|
||||
],
|
||||
"description": "",
|
||||
"name": "vanilla extract",
|
||||
"plural_name": "vanilla extracts"
|
||||
"name": "extrait de vanille",
|
||||
"plural_name": "extraits de vanille"
|
||||
},
|
||||
"baking powder": {
|
||||
"aliases": [],
|
||||
|
@ -15025,8 +15025,8 @@
|
|||
"vanilla liqueur": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vanilla liqueur",
|
||||
"plural_name": "vanilla liqueurs"
|
||||
"name": "liqueur de vanille",
|
||||
"plural_name": "liqueurs de vanille"
|
||||
},
|
||||
"sangria": {
|
||||
"aliases": [],
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
"shallot": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "shallot",
|
||||
"plural_name": "shallots"
|
||||
"name": "chalota",
|
||||
"plural_name": "chalotas"
|
||||
},
|
||||
"cherry tomato": {
|
||||
"aliases": [],
|
||||
|
@ -100,8 +100,8 @@
|
|||
"sweet corn": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sweet corn",
|
||||
"plural_name": "sweet corns"
|
||||
"name": "millo doce",
|
||||
"plural_name": "millos doces"
|
||||
},
|
||||
"chile pepper": {
|
||||
"aliases": [
|
||||
|
@ -168,8 +168,8 @@
|
|||
"arugula": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "arugula",
|
||||
"plural_name": "arugulas"
|
||||
"name": "rúcula",
|
||||
"plural_name": "rúculas"
|
||||
},
|
||||
"leek": {
|
||||
"aliases": [],
|
||||
|
@ -192,14 +192,14 @@
|
|||
"butternut squash": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "butternut squash",
|
||||
"plural_name": "butternut squashes"
|
||||
"name": "cabaza",
|
||||
"plural_name": "cabazas"
|
||||
},
|
||||
"romaine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "romaine",
|
||||
"plural_name": "romaines"
|
||||
"name": "leituga-romana",
|
||||
"plural_name": "leitugas-romanas"
|
||||
},
|
||||
"beetroot": {
|
||||
"aliases": [],
|
||||
|
@ -222,8 +222,8 @@
|
|||
"sun dried tomato": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sun dried tomato",
|
||||
"plural_name": "sun dried tomatoes"
|
||||
"name": "tomate seco",
|
||||
"plural_name": "tomates secos"
|
||||
},
|
||||
"radish": {
|
||||
"aliases": [],
|
||||
|
@ -234,8 +234,8 @@
|
|||
"red cabbage": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "red cabbage",
|
||||
"plural_name": "red cabbages"
|
||||
"name": "repolo roxo",
|
||||
"plural_name": "repolos roxos"
|
||||
},
|
||||
"artichoke": {
|
||||
"aliases": [],
|
||||
|
@ -251,7 +251,7 @@
|
|||
},
|
||||
"summer squash": {
|
||||
"aliases": [
|
||||
"courgette",
|
||||
"cabaciña",
|
||||
"gem squash"
|
||||
],
|
||||
"description": "",
|
||||
|
@ -274,7 +274,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "baby carrot",
|
||||
"plural_name": "baby carrots"
|
||||
"plural_name": "mini cenouras"
|
||||
},
|
||||
"mixed vegetable": {
|
||||
"aliases": [],
|
||||
|
@ -303,8 +303,8 @@
|
|||
"cayenne pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cayenne pepper",
|
||||
"plural_name": "cayenne peppers"
|
||||
"name": "pimenta caiena",
|
||||
"plural_name": "pimentas de caiena"
|
||||
},
|
||||
"green tomato": {
|
||||
"aliases": [],
|
||||
|
@ -327,8 +327,8 @@
|
|||
"mashed potato": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mashed potato",
|
||||
"plural_name": "mashed potatoes"
|
||||
"name": "puré de pataca",
|
||||
"plural_name": "purés de pataca"
|
||||
},
|
||||
"horseradish": {
|
||||
"aliases": [],
|
||||
|
@ -368,11 +368,11 @@
|
|||
},
|
||||
"napa cabbage": {
|
||||
"aliases": [
|
||||
"chinese leaves"
|
||||
"repolo chinés"
|
||||
],
|
||||
"description": "",
|
||||
"name": "napa cabbage",
|
||||
"plural_name": "napa cabbages"
|
||||
"name": "repolo napa",
|
||||
"plural_name": "repolos napa"
|
||||
},
|
||||
"celeriac": {
|
||||
"aliases": [],
|
||||
|
@ -389,8 +389,8 @@
|
|||
"turnip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "turnip",
|
||||
"plural_name": "turnips"
|
||||
"name": "nabo",
|
||||
"plural_name": "nabos"
|
||||
},
|
||||
"thai chile pepper": {
|
||||
"aliases": [],
|
||||
|
@ -628,15 +628,15 @@
|
|||
"foods": {
|
||||
"tomato": {
|
||||
"aliases": [],
|
||||
"description": "Yes they are a fruit",
|
||||
"description": "Si, son froitas",
|
||||
"name": "tomate",
|
||||
"plural_name": "tomates"
|
||||
},
|
||||
"lemon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lemon",
|
||||
"plural_name": "lemons"
|
||||
"name": "limón",
|
||||
"plural_name": "limóns"
|
||||
},
|
||||
"lime": {
|
||||
"aliases": [],
|
||||
|
@ -671,8 +671,8 @@
|
|||
"pineapple": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pineapple",
|
||||
"plural_name": "pineapples"
|
||||
"name": "ananás",
|
||||
"plural_name": "ananás"
|
||||
},
|
||||
"mango": {
|
||||
"aliases": [],
|
||||
|
@ -683,8 +683,8 @@
|
|||
"peach": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "peach",
|
||||
"plural_name": "peaches"
|
||||
"name": "pexego",
|
||||
"plural_name": "pexegos"
|
||||
},
|
||||
"date": {
|
||||
"aliases": [],
|
||||
|
@ -881,8 +881,8 @@
|
|||
"dried mango": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried mango",
|
||||
"plural_name": "dried mangoes"
|
||||
"name": "manga seca",
|
||||
"plural_name": "mangas secas"
|
||||
},
|
||||
"dried apple": {
|
||||
"aliases": [],
|
||||
|
@ -905,8 +905,8 @@
|
|||
"banana chip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "banana chip",
|
||||
"plural_name": "banana chips"
|
||||
"name": "chip de banana",
|
||||
"plural_name": "chips de banana"
|
||||
},
|
||||
"kumquat": {
|
||||
"aliases": [],
|
||||
|
@ -935,8 +935,8 @@
|
|||
"asian pear": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "asian pear",
|
||||
"plural_name": "asian pears"
|
||||
"name": "pera asiática",
|
||||
"plural_name": "peras asiáticas"
|
||||
},
|
||||
"lychee": {
|
||||
"aliases": [],
|
||||
|
@ -972,7 +972,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pomelo",
|
||||
"plural_name": "pomeloes"
|
||||
"plural_name": "pomelos"
|
||||
},
|
||||
"chestnut puree": {
|
||||
"aliases": [],
|
||||
|
@ -1007,8 +1007,8 @@
|
|||
"apple chip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "apple chip",
|
||||
"plural_name": "apple chips"
|
||||
"name": "chip de mazá",
|
||||
"plural_name": "chips de mazá"
|
||||
},
|
||||
"mixed peel": {
|
||||
"aliases": [],
|
||||
|
@ -1055,8 +1055,8 @@
|
|||
"dried lemon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried lemon",
|
||||
"plural_name": "dried lemons"
|
||||
"name": "limón seco",
|
||||
"plural_name": "limóns secos"
|
||||
},
|
||||
"young jackfruit": {
|
||||
"aliases": [],
|
||||
|
@ -1465,8 +1465,8 @@
|
|||
"raspberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raspberry",
|
||||
"plural_name": "raspberries"
|
||||
"name": "framboesa",
|
||||
"plural_name": "framboesas"
|
||||
},
|
||||
"cranberry": {
|
||||
"aliases": [],
|
||||
|
@ -1483,8 +1483,8 @@
|
|||
"blackberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "blackberry",
|
||||
"plural_name": "blackberries"
|
||||
"name": "amora",
|
||||
"plural_name": "amoras"
|
||||
},
|
||||
"berry mix": {
|
||||
"aliases": [],
|
||||
|
@ -1781,8 +1781,8 @@
|
|||
"pumpkin seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pumpkin seed",
|
||||
"plural_name": "pumpkin seeds"
|
||||
"name": "semente de cabaza",
|
||||
"plural_name": "sementes de cabaza"
|
||||
},
|
||||
"hazelnut": {
|
||||
"aliases": [],
|
||||
|
@ -2009,7 +2009,7 @@
|
|||
"cheddars"
|
||||
],
|
||||
"description": "",
|
||||
"name": "cheddar cheese",
|
||||
"name": "queixo cheddar",
|
||||
"plural_name": "cheddar cheeses"
|
||||
},
|
||||
"cream cheese": {
|
||||
|
@ -2531,8 +2531,8 @@
|
|||
"requeijão": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "requeijão",
|
||||
"plural_name": "requeijãoes"
|
||||
"name": "requeixo",
|
||||
"plural_name": "requeixos"
|
||||
},
|
||||
"vacherin": {
|
||||
"aliases": [],
|
||||
|
@ -2687,8 +2687,8 @@
|
|||
"condensed milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "condensed milk",
|
||||
"plural_name": "condensed milks"
|
||||
"name": "leite condensado",
|
||||
"plural_name": "leites condensados"
|
||||
},
|
||||
"half and half": {
|
||||
"aliases": [],
|
||||
|
@ -2849,8 +2849,8 @@
|
|||
"goat milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat milk",
|
||||
"plural_name": "goat milks"
|
||||
"name": "leite de cabra",
|
||||
"plural_name": "leites de cabra"
|
||||
},
|
||||
"cheese curd": {
|
||||
"aliases": [],
|
||||
|
@ -2879,8 +2879,8 @@
|
|||
"duck egg": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "duck egg",
|
||||
"plural_name": "duck eggs"
|
||||
"name": "ovo de pato",
|
||||
"plural_name": "ovos de pato"
|
||||
},
|
||||
"salted egg": {
|
||||
"aliases": [],
|
||||
|
@ -2903,8 +2903,8 @@
|
|||
"raw milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raw milk",
|
||||
"plural_name": "raw milks"
|
||||
"name": "leite cru",
|
||||
"plural_name": "leites crus"
|
||||
},
|
||||
"lime curd": {
|
||||
"aliases": [],
|
||||
|
@ -2975,8 +2975,8 @@
|
|||
"goat butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat butter",
|
||||
"plural_name": "goat butter"
|
||||
"name": "manteiga de leite de cabra",
|
||||
"plural_name": "manteigas de leite de cabra"
|
||||
},
|
||||
"century egg": {
|
||||
"aliases": [],
|
||||
|
@ -3141,8 +3141,8 @@
|
|||
"almond milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "almond milk",
|
||||
"plural_name": "almond milks"
|
||||
"name": "leite de améndoa",
|
||||
"plural_name": "leites de améndoa"
|
||||
},
|
||||
"almond butter": {
|
||||
"aliases": [],
|
||||
|
@ -3165,7 +3165,7 @@
|
|||
"vegan butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan butter",
|
||||
"name": "manteiga vegana",
|
||||
"plural_name": "vegan butter"
|
||||
},
|
||||
"non-dairy milk": {
|
||||
|
@ -3219,8 +3219,8 @@
|
|||
"vegan cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan cheese",
|
||||
"plural_name": "vegan cheeses"
|
||||
"name": "queixo vegano",
|
||||
"plural_name": "queixos veganos"
|
||||
},
|
||||
"cashew butter": {
|
||||
"aliases": [],
|
||||
|
@ -3267,8 +3267,8 @@
|
|||
"oat milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "oat milk",
|
||||
"plural_name": "oat milks"
|
||||
"name": "leite de avea",
|
||||
"plural_name": "leites de avea"
|
||||
},
|
||||
"nut butter": {
|
||||
"aliases": [],
|
||||
|
@ -3280,7 +3280,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "leite de arroz",
|
||||
"plural_name": "rice milks"
|
||||
"plural_name": "leites de arroz"
|
||||
},
|
||||
"vegan sour cream": {
|
||||
"aliases": [],
|
||||
|
@ -3823,8 +3823,8 @@
|
|||
"chorizo": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chorizo",
|
||||
"plural_name": "chorizoes"
|
||||
"name": "chourizo",
|
||||
"plural_name": "chourizos"
|
||||
},
|
||||
"pancetta": {
|
||||
"aliases": [],
|
||||
|
@ -3883,8 +3883,8 @@
|
|||
"salami": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "salami",
|
||||
"plural_name": "salamis"
|
||||
"name": "salame",
|
||||
"plural_name": "salames"
|
||||
},
|
||||
"brisket": {
|
||||
"aliases": [],
|
||||
|
@ -5079,8 +5079,8 @@
|
|||
"carp": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "carp",
|
||||
"plural_name": "carp"
|
||||
"name": "carpa",
|
||||
"plural_name": "carpas"
|
||||
},
|
||||
"cuttlefish": {
|
||||
"aliases": [],
|
||||
|
@ -5515,8 +5515,8 @@
|
|||
"crab": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "crab",
|
||||
"plural_name": "crabs"
|
||||
"name": "caranguexo",
|
||||
"plural_name": "caranguexos"
|
||||
},
|
||||
"scallop": {
|
||||
"aliases": [],
|
||||
|
@ -5813,8 +5813,8 @@
|
|||
"cinnamon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cinnamon",
|
||||
"plural_name": "cinnamons"
|
||||
"name": "canela",
|
||||
"plural_name": "canelas"
|
||||
},
|
||||
"parsley": {
|
||||
"aliases": [],
|
||||
|
@ -5855,8 +5855,8 @@
|
|||
"garlic powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "garlic powder",
|
||||
"plural_name": "garlic powders"
|
||||
"name": "allo en pó",
|
||||
"plural_name": "allos en pó"
|
||||
},
|
||||
"oregano": {
|
||||
"aliases": [],
|
||||
|
@ -5921,8 +5921,8 @@
|
|||
"onion powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "onion powder",
|
||||
"plural_name": "onion powders"
|
||||
"name": "cebola en pó",
|
||||
"plural_name": "cebolas en pó"
|
||||
},
|
||||
"ginger powder": {
|
||||
"aliases": [],
|
||||
|
@ -15107,8 +15107,8 @@
|
|||
"coffee": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "coffee",
|
||||
"plural_name": "coffees"
|
||||
"name": "café",
|
||||
"plural_name": "cafés"
|
||||
},
|
||||
"club soda": {
|
||||
"aliases": [],
|
||||
|
|
|
@ -1890,7 +1890,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "trail mix",
|
||||
"plural_name": "trail mixes"
|
||||
"plural_name": "studentenhavers"
|
||||
},
|
||||
"basil seed": {
|
||||
"aliases": [],
|
||||
|
@ -2105,8 +2105,8 @@
|
|||
"cottage cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cottage cheese",
|
||||
"plural_name": "cottage cheeses"
|
||||
"name": "huttenkaas",
|
||||
"plural_name": "huttenkazen"
|
||||
},
|
||||
"american cheese": {
|
||||
"aliases": [],
|
||||
|
@ -2813,14 +2813,14 @@
|
|||
"buttermilk powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "buttermilk powder",
|
||||
"plural_name": "buttermilk powders"
|
||||
"name": "karnemelkpoeder",
|
||||
"plural_name": "karnemelkpoeders"
|
||||
},
|
||||
"frozen yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "frozen yogurt",
|
||||
"plural_name": "frozen yogurts"
|
||||
"name": "bevroren yoghurt",
|
||||
"plural_name": "bevroren yoghurts"
|
||||
},
|
||||
"khoya": {
|
||||
"aliases": [],
|
||||
|
@ -2951,8 +2951,8 @@
|
|||
"honey greek yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "honey greek yogurt",
|
||||
"plural_name": "honey greek yogurts"
|
||||
"name": "Griekse honing yoghurt",
|
||||
"plural_name": "Griekse honing yoghurt"
|
||||
},
|
||||
"amul butter": {
|
||||
"aliases": [],
|
||||
|
@ -2963,8 +2963,8 @@
|
|||
"honey butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "honey butter",
|
||||
"plural_name": "honey butter"
|
||||
"name": "honing boter",
|
||||
"plural_name": "honing boter"
|
||||
},
|
||||
"strawberry cream cheese": {
|
||||
"aliases": [],
|
||||
|
@ -2993,8 +2993,8 @@
|
|||
"goat yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat yogurt",
|
||||
"plural_name": "goat yogurts"
|
||||
"name": "geiten yoghurt",
|
||||
"plural_name": "geiten yoghurt"
|
||||
},
|
||||
"dahi": {
|
||||
"aliases": [],
|
||||
|
@ -3041,7 +3041,7 @@
|
|||
"strawberry milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strawberry milk",
|
||||
"name": "aardbeien melk",
|
||||
"plural_name": "strawberry milks"
|
||||
},
|
||||
"ayran": {
|
||||
|
@ -3165,8 +3165,8 @@
|
|||
"vegan butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan butter",
|
||||
"plural_name": "vegan butter"
|
||||
"name": "veganistische boter",
|
||||
"plural_name": "veganistische boter"
|
||||
},
|
||||
"non-dairy milk": {
|
||||
"aliases": [],
|
||||
|
@ -3243,8 +3243,8 @@
|
|||
"coconut yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "coconut yogurt",
|
||||
"plural_name": "coconut yogurts"
|
||||
"name": "kokokosnoot yoghurt",
|
||||
"plural_name": "kokokosnoot yoghurt"
|
||||
},
|
||||
"non-dairy yogurt": {
|
||||
"aliases": [],
|
||||
|
@ -3279,8 +3279,8 @@
|
|||
"rice milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "rice milk",
|
||||
"plural_name": "rice milks"
|
||||
"name": "rijstmelk",
|
||||
"plural_name": "rijstmelk"
|
||||
},
|
||||
"vegan sour cream": {
|
||||
"aliases": [],
|
||||
|
@ -3429,8 +3429,8 @@
|
|||
"vegan feta": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan feta",
|
||||
"plural_name": "vegan fetas"
|
||||
"name": "veganistische feta",
|
||||
"plural_name": "veganistische feta"
|
||||
},
|
||||
"soy chorizo": {
|
||||
"aliases": [],
|
||||
|
@ -3693,8 +3693,8 @@
|
|||
"banana milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "banana milk",
|
||||
"plural_name": "banana milks"
|
||||
"name": "bananenmelk",
|
||||
"plural_name": "bananenmelk"
|
||||
},
|
||||
"soy quark": {
|
||||
"aliases": [],
|
||||
|
@ -3739,7 +3739,7 @@
|
|||
"bacon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "bacon",
|
||||
"name": "spek",
|
||||
"plural_name": "bacons"
|
||||
},
|
||||
"chopped bacon": {
|
||||
|
@ -3884,7 +3884,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "salami",
|
||||
"plural_name": "salamis"
|
||||
"plural_name": "salami"
|
||||
},
|
||||
"brisket": {
|
||||
"aliases": [],
|
||||
|
@ -4081,8 +4081,8 @@
|
|||
"rabbit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "rabbit",
|
||||
"plural_name": "rabbits"
|
||||
"name": "konijn",
|
||||
"plural_name": "konijnen"
|
||||
},
|
||||
"pork cutlet": {
|
||||
"aliases": [],
|
||||
|
@ -4171,8 +4171,8 @@
|
|||
"beef liver": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "beef liver",
|
||||
"plural_name": "beef livers"
|
||||
"name": "runderlever",
|
||||
"plural_name": "runderlevers"
|
||||
},
|
||||
"pastrami": {
|
||||
"aliases": [],
|
||||
|
@ -4237,7 +4237,7 @@
|
|||
"dried beef": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried beef",
|
||||
"name": "gedroogd rundvlees",
|
||||
"plural_name": "dried beefs"
|
||||
},
|
||||
"gammon joint": {
|
||||
|
@ -4439,14 +4439,14 @@
|
|||
"duck": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "duck",
|
||||
"plural_name": "ducks"
|
||||
"name": "eend",
|
||||
"plural_name": "eenden"
|
||||
},
|
||||
"duck breast": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "duck breast",
|
||||
"plural_name": "duck breasts"
|
||||
"name": "eendenborst",
|
||||
"plural_name": "eendenborsten"
|
||||
},
|
||||
"boneless chicken": {
|
||||
"aliases": [],
|
||||
|
@ -4457,8 +4457,8 @@
|
|||
"chicken liver": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken liver",
|
||||
"plural_name": "chicken livers"
|
||||
"name": "kippenlever",
|
||||
"plural_name": "kippenlevers"
|
||||
},
|
||||
"cornish hen": {
|
||||
"aliases": [],
|
||||
|
@ -4499,7 +4499,7 @@
|
|||
"quail": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "quail",
|
||||
"name": "kwartel",
|
||||
"plural_name": "quails"
|
||||
},
|
||||
"smoked turkey sausage": {
|
||||
|
@ -4595,7 +4595,7 @@
|
|||
"chicken nugget": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chicken nugget",
|
||||
"name": "kipnugget",
|
||||
"plural_name": "chicken nuggets"
|
||||
},
|
||||
"turkey burger": {
|
||||
|
|
|
@ -251,7 +251,7 @@
|
|||
},
|
||||
"summer squash": {
|
||||
"aliases": [
|
||||
"courgette",
|
||||
"squash",
|
||||
"gem squash"
|
||||
],
|
||||
"description": "",
|
||||
|
@ -339,7 +339,7 @@
|
|||
"chard": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chard",
|
||||
"name": "bladbete",
|
||||
"plural_name": "chards"
|
||||
},
|
||||
"pimiento": {
|
||||
|
@ -402,7 +402,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "bok choy",
|
||||
"plural_name": "bok choy"
|
||||
"plural_name": "pak choi"
|
||||
},
|
||||
"okra": {
|
||||
"aliases": [],
|
||||
|
@ -511,8 +511,8 @@
|
|||
"baby corn": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "baby corn",
|
||||
"plural_name": "baby corns"
|
||||
"name": "baby mais",
|
||||
"plural_name": "baby mais"
|
||||
},
|
||||
"broccoli rabe": {
|
||||
"aliases": [],
|
||||
|
@ -642,7 +642,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lime",
|
||||
"plural_name": "limes"
|
||||
"plural_name": "lime"
|
||||
},
|
||||
"apple": {
|
||||
"aliases": [],
|
||||
|
@ -719,7 +719,7 @@
|
|||
"pomegranate": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pomegranate",
|
||||
"name": "granateple",
|
||||
"plural_name": "pomegranates"
|
||||
},
|
||||
"watermelon": {
|
||||
|
@ -749,7 +749,7 @@
|
|||
"grapefruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "grapefruit",
|
||||
"name": "grapefrukt",
|
||||
"plural_name": "grapefrukt"
|
||||
},
|
||||
"plum": {
|
||||
|
@ -762,13 +762,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "fig",
|
||||
"plural_name": "figs"
|
||||
"plural_name": "fikener"
|
||||
},
|
||||
"apricot": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "aprikos",
|
||||
"plural_name": "apricots"
|
||||
"plural_name": "aprikos"
|
||||
},
|
||||
"currant": {
|
||||
"aliases": [],
|
||||
|
@ -803,8 +803,8 @@
|
|||
"passion fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "passion fruit",
|
||||
"plural_name": "passion fruits"
|
||||
"name": "pasjonsfrukt",
|
||||
"plural_name": "pasjonsfrukter"
|
||||
},
|
||||
"papaya": {
|
||||
"aliases": [],
|
||||
|
@ -821,20 +821,20 @@
|
|||
"nectarine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "nectarine",
|
||||
"plural_name": "nectarines"
|
||||
"name": "nektarin",
|
||||
"plural_name": "nektariner"
|
||||
},
|
||||
"dried fig": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fig",
|
||||
"plural_name": "dried figs"
|
||||
"plural_name": "tørkede fikener"
|
||||
},
|
||||
"chestnut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chestnut",
|
||||
"plural_name": "chestnuts"
|
||||
"name": "kastanje",
|
||||
"plural_name": "kastanjer"
|
||||
},
|
||||
"meyer lemon": {
|
||||
"aliases": [],
|
||||
|
@ -845,14 +845,14 @@
|
|||
"honeydew melon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "honeydew melon",
|
||||
"name": "honning melon",
|
||||
"plural_name": "honeydew melons"
|
||||
},
|
||||
"dried fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fruit",
|
||||
"plural_name": "dried fruits"
|
||||
"name": "tørket frukt",
|
||||
"plural_name": "tørket frukt"
|
||||
},
|
||||
"clementine": {
|
||||
"aliases": [],
|
||||
|
@ -1056,7 +1056,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried lemon",
|
||||
"plural_name": "dried lemons"
|
||||
"plural_name": "tørkede sitroner"
|
||||
},
|
||||
"young jackfruit": {
|
||||
"aliases": [],
|
||||
|
|
|
@ -310,7 +310,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "green tomato",
|
||||
"plural_name": "green tomatoes"
|
||||
"plural_name": "zielone pomidory"
|
||||
},
|
||||
"watercress": {
|
||||
"aliases": [],
|
||||
|
@ -357,8 +357,8 @@
|
|||
"butter lettuce": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "butter lettuce",
|
||||
"plural_name": "butter lettuces"
|
||||
"name": "sałata masłowa",
|
||||
"plural_name": "sałaty masłowe"
|
||||
},
|
||||
"hash brown": {
|
||||
"aliases": [],
|
||||
|
@ -389,8 +389,8 @@
|
|||
"turnip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "turnip",
|
||||
"plural_name": "turnips"
|
||||
"name": "rzepa",
|
||||
"plural_name": "rzepy"
|
||||
},
|
||||
"thai chile pepper": {
|
||||
"aliases": [],
|
||||
|
@ -851,8 +851,8 @@
|
|||
"dried fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fruit",
|
||||
"plural_name": "dried fruits"
|
||||
"name": "Suszony owoc",
|
||||
"plural_name": "Suszone owoce"
|
||||
},
|
||||
"clementine": {
|
||||
"aliases": [],
|
||||
|
@ -881,14 +881,14 @@
|
|||
"dried mango": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried mango",
|
||||
"plural_name": "dried mangoes"
|
||||
"name": "Suszone mango",
|
||||
"plural_name": "Suszone mango"
|
||||
},
|
||||
"dried apple": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried apple",
|
||||
"plural_name": "dried apples"
|
||||
"name": "Suszone jabłko",
|
||||
"plural_name": "Suszone jabłka"
|
||||
},
|
||||
"quince": {
|
||||
"aliases": [],
|
||||
|
@ -912,7 +912,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kumquat",
|
||||
"plural_name": "kumquats"
|
||||
"plural_name": "kumkwat"
|
||||
},
|
||||
"jackfruit": {
|
||||
"aliases": [],
|
||||
|
@ -923,8 +923,8 @@
|
|||
"dragon fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dragon fruit",
|
||||
"plural_name": "dragon fruits"
|
||||
"name": "smoczy owoc",
|
||||
"plural_name": "smocze owoce"
|
||||
},
|
||||
"mixed fruit": {
|
||||
"aliases": [],
|
||||
|
@ -959,20 +959,20 @@
|
|||
"star fruit": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "star fruit",
|
||||
"plural_name": "star fruits"
|
||||
"name": "karambola",
|
||||
"plural_name": "karambole"
|
||||
},
|
||||
"green papaya": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "green papaya",
|
||||
"plural_name": "green papayas"
|
||||
"name": "zielona papaja",
|
||||
"plural_name": "zielone papaje"
|
||||
},
|
||||
"pomelo": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pomelo",
|
||||
"plural_name": "pomeloes"
|
||||
"plural_name": "pomelo"
|
||||
},
|
||||
"chestnut puree": {
|
||||
"aliases": [],
|
||||
|
@ -1055,8 +1055,8 @@
|
|||
"dried lemon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried lemon",
|
||||
"plural_name": "dried lemons"
|
||||
"name": "Suszona cytryna",
|
||||
"plural_name": "Suszone cytryny"
|
||||
},
|
||||
"young jackfruit": {
|
||||
"aliases": [],
|
||||
|
@ -1068,7 +1068,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "durian",
|
||||
"plural_name": "durians"
|
||||
"plural_name": "duriany"
|
||||
},
|
||||
"freeze-dried apple": {
|
||||
"aliases": [],
|
||||
|
@ -1245,8 +1245,8 @@
|
|||
"shiitake mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "shiitake mushroom",
|
||||
"plural_name": "shiitake mushrooms"
|
||||
"name": "Grzyb Shiitake",
|
||||
"plural_name": "Grzyby Shiitake"
|
||||
},
|
||||
"portobello mushroom": {
|
||||
"aliases": [],
|
||||
|
@ -1299,8 +1299,8 @@
|
|||
"black truffle": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "black truffle",
|
||||
"plural_name": "black truffles"
|
||||
"name": "czarna trufla",
|
||||
"plural_name": "czarne trufle"
|
||||
},
|
||||
"morel mushroom": {
|
||||
"aliases": [],
|
||||
|
@ -1353,8 +1353,8 @@
|
|||
"white truffle": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "white truffle",
|
||||
"plural_name": "white truffles"
|
||||
"name": "biała trufla",
|
||||
"plural_name": "białe trufle"
|
||||
},
|
||||
"white fungu": {
|
||||
"aliases": [],
|
||||
|
@ -1453,26 +1453,26 @@
|
|||
"strawberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strawberry",
|
||||
"plural_name": "strawberries"
|
||||
"name": "truskawka",
|
||||
"plural_name": "truskawki"
|
||||
},
|
||||
"blueberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "blueberry",
|
||||
"plural_name": "blueberries"
|
||||
"name": "borówka",
|
||||
"plural_name": "borówki"
|
||||
},
|
||||
"raspberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raspberry",
|
||||
"plural_name": "raspberries"
|
||||
"name": "malina",
|
||||
"plural_name": "maliny"
|
||||
},
|
||||
"cranberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cranberry",
|
||||
"plural_name": "cranberries"
|
||||
"name": "żurawina",
|
||||
"plural_name": "żurawiny"
|
||||
},
|
||||
"cherry": {
|
||||
"aliases": [],
|
||||
|
@ -1483,8 +1483,8 @@
|
|||
"blackberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "blackberry",
|
||||
"plural_name": "blackberries"
|
||||
"name": "jeżyna",
|
||||
"plural_name": "jeżyny"
|
||||
},
|
||||
"berry mix": {
|
||||
"aliases": [],
|
||||
|
@ -1519,14 +1519,14 @@
|
|||
"goji berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goji berry",
|
||||
"plural_name": "goji berries"
|
||||
"name": "jagoda goji",
|
||||
"plural_name": "jagody goji"
|
||||
},
|
||||
"dried blueberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried blueberry",
|
||||
"plural_name": "dried blueberries"
|
||||
"name": "Suszona borówka",
|
||||
"plural_name": "Suszone borówki"
|
||||
},
|
||||
"freeze-dried strawberry": {
|
||||
"aliases": [],
|
||||
|
@ -1537,8 +1537,8 @@
|
|||
"gooseberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "gooseberry",
|
||||
"plural_name": "gooseberries"
|
||||
"name": "agrest",
|
||||
"plural_name": "agresty"
|
||||
},
|
||||
"freeze-dried raspberry": {
|
||||
"aliases": [],
|
||||
|
@ -1561,14 +1561,14 @@
|
|||
"mulberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mulberry",
|
||||
"plural_name": "mulberries"
|
||||
"name": "morwa",
|
||||
"plural_name": "morwy"
|
||||
},
|
||||
"acai berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "acai berry",
|
||||
"plural_name": "acai berries"
|
||||
"name": "jagoda acai",
|
||||
"plural_name": "jagody acai"
|
||||
},
|
||||
"canned cherry": {
|
||||
"aliases": [],
|
||||
|
@ -1585,8 +1585,8 @@
|
|||
"elderberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "elderberry",
|
||||
"plural_name": "elderberries"
|
||||
"name": "czarny bez",
|
||||
"plural_name": "czarny bez"
|
||||
},
|
||||
"freeze-dried blueberry": {
|
||||
"aliases": [],
|
||||
|
@ -1663,8 +1663,8 @@
|
|||
"aronia berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "aronia berry",
|
||||
"plural_name": "aronia berries"
|
||||
"name": "jagoda aronii",
|
||||
"plural_name": "jagody aronii"
|
||||
},
|
||||
"chokeberry": {
|
||||
"aliases": [],
|
||||
|
@ -5181,8 +5181,8 @@
|
|||
"dried anchovy": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried anchovy",
|
||||
"plural_name": "dried anchovies"
|
||||
"name": "Suszona anszua",
|
||||
"plural_name": "Suszone anszua"
|
||||
},
|
||||
"arctic char": {
|
||||
"aliases": [],
|
||||
|
@ -5331,8 +5331,8 @@
|
|||
"dried fish": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried fish",
|
||||
"plural_name": "dried fish"
|
||||
"name": "suszona ryba",
|
||||
"plural_name": "suszone ryby"
|
||||
},
|
||||
"flathead": {
|
||||
"aliases": [],
|
||||
|
@ -5587,8 +5587,8 @@
|
|||
"dried shrimp": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried shrimp",
|
||||
"plural_name": "dried shrimps"
|
||||
"name": "suszona garnela",
|
||||
"plural_name": "suszone garnele"
|
||||
},
|
||||
"bay scallop": {
|
||||
"aliases": [],
|
||||
|
@ -5641,8 +5641,8 @@
|
|||
"dried prawn": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried prawn",
|
||||
"plural_name": "dried prawns"
|
||||
"name": "suszona krewetka",
|
||||
"plural_name": "suszone krewetki"
|
||||
},
|
||||
"dulse seaweed": {
|
||||
"aliases": [],
|
||||
|
@ -6215,8 +6215,8 @@
|
|||
"dried chili": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried chili",
|
||||
"plural_name": "dried chilies"
|
||||
"name": "suszone chili",
|
||||
"plural_name": "suszone chili"
|
||||
},
|
||||
"black cardamom": {
|
||||
"aliases": [],
|
||||
|
@ -9332,8 +9332,8 @@
|
|||
"dried pea": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dried pea",
|
||||
"plural_name": "dried peas"
|
||||
"name": "suszony groch",
|
||||
"plural_name": "suszony groch"
|
||||
},
|
||||
"pink bean": {
|
||||
"aliases": [],
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -395,44 +395,44 @@
|
|||
"thai chile pepper": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "thai chile pepper",
|
||||
"plural_name": "thai chile peppers"
|
||||
"name": "тайский перец чили",
|
||||
"plural_name": "тайские перцы чили"
|
||||
},
|
||||
"bok choy": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "bok choy",
|
||||
"plural_name": "bok choy"
|
||||
"name": "бок-чой, черешковая капуста",
|
||||
"plural_name": "бок-чой, черешковых капуст"
|
||||
},
|
||||
"okra": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "okra",
|
||||
"plural_name": "okra"
|
||||
"name": "бамия",
|
||||
"plural_name": "бамия"
|
||||
},
|
||||
"acorn squash": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "acorn squash",
|
||||
"plural_name": "acorn squashes"
|
||||
"name": "желудевая тыква",
|
||||
"plural_name": "желудевых тыкв"
|
||||
},
|
||||
"corn cob": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "corn cob",
|
||||
"plural_name": "corn cobs"
|
||||
"name": "кукурузный початок",
|
||||
"plural_name": "кукурузных початков"
|
||||
},
|
||||
"radicchio": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "radicchio",
|
||||
"plural_name": "radicchio"
|
||||
"name": "радиччио, итальянский цикорий",
|
||||
"plural_name": "радиччио, итальянских цикориев"
|
||||
},
|
||||
"pearl onion": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pearl onion",
|
||||
"plural_name": "pearl onions"
|
||||
"name": "жемчужный лук",
|
||||
"plural_name": "жемчужных луковиц"
|
||||
},
|
||||
"tenderstem broccoli": {
|
||||
"aliases": [],
|
||||
|
|
|
@ -1853,8 +1853,8 @@
|
|||
"onion seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "onion seed",
|
||||
"plural_name": "onion seeds"
|
||||
"name": "lökfrö",
|
||||
"plural_name": "lökfrön"
|
||||
},
|
||||
"watermelon seed": {
|
||||
"aliases": [],
|
||||
|
@ -1913,8 +1913,8 @@
|
|||
"jackfruit seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "jackfruit seed",
|
||||
"plural_name": "jackfruit seeds"
|
||||
"name": "jackfruktfrö",
|
||||
"plural_name": "jackfruktfrön"
|
||||
},
|
||||
"honey-roasted almond": {
|
||||
"aliases": [],
|
||||
|
@ -1932,7 +1932,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chironji",
|
||||
"plural_name": "chironjis"
|
||||
"plural_name": "chironjin"
|
||||
},
|
||||
"honey-roasted pecan": {
|
||||
"aliases": [],
|
||||
|
@ -1943,8 +1943,8 @@
|
|||
"tigernut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "tigernut",
|
||||
"plural_name": "tigernuts"
|
||||
"name": "jordmandel",
|
||||
"plural_name": "jordmandlar"
|
||||
},
|
||||
"sunflower sprout": {
|
||||
"aliases": [],
|
||||
|
@ -1967,26 +1967,26 @@
|
|||
"ginkgo nut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "ginkgo nut",
|
||||
"plural_name": "ginkgo nuts"
|
||||
"name": "ginkonöt",
|
||||
"plural_name": "ginkonötter"
|
||||
},
|
||||
"keto trail mix": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "keto trail mix",
|
||||
"plural_name": "keto trail mixes"
|
||||
"name": "keto trail-mix",
|
||||
"plural_name": "keto trail-mixer"
|
||||
},
|
||||
"wattleseed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "wattleseed",
|
||||
"plural_name": "wattleseeds"
|
||||
"name": "akaciafrö",
|
||||
"plural_name": "akaciafrön"
|
||||
},
|
||||
"barùka": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "barùka",
|
||||
"plural_name": "barùkas"
|
||||
"plural_name": "barùkan"
|
||||
},
|
||||
"indian almond": {
|
||||
"aliases": [],
|
||||
|
@ -2147,8 +2147,8 @@
|
|||
"fontina": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "fontina",
|
||||
"plural_name": "fontinas"
|
||||
"name": "fortina-ost",
|
||||
"plural_name": "fortina-ostar"
|
||||
},
|
||||
"queso fresco": {
|
||||
"aliases": [],
|
||||
|
@ -2171,8 +2171,8 @@
|
|||
"cotija": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cotija",
|
||||
"plural_name": "cotijas"
|
||||
"name": "cotijamajs",
|
||||
"plural_name": "cotijamajs"
|
||||
},
|
||||
"asiago": {
|
||||
"aliases": [],
|
||||
|
@ -2213,14 +2213,14 @@
|
|||
"neufchatel": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "neufchatel",
|
||||
"plural_name": "neufchatels"
|
||||
"name": "neufchatelost",
|
||||
"plural_name": "neufchatelsostar"
|
||||
},
|
||||
"herb cream cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "herb cream cheese",
|
||||
"plural_name": "herb cream cheeses"
|
||||
"name": "örtfärskost",
|
||||
"plural_name": "örtfärskostar"
|
||||
},
|
||||
"burrata": {
|
||||
"aliases": [],
|
||||
|
@ -2303,14 +2303,14 @@
|
|||
"oaxaca": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "oaxaca",
|
||||
"plural_name": "oaxacas"
|
||||
"name": "oaxaca-ost",
|
||||
"plural_name": "oaxaca-ostar"
|
||||
},
|
||||
"labneh": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "labneh",
|
||||
"plural_name": "labnehs"
|
||||
"name": "labneh-ost",
|
||||
"plural_name": "labnehs-ostar"
|
||||
},
|
||||
"edam": {
|
||||
"aliases": [],
|
||||
|
@ -2339,44 +2339,44 @@
|
|||
"asadero": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "asadero",
|
||||
"plural_name": "asaderoes"
|
||||
"name": "asadero-ost",
|
||||
"plural_name": "asadero-ostar"
|
||||
},
|
||||
"marble cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "marble cheese",
|
||||
"plural_name": "marble cheeses"
|
||||
"name": "marmorost",
|
||||
"plural_name": "marmorostar"
|
||||
},
|
||||
"leicester": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "leicester",
|
||||
"plural_name": "leicesters"
|
||||
"name": "leicesterost",
|
||||
"plural_name": "leicesterostar"
|
||||
},
|
||||
"kefalotyri": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kefalotyri",
|
||||
"plural_name": "kefalotyris"
|
||||
"name": "kefalotyriost",
|
||||
"plural_name": "kefalotyriostar"
|
||||
},
|
||||
"mizithra": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mizithra",
|
||||
"plural_name": "mizithras"
|
||||
"name": "mizithra-ost",
|
||||
"plural_name": "mizithras-ostar"
|
||||
},
|
||||
"lancashire": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lancashire",
|
||||
"plural_name": "lancashires"
|
||||
"name": "lancashire-ost",
|
||||
"plural_name": "lancashire-ostar"
|
||||
},
|
||||
"kasseri": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kasseri",
|
||||
"plural_name": "kasseris"
|
||||
"name": "kasseriost",
|
||||
"plural_name": "kasseriostar"
|
||||
},
|
||||
"babybel": {
|
||||
"aliases": [],
|
||||
|
@ -2387,8 +2387,8 @@
|
|||
"panela cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "panela cheese",
|
||||
"plural_name": "panela cheeses"
|
||||
"name": "panelaost",
|
||||
"plural_name": "panelaostar"
|
||||
},
|
||||
"longhorn": {
|
||||
"aliases": [],
|
||||
|
@ -2399,8 +2399,8 @@
|
|||
"seasoned feta cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "seasoned feta cheese",
|
||||
"plural_name": "seasoned feta cheeses"
|
||||
"name": "kryddad fetaost",
|
||||
"plural_name": "kryddade fetaostar"
|
||||
},
|
||||
"comté": {
|
||||
"aliases": [],
|
||||
|
@ -2411,8 +2411,8 @@
|
|||
"graviera": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "graviera",
|
||||
"plural_name": "gravieras"
|
||||
"name": "gravieraost",
|
||||
"plural_name": "gravieraostar"
|
||||
},
|
||||
"wensleydale": {
|
||||
"aliases": [],
|
||||
|
@ -2430,55 +2430,55 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cambozola",
|
||||
"plural_name": "cambozolas"
|
||||
"plural_name": "cambozolaost"
|
||||
},
|
||||
"cheshire cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cheshire cheese",
|
||||
"plural_name": "cheshire cheeses"
|
||||
"name": "cheshire-ost",
|
||||
"plural_name": "cheshire-ostar"
|
||||
},
|
||||
"anthotyro": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "anthotyro",
|
||||
"plural_name": "anthotyros"
|
||||
"name": "antotyro-ost",
|
||||
"plural_name": "anthotyro-ostar"
|
||||
},
|
||||
"chenna": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chenna",
|
||||
"plural_name": "chennas"
|
||||
"name": "chenna-ost",
|
||||
"plural_name": "chennas-ostar"
|
||||
},
|
||||
"hard goat cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hard goat cheese",
|
||||
"plural_name": "hard goat cheeses"
|
||||
"name": "hård getost",
|
||||
"plural_name": "hårda getostar"
|
||||
},
|
||||
"kashkaval": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "kashkaval",
|
||||
"plural_name": "kashkavals"
|
||||
"plural_name": "kashkavaler"
|
||||
},
|
||||
"sheep cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sheep cheese",
|
||||
"name": "fårost",
|
||||
"plural_name": "fårost"
|
||||
},
|
||||
"amul cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "amul cheese",
|
||||
"plural_name": "amul cheeses"
|
||||
"name": "amul-ost",
|
||||
"plural_name": "amul-ostar"
|
||||
},
|
||||
"reblochon": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "reblochon",
|
||||
"plural_name": "reblochons"
|
||||
"plural_name": "reblochoner"
|
||||
},
|
||||
"robiola": {
|
||||
"aliases": [],
|
||||
|
@ -2501,20 +2501,20 @@
|
|||
"farmer's cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "farmer's cheese",
|
||||
"plural_name": "farmer's cheeses"
|
||||
"name": "bondost",
|
||||
"plural_name": "bondostar"
|
||||
},
|
||||
"manouri": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "manouri",
|
||||
"plural_name": "manouris"
|
||||
"name": "manouri-ost",
|
||||
"plural_name": "manouri-ostar"
|
||||
},
|
||||
"mimolette": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mimolette",
|
||||
"plural_name": "mimolettes"
|
||||
"plural_name": "mimoletter"
|
||||
},
|
||||
"queso quesadilla": {
|
||||
"aliases": [],
|
||||
|
@ -2525,7 +2525,7 @@
|
|||
"caciocavallo": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "caciocavallo",
|
||||
"name": "",
|
||||
"plural_name": "caciocavalloes"
|
||||
},
|
||||
"requeijão": {
|
||||
|
@ -2598,7 +2598,7 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "petit-suisse",
|
||||
"plural_name": "petit-suisses"
|
||||
"plural_name": "petit-suisser"
|
||||
},
|
||||
"sbrinz": {
|
||||
"aliases": [],
|
||||
|
@ -2970,13 +2970,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strawberry cream cheese",
|
||||
"plural_name": "strawberry cream cheeses"
|
||||
"plural_name": "jordgubbsfärskost"
|
||||
},
|
||||
"goat butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat butter",
|
||||
"plural_name": "goat butter"
|
||||
"name": "getsmör\n",
|
||||
"plural_name": "getsmör"
|
||||
},
|
||||
"century egg": {
|
||||
"aliases": [],
|
||||
|
@ -2987,14 +2987,14 @@
|
|||
"orange curd": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "orange curd",
|
||||
"plural_name": "orange curds"
|
||||
"name": "apelsincurd",
|
||||
"plural_name": "apelsincurd"
|
||||
},
|
||||
"goat yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat yogurt",
|
||||
"plural_name": "goat yogurts"
|
||||
"name": "getyoghurt",
|
||||
"plural_name": "getyoghurter"
|
||||
},
|
||||
"dahi": {
|
||||
"aliases": [],
|
||||
|
@ -3011,8 +3011,8 @@
|
|||
"bulgarian yogurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "bulgarian yogurt",
|
||||
"plural_name": "bulgarian yogurts"
|
||||
"name": "bulgarisk yoghurt",
|
||||
"plural_name": "bulgariska yoghurter"
|
||||
},
|
||||
"tvorog": {
|
||||
"aliases": [],
|
||||
|
@ -3023,26 +3023,26 @@
|
|||
"chocolate milk powder": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chocolate milk powder",
|
||||
"plural_name": "chocolate milk powders"
|
||||
"name": "chokladmjölkpulver",
|
||||
"plural_name": "chokladmjölkpulver"
|
||||
},
|
||||
"liquid rennet": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "liquid rennet",
|
||||
"plural_name": "liquid rennets"
|
||||
"name": "flytande löpe",
|
||||
"plural_name": "flytande löpe"
|
||||
},
|
||||
"sheep’s milk yoghurt": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sheep’s milk yoghurt",
|
||||
"plural_name": "sheep’s milk yoghurts"
|
||||
"name": "fårmjölksyoghurt",
|
||||
"plural_name": "fårmjölksyoghurt"
|
||||
},
|
||||
"strawberry milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strawberry milk",
|
||||
"plural_name": "strawberry milks"
|
||||
"name": "jordgubbsmjölk",
|
||||
"plural_name": "jordgubbsmjölk"
|
||||
},
|
||||
"ayran": {
|
||||
"aliases": [],
|
||||
|
@ -3059,8 +3059,8 @@
|
|||
"yogurt drink": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "yogurt drink",
|
||||
"plural_name": "yogurt drinks"
|
||||
"name": "yoghurtdryck",
|
||||
"plural_name": "yoghurtdrycker"
|
||||
},
|
||||
"passion-fruit curd": {
|
||||
"aliases": [],
|
||||
|
@ -3071,20 +3071,20 @@
|
|||
"pickled egg": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pickled egg",
|
||||
"plural_name": "pickled eggs"
|
||||
"name": "inlagt ägg",
|
||||
"plural_name": "inlagda ägg"
|
||||
},
|
||||
"sheep milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sheep milk",
|
||||
"plural_name": "sheep milks"
|
||||
"plural_name": "fårmjölk"
|
||||
},
|
||||
"starter culture": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "starter culture",
|
||||
"plural_name": "starter cultures"
|
||||
"name": "startkultur",
|
||||
"plural_name": "startkulturer"
|
||||
},
|
||||
"kashk": {
|
||||
"aliases": [],
|
||||
|
@ -3096,13 +3096,13 @@
|
|||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "strutsägg",
|
||||
"plural_name": "ostrich eggs"
|
||||
"plural_name": "strutsägg"
|
||||
},
|
||||
"vanilla milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vanilla milk",
|
||||
"plural_name": "vanilla milks"
|
||||
"name": "vaniljmjölk",
|
||||
"plural_name": "vaniljmjölk"
|
||||
},
|
||||
"yoplait whip": {
|
||||
"aliases": [],
|
||||
|
@ -3113,14 +3113,14 @@
|
|||
"buffalo milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "buffalo milk",
|
||||
"plural_name": "buffalo milks"
|
||||
"name": "buffelmjölk",
|
||||
"plural_name": "buffelmjölk"
|
||||
},
|
||||
"goat kefir": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "goat kefir",
|
||||
"plural_name": "goat kefirs"
|
||||
"name": "getkefir",
|
||||
"plural_name": "getkefir"
|
||||
},
|
||||
"lebneh": {
|
||||
"aliases": [],
|
||||
|
@ -3165,26 +3165,26 @@
|
|||
"vegan butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan butter",
|
||||
"plural_name": "vegan butter"
|
||||
"name": "veganskt smör",
|
||||
"plural_name": "veganskt smör"
|
||||
},
|
||||
"non-dairy milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "non-dairy milk",
|
||||
"plural_name": "non-dairy milks"
|
||||
"name": "mjölkfri mjölk",
|
||||
"plural_name": "mjölkfri mjölk"
|
||||
},
|
||||
"soy milk": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sojamjölk",
|
||||
"plural_name": "soy milks"
|
||||
"plural_name": "sojamjölk"
|
||||
},
|
||||
"extra firm tofu": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "extra firm tofu",
|
||||
"plural_name": "extra firm tofus"
|
||||
"name": "extra fast tofu",
|
||||
"plural_name": "extra fast tofu"
|
||||
},
|
||||
"silken tofu": {
|
||||
"aliases": [],
|
||||
|
@ -3207,26 +3207,26 @@
|
|||
"egg replacer": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "egg replacer",
|
||||
"plural_name": "egg replacers"
|
||||
"name": "äggersättning",
|
||||
"plural_name": "äggersättare"
|
||||
},
|
||||
"vegan mayonnaise": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan mayonnaise",
|
||||
"plural_name": "vegan mayonnaises"
|
||||
"name": "vegansk majonnäs",
|
||||
"plural_name": "veganskt majonnäs"
|
||||
},
|
||||
"vegan cheese": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vegan cheese",
|
||||
"plural_name": "vegan cheeses"
|
||||
"name": "veganost",
|
||||
"plural_name": "veganska ostar"
|
||||
},
|
||||
"cashew butter": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cashew butter",
|
||||
"plural_name": "cashew butter"
|
||||
"name": "cashewsmör",
|
||||
"plural_name": "cashewsmör"
|
||||
},
|
||||
"tempeh": {
|
||||
"aliases": [],
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"name": "Gewürze"
|
||||
},
|
||||
{
|
||||
"name": "Konditorwaren"
|
||||
"name": "Süßwaren"
|
||||
},
|
||||
{
|
||||
"name": "Milchprodukte"
|
||||
|
@ -54,7 +54,7 @@
|
|||
"name": "Gewürze"
|
||||
},
|
||||
{
|
||||
"name": "Süßwaren"
|
||||
"name": "Süßigkeiten"
|
||||
},
|
||||
{
|
||||
"name": "Alkohol"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[
|
||||
{
|
||||
"name": "Свежие Овощи&фрукты"
|
||||
"name": "Свежие Овощи и фрукты"
|
||||
},
|
||||
{
|
||||
"name": "Крупы"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue