mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-01-06 05:18:32 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6fc98fc82 | ||
|
|
6f03010f6c | ||
|
|
69397c91b8 | ||
|
|
798792dcdc | ||
|
|
cc32dd9fa6 | ||
|
|
0c64eb29f9 | ||
|
|
8baa5cc315 | ||
|
|
6f3a5c6c8f | ||
|
|
778078590b | ||
|
|
53c82e5491 | ||
|
|
fef114d97f | ||
|
|
e80cbfad7f | ||
|
|
99527ce738 | ||
|
|
08ccced734 | ||
|
|
43c2c9552b | ||
|
|
db5741c7ee | ||
|
|
a1e394cf36 | ||
|
|
bdbef1ab9e | ||
|
|
e5276f6c20 | ||
|
|
20a6e71b31 | ||
|
|
24c111af7b | ||
|
|
ab4559319e | ||
|
|
2f8625ac44 | ||
|
|
dd146afa57 | ||
|
|
91d15f671e | ||
|
|
7008b13246 |
@@ -13,6 +13,7 @@ RUN echo "export PROMPT_COMMAND='history -a'" >> /home/vscode/.bashrc \
|
||||
&& chown vscode:vscode -R /home/vscode/
|
||||
|
||||
RUN npm install -g @go-task/cli
|
||||
RUN npm install -g json-schema-to-typescript
|
||||
|
||||
# Install additional OS packages
|
||||
RUN apt-get update \
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
"settings": {
|
||||
"python.defaultInterpreterPath": "/usr/local/bin/python",
|
||||
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
"mypy.runUsingActiveInterpreter": true
|
||||
},
|
||||
@@ -34,6 +33,7 @@
|
||||
"ms-python.pylint",
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"streetsidesoftware.code-spell-checker-cspell-bundled-dictionaries",
|
||||
"Vue.volar"
|
||||
]
|
||||
}
|
||||
@@ -41,6 +41,7 @@
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
3000,
|
||||
8000, // used by mkdocs
|
||||
9000,
|
||||
9091, // used by docker production
|
||||
24678 // used by nuxt when hot-reloading using polling
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,6 +20,7 @@ dev/data/backups/*
|
||||
dev/data/debug/*
|
||||
dev/data/img/*
|
||||
dev/data/migration/*
|
||||
dev/data/templates/*
|
||||
dev/data/users/*
|
||||
dev/data/groups/*
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ repos:
|
||||
exclude: ^tests/data/
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.14.8
|
||||
rev: v0.14.9
|
||||
hooks:
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
|
||||
@@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t
|
||||
We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do:
|
||||
|
||||
1. Take a backup just in case!
|
||||
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.7.0`
|
||||
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.8.0`
|
||||
3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access.
|
||||
4. Restart the container
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.7.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.8.0 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
|
||||
@@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.7.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.8.0 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -14,7 +14,7 @@
|
||||
<BaseButton
|
||||
download
|
||||
size="small"
|
||||
:download-url="`/api/recipes/bulk-actions/export/download?path=${item.path}`"
|
||||
:download-url="`/api/recipes/bulk-actions/export/${item.id}/download`"
|
||||
/>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:title="$t('recipe.edit-timeline-event')"
|
||||
:icon="$globals.icons.edit"
|
||||
can-submit
|
||||
disable-submit-on-enter
|
||||
:submit-text="$t('general.save')"
|
||||
@submit="submitEdit"
|
||||
>
|
||||
|
||||
@@ -149,6 +149,6 @@ export default defineNuxtComponent({
|
||||
|
||||
<style scoped>
|
||||
.v-toolbar {
|
||||
z-index: 1010 !important;
|
||||
z-index: 2010 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default defineNuxtComponent({
|
||||
"ul", "ol", "li", "dl", "dt", "dd", "abbr", "a", "img", "blockquote", "iframe",
|
||||
"del", "ins", "table", "thead", "tbody", "tfoot", "tr", "th", "td", "colgroup",
|
||||
],
|
||||
ADD_ATTR: [
|
||||
ALLOWED_ATTR: [
|
||||
"href", "src", "alt", "height", "width", "class", "allow", "title", "allowfullscreen", "frameborder",
|
||||
"scrolling", "cite", "datetime", "name", "abbr", "target", "border",
|
||||
],
|
||||
|
||||
58
frontend/composables/partials/use-actions-factory.test.ts
Normal file
58
frontend/composables/partials/use-actions-factory.test.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { ref } from "vue";
|
||||
import { useStoreActions } from "./use-actions-factory";
|
||||
import type { BaseCRUDAPI } from "~/lib/api/base/base-clients";
|
||||
|
||||
describe("useStoreActions", () => {
|
||||
const mockApi = {
|
||||
getAll: vi.fn(),
|
||||
createOne: vi.fn(),
|
||||
updateOne: vi.fn(),
|
||||
deleteOne: vi.fn(),
|
||||
} as unknown as BaseCRUDAPI<unknown, unknown, unknown>;
|
||||
|
||||
const mockStore = ref([]);
|
||||
const mockLoading = ref(false);
|
||||
|
||||
test("deleteMany calls deleteOne for each ID and refreshes once", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn().mockResolvedValue({ response: { data: {} } });
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
const ids = ["1", "2", "3"];
|
||||
await actions.deleteMany(ids);
|
||||
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledTimes(3);
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("1");
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("2");
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("3");
|
||||
|
||||
expect(mockApi.getAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("deleteMany handles empty array", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn();
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
await actions.deleteMany([]);
|
||||
|
||||
expect(mockApi.deleteOne).not.toHaveBeenCalled();
|
||||
expect(mockApi.getAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("deleteMany sets loading state", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn().mockResolvedValue({});
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
const promise = actions.deleteMany(["1"]);
|
||||
expect(mockLoading.value).toBe(true);
|
||||
|
||||
await promise;
|
||||
expect(mockLoading.value).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,7 @@ interface StoreActions<T extends BoundT> extends ReadOnlyStoreActions<T> {
|
||||
createOne(createData: T): Promise<T | null>;
|
||||
updateOne(updateData: T): Promise<T | null>;
|
||||
deleteOne(id: string | number): Promise<T | null>;
|
||||
deleteMany(ids: (string | number)[]): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,11 +166,23 @@ export function useStoreActions<T extends BoundT>(
|
||||
return response?.data || null;
|
||||
}
|
||||
|
||||
async function deleteMany(ids: (string | number)[]) {
|
||||
loading.value = true;
|
||||
for (const id of ids) {
|
||||
await api.deleteOne(id);
|
||||
}
|
||||
if (allRef?.value) {
|
||||
await refresh();
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
return {
|
||||
getAll,
|
||||
refresh,
|
||||
createOne,
|
||||
updateOne,
|
||||
deleteOne,
|
||||
deleteMany,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Türkçe (Turkish)",
|
||||
value: "tr-TR",
|
||||
progress: 36,
|
||||
progress: 39,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
name: "Svenska (Swedish)",
|
||||
value: "sv-SE",
|
||||
progress: 67,
|
||||
progress: 68,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
@@ -69,7 +69,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Português (Portuguese)",
|
||||
value: "pt-PT",
|
||||
progress: 40,
|
||||
progress: 39,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
@@ -81,7 +81,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Polski (Polish)",
|
||||
value: "pl-PL",
|
||||
progress: 53,
|
||||
progress: 52,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
@@ -147,7 +147,7 @@ export const LOCALES = [
|
||||
{
|
||||
name: "עברית (Hebrew)",
|
||||
value: "he-IL",
|
||||
progress: 73,
|
||||
progress: 72,
|
||||
dir: "rtl",
|
||||
},
|
||||
{
|
||||
@@ -201,13 +201,13 @@ export const LOCALES = [
|
||||
{
|
||||
name: "British English",
|
||||
value: "en-GB",
|
||||
progress: 44,
|
||||
progress: 43,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
name: "Ελληνικά (Greek)",
|
||||
value: "el-GR",
|
||||
progress: 41,
|
||||
progress: 42,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
@@ -231,13 +231,13 @@ export const LOCALES = [
|
||||
{
|
||||
name: "Català (Catalan)",
|
||||
value: "ca-ES",
|
||||
progress: 38,
|
||||
progress: 39,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
name: "Български (Bulgarian)",
|
||||
value: "bg-BG",
|
||||
progress: 49,
|
||||
progress: 51,
|
||||
dir: "ltr",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { RequestResponse } from "~/lib/api/types/non-generated";
|
||||
import type { ValidationResponse } from "~/lib/api/types/response";
|
||||
import { required, email, whitespace, url, minLength, maxLength } from "~/lib/validators";
|
||||
import { required, email, whitespace, url, urlOptional, minLength, maxLength } from "~/lib/validators";
|
||||
|
||||
export const validators = {
|
||||
required,
|
||||
email,
|
||||
whitespace,
|
||||
url,
|
||||
urlOptional,
|
||||
minLength,
|
||||
maxLength,
|
||||
};
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Laai 'n resep op",
|
||||
"upload-individual-zip-file": "Laai 'n .zip-lêer op wat vanaf 'n ander Mealie-instansie uitgevoer is.",
|
||||
"url-form-hint": "Kopieer en plak 'n skakel vanaf jou gunstelingresepwebwerf",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Bekyk opgespoorde data",
|
||||
"trim-whitespace-description": "Knip voorste en agterste witspasie sowel as leë reëls",
|
||||
"trim-prefix-description": "Knip die eerste karakter van elke reël af",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "تحميل وصفة",
|
||||
"upload-individual-zip-file": "تحميل مِلَفّ zip فردي تم تصديره من مثيل Malie آخر.",
|
||||
"url-form-hint": "نسخ ولصق رابط من موقعك المفضل للوصفة",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "عرض البيانات المحللة",
|
||||
"trim-whitespace-description": "قص المسافات البيضاء البادئة واللاحقة وكذلك الأسطر الفارغة",
|
||||
"trim-prefix-description": "قص الحرف الأول من كل سطر",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "هو مثل",
|
||||
"is-not-like": "ليس مثل"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Качи рецепта",
|
||||
"upload-individual-zip-file": "Качи като индивидуален .zip файлов формат от друга инстанция на Mealie.",
|
||||
"url-form-hint": "Копирай и постави линк от твоя любим сайт за рецепти",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Виж събраните данни",
|
||||
"trim-whitespace-description": "Премахни интервалите в началото и края на текста, също така и празните редове",
|
||||
"trim-prefix-description": "Премахни първия символ от всеки ред",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "е като",
|
||||
"is-not-like": "не е като"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Puja una recepta",
|
||||
"upload-individual-zip-file": "Puja només un arxiu zip, exportat d'altre Mealie.",
|
||||
"url-form-hint": "Copia i enganxa l'enllaç del teu lloc web de receptes preferit",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Visualitza les dades recuperades",
|
||||
"trim-whitespace-description": "Elimina els espais a principi i final; i elimina les línies buides",
|
||||
"trim-prefix-description": "Elimina el primer caràcter de cada línia",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "és com",
|
||||
"is-not-like": "no és com"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Nahrát recept",
|
||||
"upload-individual-zip-file": "Nahrát individuální .zip soubor exportovaný z jiné instance Mealie.",
|
||||
"url-form-hint": "Zkopírujte a vložte odkaz z vaší oblíbené stránky s recepty",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Zobrazit scrapovaná data",
|
||||
"trim-whitespace-description": "Oříznout počáteční a koncové mezery stejně jako prázdné řádky",
|
||||
"trim-prefix-description": "Oříznout první znak z každé řádky",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "je jako",
|
||||
"is-not-like": "není jako"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload en opskrift",
|
||||
"upload-individual-zip-file": "Upload en individuel .zip-fil, eksporteret fra en anden Mealie-instans.",
|
||||
"url-form-hint": "Kopiér og indsæt et link fra din foretrukne opskrifts hjemmeside",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Vis dataudtræk",
|
||||
"trim-whitespace-description": "Fjern indledende og efterfølgende mellemrum samt blanke linjer",
|
||||
"trim-prefix-description": "Beskær første tegn fra hver linje",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "er ligesom",
|
||||
"is-not-like": "er ikke som"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"category": "Kategorie"
|
||||
},
|
||||
"events": {
|
||||
"apprise-url": "Apprise-URL",
|
||||
"apprise-url": "Apprise URL",
|
||||
"database": "Datenbank",
|
||||
"delete-event": "Ereignis löschen",
|
||||
"event-delete-confirmation": "Bist du dir sicher, dass du dieses Ereignis löschen möchtest?",
|
||||
@@ -191,7 +191,7 @@
|
||||
"menu": "Menü",
|
||||
"a-name-is-required": "Ein Name wird benötigt",
|
||||
"delete-with-name": "{name} löschen",
|
||||
"confirm-delete-generic-with-name": "Bist du dir sicher, dass du dies löschen möchtest?",
|
||||
"confirm-delete-generic-with-name": "Bist du dir sicher, dass du {name} löschen möchtest?",
|
||||
"confirm-delete-own-admin-account": "Bitte beachte, dass du versuchst, dein eigenes Administrator-Konto zu löschen! Diese Aktion kann nicht rückgängig gemacht werden und wird dein Konto dauerhaft löschen?",
|
||||
"organizer": "Organisator",
|
||||
"transfer": "Übertragen",
|
||||
@@ -342,9 +342,9 @@
|
||||
"breakfast": "Frühstück",
|
||||
"lunch": "Mittagessen",
|
||||
"dinner": "Abendessen",
|
||||
"snack": "Snack",
|
||||
"drink": "Drink",
|
||||
"dessert": "Dessert",
|
||||
"snack": "Zwischenmahlzeit ",
|
||||
"drink": "Getränk",
|
||||
"dessert": "Nachspeise",
|
||||
"type-any": "Alle",
|
||||
"day-any": "Alle",
|
||||
"editor": "Bearbeiten",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Rezept hochladen",
|
||||
"upload-individual-zip-file": "Lade eine individuelle .zip-Datei hoch, die von einer anderen Mealie-Instanz exportiert wird.",
|
||||
"url-form-hint": "Kopiere einen Link von deiner Lieblingsrezept-Website und füge ihn ein",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Kopieren und fügen Sie die Quell-URL Ihrer Daten ein (optional)",
|
||||
"view-scraped-data": "Gesammelte Daten anzeigen",
|
||||
"trim-whitespace-description": "Leerzeichen am Anfang und Ende sowie leere Zeilen entfernen",
|
||||
"trim-prefix-description": "Erste Zeichen aus jeder Zeile entfernen",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Probiere den Massenimporter aus",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Hast du Roh-HTML oder JSON Daten?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Du kannst direkt von Rohdaten importieren",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Die Website wird blockiert?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Versuchen Sie stattdessen das reine HTML zu importieren.",
|
||||
"import-original-keywords-as-tags": "Importiere ursprüngliche Stichwörter als Schlagwörter",
|
||||
"stay-in-edit-mode": "Im Bearbeitungsmodus bleiben",
|
||||
"parse-recipe-ingredients-after-import": "Zutaten nach dem Import parsen",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "ist wie",
|
||||
"is-not-like": "ist nicht wie"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Dieses Feld ist erforderlich",
|
||||
"invalid-email": "E-Mail muss gültig sein",
|
||||
"invalid-url": "Muss eine gültige URL sein",
|
||||
"no-whitespace": "Kein Leerzeichen erlaubt",
|
||||
"min-length": "Muss mindestens {min} Zeichen haben",
|
||||
"max-length": "Darf mindestens {max} Zeichen haben"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Μόνο συνταγές με αυτές τις κατηγορίες θα χρησιμοποιηθούν στα προγράμματα γευμάτων",
|
||||
"planner": "Προγραμματισμός",
|
||||
"quick-week": "Γρήγορη προβολή",
|
||||
"side": "Πλευρά",
|
||||
"side": "Συνοδευτικό",
|
||||
"sides": "Πλευρές",
|
||||
"start-date": "Ημερομηνία έναρξης",
|
||||
"rule-day": "Ημέρα/ες Κανόνα",
|
||||
@@ -362,7 +362,7 @@
|
||||
"for-type-meal-types": "για γεύματα τύπου {0}",
|
||||
"meal-plan-rules": "Κανόνες Προγράμματος Γευμάτων",
|
||||
"new-rule": "Νέος κανόνας",
|
||||
"meal-plan-rules-description": "Μπορείτε να δημιουργήσετε κανόνες για την αυτόματη επιλογή συνταγών για τα προγράμματα γευμάτων. Αυτοί οι κανόνες χρησιμοποιούνται από το διακομιστή για τον προσδιορισμό της τυχαίας δεξαμενής συνταγών από τις οποίες μπορείτε να επιλέξετε κατά τη δημιουργία προγραμμάτων γευμάτων. Σημειώστε ότι αν οι κανόνες έχουν τους ίδιους περιορισμούς ημέρας/τύπου τότε τα φίλτρα κανόνων θα συγχωνευθούν. Στην πράξη, είναι περιττή η δημιουργία διπλότυπων κανόνων, είναι όμως εφικτή.",
|
||||
"meal-plan-rules-description": "Μπορείτε να δημιουργήσετε κανόνες για την αυτόματη επιλογή συνταγών για τα προγράμματα γευμάτων. Αυτοί οι κανόνες χρησιμοποιούνται από το διακομιστή για τον προσδιορισμό της δεξαμενής τυχαίας επιλογής συνταγής, κατά τη δημιουργία προγραμμάτων γευμάτων. Σημειώστε ότι αν οι κανόνες έχουν τους ίδιους περιορισμούς ημέρας/τύπου τότε τα φίλτρα κανόνων θα συγχωνευθούν. Στην πράξη, είναι περιττή η δημιουργία διπλότυπων κανόνων, είναι όμως εφικτή.",
|
||||
"new-rule-description": "Κατά τη δημιουργία ενός νέου κανόνα για ένα σχέδιο γεύματος, μπορείτε να περιορίσετε τον κανόνα ώστε να ισχύει για μια συγκεκριμένη ημέρα της εβδομάδας ή/και ένα συγκεκριμένο τύπο γεύματος. Για να εφαρμόσετε έναν κανόνα σε όλες τις ημέρες ή σε όλους τους τύπους γεύματος μπορείτε να ορίσετε τον κανόνα σε \"Ολα\" που θα τον εφαρμόσει σε όλες τις πιθανές τιμές για την ημέρα ή/και τον τύπο γεύματος.",
|
||||
"recipe-rules": "Κανόνες Συνταγής",
|
||||
"applies-to-all-days": "Εφαρμόζεται για όλες τις ημέρες",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Ανεβάστε μια συνταγή",
|
||||
"upload-individual-zip-file": "Ανεβάστε ένα μεμονωμένο αρχείο .zip που εξάγεται από μια άλλη περίπτωση Mealie.",
|
||||
"url-form-hint": "Αντιγράψτε και επικολλήστε έναν σύνδεσμο από την αγαπημένη σας ιστοσελίδα συνταγών",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Αντιγράψτε και επικολλήστε το πηγαίο URL των δεδομένων σας (προαιρετικό)",
|
||||
"view-scraped-data": "Προβολή Παραγόμενων Δεδομένων",
|
||||
"trim-whitespace-description": "Περικοπή κενών στην αρχή και το τέλος καθώς και των κενών γραμμών",
|
||||
"trim-prefix-description": "Περικοπή πρώτου χαρακτήρα από κάθε γραμμή",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Δοκιμάστε τον μαζικό εισαγωγέα συνταγών μας",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Εχουν ακατέργαστα δεδομένα HTML ή JSON;",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Μπορείτε να κάνετε εισαγωγή απευθείας από ακατέργαστα δεδομένα",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Η ιστοσελίδα μπλοκάρεται;",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Δοκιμάστε να εισάγετε τον ακατέργαστο κώδικα HTML.",
|
||||
"import-original-keywords-as-tags": "Εισαγωγή αρχικών λέξεων-κλειδιών ως ετικέτες",
|
||||
"stay-in-edit-mode": "Παραμονή σε λειτουργία επεξεργασίας",
|
||||
"parse-recipe-ingredients-after-import": "Ανάλυση συστατικών συνταγής μετά την εισαγωγή",
|
||||
@@ -878,9 +879,9 @@
|
||||
"secure-site": "Ασφαλής Ιστοσελίδα",
|
||||
"secure-site-error-text": "Παροχή μέσω localhost ή ασφάλεια με https. Το πρόχειρο και τα πρόσθετα API προγράμματος περιήγησης μπορεί να μην λειτουργούν.",
|
||||
"secure-site-success-text": "Ο ιστότοπος έχει πρόσβαση από localhost ή https",
|
||||
"server-side-base-url": "Βασική Διεύθυνση URL Πλευράς Διακομιστή",
|
||||
"server-side-base-url": "Βασική διεύθυνση URL πλευράς διακομιστή",
|
||||
"server-side-base-url-error-text": "Το `BASE_URL` εξακολουθεί να είναι η προεπιλεγμένη τιμή στο διακομιστή API. Αυτό θα προκαλέσει προβλήματα με τις συνδέσεις ειδοποιήσεων που δημιουργούνται στο διακομιστή για email, κλπ.",
|
||||
"server-side-base-url-success-text": "Το URL Πλευράς Διακομιστή δεν ταιριάζει με την προεπιλογή",
|
||||
"server-side-base-url-success-text": "Η διεύθυνση URL πλευράς διακομιστή δεν ταιριάζει με την προεπιλεγμένη",
|
||||
"ldap-ready": "Ετοιμο για LDAP",
|
||||
"ldap-ready-error-text": "Δεν έχουν ρυθμιστεί όλες οι τιμές LDAP. Αυτό μπορεί να αγνοηθεί αν δεν χρησιμοποιείτε έλεγχο ταυτότητας LDAP.",
|
||||
"ldap-ready-success-text": "Ολες οι απαιτούμενες μεταβλητές LDAP έχουν οριστεί.",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "είναι όμοιο με",
|
||||
"is-not-like": "δεν είναι όμοιο με"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Αυτό το πεδίο είναι υποχρεωτικό",
|
||||
"invalid-email": "Το e-mail πρέπει να είναι έγκυρο",
|
||||
"invalid-url": "Πρέπει να είναι μια έγκυρη διεύθυνση URL",
|
||||
"no-whitespace": "Δεν επιτρέπονται κενοί χαρακτήρες",
|
||||
"min-length": "Πρέπει να αποτελείται από τουλάχιστον {min} χαρακτήρες",
|
||||
"max-length": "Πρέπει να αποτελείται το πολύ από {max} χαρακτήρες"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload a Recipe",
|
||||
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
||||
"url-form-hint": "Copy and paste a link from your favourite recipe website",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "View Scraped Data",
|
||||
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload a Recipe",
|
||||
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
||||
"url-form-hint": "Copy and paste a link from your favorite recipe website",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "View Scraped Data",
|
||||
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Subir una receta",
|
||||
"upload-individual-zip-file": "Sube un archivo .zip individual exportado desde otra instancia de Mealie.",
|
||||
"url-form-hint": "Copia y pega un enlace desde tu página web favorita",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Ver información recuperada",
|
||||
"trim-whitespace-description": "Eliminar espacios en blanco iniciales y finales así como líneas en blanco",
|
||||
"trim-prefix-description": "Eliminar el primer carácter de cada línea",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "es como",
|
||||
"is-not-like": "no es como"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Retsepti üleslaadimne",
|
||||
"upload-individual-zip-file": "Lae üles üksik .zip fail, mis eksporditi teisest Mealie ekspemplarist.",
|
||||
"url-form-hint": "Kopeeri ja kleebi link oma lemmikust retsepti leheküljest",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Kuva omandatud andmed",
|
||||
"trim-whitespace-description": "Eemalda alguses ning lõpus olevad tühikud ning tühjad read",
|
||||
"trim-prefix-description": "Eemalda esimene tähemärk igast reast",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "on nagu",
|
||||
"is-not-like": "ei ole nagu"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Lataa resepti",
|
||||
"upload-individual-zip-file": "Tuo yksittäinen pakattu kansio toisesta Mealie instanssista.",
|
||||
"url-form-hint": "Liitä linkki lempireseptiverkkosivultasi",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Näytä hankittu data",
|
||||
"trim-whitespace-description": "Leikkaa alussa ja lopussa olevat välilyönnit sekä tyhjät rivit",
|
||||
"trim-prefix-description": "Poista joka rivin ensimmäinen merkki",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "on kuin",
|
||||
"is-not-like": "ei ole kuin"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +342,8 @@
|
||||
"breakfast": "Petit-déjeuner",
|
||||
"lunch": "Déjeuner",
|
||||
"dinner": "Souper",
|
||||
"snack": "Snack",
|
||||
"drink": "Drink",
|
||||
"snack": "Goûter",
|
||||
"drink": "Boissons",
|
||||
"dessert": "Dessert",
|
||||
"type-any": "Tous",
|
||||
"day-any": "Tous",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Télécharger une recette",
|
||||
"upload-individual-zip-file": "Chargez un fichier .zip exporté depuis une autre instance Mealie.",
|
||||
"url-form-hint": "Copiez et collez un lien depuis votre site de recettes favori",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copiez et collez l'URL source de vos données (facultatif)",
|
||||
"view-scraped-data": "Voir les données récupérées",
|
||||
"trim-whitespace-description": "Ajuster les espaces de début et de fin ainsi que les lignes vides",
|
||||
"trim-prefix-description": "Couper le premier caractère de chaque ligne",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Essayez l’importateur de masse",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Vous avez des données brutes en HTML ou JSON ?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Vous pouvez directement importer des données brutes",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Le site web est bloqué ?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Essayez plutôt d'importer le code HTML brut.",
|
||||
"import-original-keywords-as-tags": "Importer les mots-clés d'origine en tant que tags",
|
||||
"stay-in-edit-mode": "Rester en mode édition",
|
||||
"parse-recipe-ingredients-after-import": "Analyser les ingrédients de la recette après l'import",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "est comme",
|
||||
"is-not-like": "n'est pas similaire à"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Ce champ est obligatoire",
|
||||
"invalid-email": "L’e-mail doit être valide",
|
||||
"invalid-url": "Doit être une URL valide",
|
||||
"no-whitespace": "Aucun espace n'est autorisé",
|
||||
"min-length": "Doit contenir au moins {min} caractères",
|
||||
"max-length": "Doit contenir au maximum {max} caractères"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +342,8 @@
|
||||
"breakfast": "Petit déjeuner",
|
||||
"lunch": "Dîner",
|
||||
"dinner": "Souper",
|
||||
"snack": "Snack",
|
||||
"drink": "Drink",
|
||||
"snack": "Goûter",
|
||||
"drink": "Boissons",
|
||||
"dessert": "Dessert",
|
||||
"type-any": "Tous",
|
||||
"day-any": "Tous",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Télécharger une recette",
|
||||
"upload-individual-zip-file": "Téléverser un fichier .zip exporté depuis une autre instance Mealie.",
|
||||
"url-form-hint": "Copiez et collez un lien depuis votre site de recettes favori",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copiez et collez l'URL source de vos données (facultatif)",
|
||||
"view-scraped-data": "Voir les données récupérées",
|
||||
"trim-whitespace-description": "Ajuster les espaces de début et de fin ainsi que les lignes vides",
|
||||
"trim-prefix-description": "Couper le premier caractère de chaque ligne",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Essayez l’importateur de masse",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Vous avez des données brutes en HTML ou JSON ?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Vous pouvez directement importer des données brutes",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Le site web est bloqué ?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Essayez plutôt d'importer le code HTML brut.",
|
||||
"import-original-keywords-as-tags": "Importer les mots-clés d'origine en tant que tags",
|
||||
"stay-in-edit-mode": "Rester en mode édition",
|
||||
"parse-recipe-ingredients-after-import": "Analyser les ingrédients de la recette après l'import",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "est similaire à",
|
||||
"is-not-like": "n'est pas similaire à"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Ce champ est obligatoire",
|
||||
"invalid-email": "L’e-mail doit être valide",
|
||||
"invalid-url": "Doit être une URL valide",
|
||||
"no-whitespace": "Aucun espace n'est autorisé",
|
||||
"min-length": "Doit contenir au moins {min} caractères",
|
||||
"max-length": "Doit contenir au maximum {max} caractères"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Télécharger une recette",
|
||||
"upload-individual-zip-file": "Chargez un fichier .zip exporté depuis une autre instance Mealie.",
|
||||
"url-form-hint": "Copiez et collez un lien depuis votre site de recettes favori",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copiez et collez l'URL source de vos données (facultatif)",
|
||||
"view-scraped-data": "Voir les données récupérées",
|
||||
"trim-whitespace-description": "Ajuster les espaces de début et de fin ainsi que les lignes vides",
|
||||
"trim-prefix-description": "Couper le premier caractère de chaque ligne",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "est comme",
|
||||
"is-not-like": "n'est pas similaire à"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Ce champ est obligatoire",
|
||||
"invalid-email": "L’e-mail doit être valide",
|
||||
"invalid-url": "Doit être une URL valide",
|
||||
"no-whitespace": "Aucun espace n'est autorisé",
|
||||
"min-length": "Doit contenir au moins {min} caractères",
|
||||
"max-length": "Doit contenir au maximum {max} caractères"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Cargar unha Receita",
|
||||
"upload-individual-zip-file": "Cargar un ficheiro .zip individual, exportado de outra instancia do Mealie.",
|
||||
"url-form-hint": "Copie e pegue un link do seu site de receitas favorito",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Ver datos recollidos",
|
||||
"trim-whitespace-description": "Eliminar os espazos en branco no início e no fin, asi como as liñas en branco",
|
||||
"trim-prefix-description": "Eliminar o primeiro caracter de cada liña",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "é como",
|
||||
"is-not-like": "non é como"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "העלאת מתכון",
|
||||
"upload-individual-zip-file": "העלאת קובץ זיפ שיוצא ממילי אחר.",
|
||||
"url-form-hint": "העתק והדבק קישור מאתר המתכונים המועדף עליך",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "צפייה במידע שנאסף",
|
||||
"trim-whitespace-description": "הסר רווחים מתחילת / סוף שורה ושורות ריקות",
|
||||
"trim-prefix-description": "חתוך תו ראשון מכל שורה",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "דומה ל-",
|
||||
"is-not-like": "לא דומה לא-"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Učitaj Recept",
|
||||
"upload-individual-zip-file": "Prenesite pojedinačnu .zip datoteku koja je izvezena iz druge instance Mealie aplikacije.",
|
||||
"url-form-hint": "Kopirajte i zalijepite poveznicu s vaše omiljene web stranice za recepte",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Prikaz Prikupljenih Podataka",
|
||||
"trim-whitespace-description": "Ukloni vodeće i slijedeće praznine, kao i prazne linije",
|
||||
"trim-prefix-description": "Ukloni prvi znak sa svake linije",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Recept feltöltése",
|
||||
"upload-individual-zip-file": "Tölts fel egy .zíp archívumot, ami egy másik Mealie példányból lett exportálva.",
|
||||
"url-form-hint": "Másold be a linket a kedvenc recept weboldaladról",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Másolja és illessze be az adatok forrás URL-jét (opcionális)",
|
||||
"view-scraped-data": "Letöltött adat megtekintése",
|
||||
"trim-whitespace-description": "Vágja le a kezdő és a záró fehérjeleket, valamint az üres sorokat",
|
||||
"trim-prefix-description": "Minden sor első karakterének levágása",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "hasonló",
|
||||
"is-not-like": "nem hasonló"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Ez kötelező mező",
|
||||
"invalid-email": "E-mail-nek érvényesnek kell lennie",
|
||||
"invalid-url": "Érvényes URL-nek kell lennie",
|
||||
"no-whitespace": "Szóközt nem tartalmazhat",
|
||||
"min-length": "Legalább {min} karakter legyen",
|
||||
"max-length": "Legfeljebb {max} karakter legyen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +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": "Þar sem \"Apprise\" slóðir innihalda yfirleitt viðkvæmar upplýsingar, er þessum reit viljandi skilið eftir auðum við breytingar. Ef þú vilt uppfæra slóðina skaltu slá inn þá nýju hér, annars skaltu skilja reitinn eftir auðan til að halda núverandi slóð.",
|
||||
"apprise-url-is-left-intentionally-blank": "Þar sem \"Apprise\" slóðir innihalda yfirleitt viðkvæmar upplýsingar, er þessi reitur viljandi skilinn eftir auður. Ef þú vilt uppfæra slóðina skaltu slá inn hana inn hér, annars skaltu skilja reitinn eftir auðan til að halda núverandi slóð.",
|
||||
"enable-notifier": "Virkja tilkynningar",
|
||||
"what-events": "Hvaða viðburði ætti þessi tilkynnir að vera áskrifandi að?",
|
||||
"user-events": "Notenda viðburðir",
|
||||
@@ -342,9 +342,9 @@
|
||||
"breakfast": "Morgunverður",
|
||||
"lunch": "Hádegisverður",
|
||||
"dinner": "Kvöldverður",
|
||||
"snack": "Snack",
|
||||
"drink": "Drink",
|
||||
"dessert": "Dessert",
|
||||
"snack": "Snarl",
|
||||
"drink": "Drykkur",
|
||||
"dessert": "Eftirréttur",
|
||||
"type-any": "Allir",
|
||||
"day-any": "Alla",
|
||||
"editor": "Ritill",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Hlaða inn uppskrift",
|
||||
"upload-individual-zip-file": "Hlaða inn .zip skrá sem er flutt úr annarri Mealie uppsetningu.",
|
||||
"url-form-hint": "Afritaðu og límdu tengil frá uppáhalds uppskriftar síðunni þinni",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Skoða unnin gögn",
|
||||
"trim-whitespace-description": "Fjarlægja bil fremst og aftast í texta sem og auðum línum",
|
||||
"trim-prefix-description": "Eyða fyrsta staf úr hverri línu",
|
||||
@@ -619,8 +620,8 @@
|
||||
"create-recipe-description": "Stofna nýja uppskrift frá grunni.",
|
||||
"create-recipes": "Stofna uppskriftir",
|
||||
"import-with-zip": "Hlaða inn með .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.",
|
||||
"create-recipe-from-an-image": "Stofna uppskrift út frá mynd",
|
||||
"create-recipe-from-an-image-description": "Stofna uppskrift með því hlaða inn myndum af uppskriftartextanum. Mealie mun reyna að vinna texta úr myndunum með gervigreind og stofna nýja uppskrift út frá textanum.",
|
||||
"crop-and-rotate-the-image": "Sníða og snúa mynd svo bara textinn sé sýnilegur og að myndin snúi rétt.",
|
||||
"create-from-images": "Stofna uppskrift frá mynd",
|
||||
"should-translate-description": "Þýða uppskrift á mitt tungumál",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Prófaðu að setja inn margar uppskriftir í einu",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "Ertu með hrá HTML eða JSON gögn?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Það er hægt að hlaða inn hráum gögnum beint",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Er vefsíðan lokuð?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Reyndu að flytja inn HTML kóðann í staðinn.",
|
||||
"import-original-keywords-as-tags": "Nota upprunanleg merki",
|
||||
"stay-in-edit-mode": "Vera í breytingarham",
|
||||
"parse-recipe-ingredients-after-import": "Greina innhald uppskriftar eftir að búið er að hlaða inn uppskrift",
|
||||
@@ -660,7 +661,7 @@
|
||||
"recipe-debugger": "Yfirfara uppskrift",
|
||||
"recipe-debugger-description": "Náðu í slóðina af uppskriftinni sem þú villt yfirfara og límdu hana hér. Síðan með uppskriftinni verður greind með greiningarverkfærinu og þú munnt sjá niðurstöðuna. Ef þú sérð að engin gögn skila sér þá er slóðin sem þú ert að greina ekki studd af Mealie eða greiningarverkfærinu.",
|
||||
"use-openai": "Nota OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Nota OpenAI til að greina í staðinn fyrir að treysta á greiningar verkfærið. Þegar er fengin af slóð þá gerist þetta sjálfkrafa ef almenn greining mistekst, en þú getur prófað það hér.",
|
||||
"recipe-debugger-use-openai-description": "Nota OpenAI til að greina í staðinn fyrir að treysta á greiningar verkfærið. Ef greiningar verkfærinu mistekst að greina uppskrift af vefslóð þá gerist það sjálfvirkt að OpenAI greinir uppskriftina en þú getur prófað þetta sjálfur hér.",
|
||||
"debug": "Villuleit",
|
||||
"tree-view": "Tré sýn",
|
||||
"recipe-servings": "Fjöldi skammta",
|
||||
@@ -1338,7 +1339,7 @@
|
||||
"household-delete-note": "Heimili með notendum er ekki hægt að eyða"
|
||||
},
|
||||
"profile": {
|
||||
"welcome-user": "👋 Velkomin/Velkominn/Velkomið, {0}!",
|
||||
"welcome-user": "👋 Halló, {0}",
|
||||
"description": "Umsjá með prófíl, uppskriftum og hópstillingum.",
|
||||
"invite-link": "Boð tengill",
|
||||
"get-invite-link": "Fá boð tengil",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Þessi reitur er nauðsynlegur",
|
||||
"invalid-email": "Verður að vera gilt netfang",
|
||||
"invalid-url": "Verður að vera gild vefslóð",
|
||||
"no-whitespace": "Engin bil leyfð",
|
||||
"min-length": "Verður að vera að lágmarki {min} stafir",
|
||||
"max-length": "Má vera að hámarki {max} stafir"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Carica una Ricetta",
|
||||
"upload-individual-zip-file": "Carica un singolo file .zip esportato da un'altra istanza di Mealie.",
|
||||
"url-form-hint": "Copia e incolla un link dal tuo sito di ricette preferito",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Visualizza Dati Ottenuti dallo Scraping",
|
||||
"trim-whitespace-description": "Tagliare lo spazio bianco iniziale e finale così come le linee vuote",
|
||||
"trim-prefix-description": "Taglia il primo carattere da ogni riga",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "è simile",
|
||||
"is-not-like": "non è come"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "レシピのアップロード",
|
||||
"upload-individual-zip-file": "別のMealieインスタンスからエクスポートされた個別の.zipファイルをアップロードします。",
|
||||
"url-form-hint": "お気に入りのレシピサイトからリンクをコピーして貼り付け",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "スクライピングされたデータの表示",
|
||||
"trim-whitespace-description": "先頭と末尾の空白、空白行をトリミングします。",
|
||||
"trim-prefix-description": "各行の最初の文字をトリミングする",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "次のようなものです",
|
||||
"is-not-like": "というわけではありません"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "레시피 업로드",
|
||||
"upload-individual-zip-file": "다른 Mealie 인스턴스에서 내보낸 개별 .zip 파일을 업로드합니다.",
|
||||
"url-form-hint": "좋아하는 레시피 웹사이트에서 링크를 복사하여 붙여넣으세요",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "스크랩된 데이터 보기",
|
||||
"trim-whitespace-description": "앞뒤 공백과 빈 줄을 잘라냅니다.",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Įkelti receptą",
|
||||
"upload-individual-zip-file": "Įkelkite .zip failą, eksportuotą iš kitos \"Mealie\" sistemos.",
|
||||
"url-form-hint": "Nukopijuokite ir įklijuokite nuorodą iš mėgstamų receptų svetainės",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Peržiūrėti nuskaitytus duomenis",
|
||||
"trim-whitespace-description": "Pašalinti tarpus bei tuščias eilutes pradžioje ir pabaigoje",
|
||||
"trim-prefix-description": "Pašalinti kiekvienos eilutės pirmąjį ženklą",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Augšupielādējiet recepti",
|
||||
"upload-individual-zip-file": "Augšupielādējiet atsevišķu.zip failu, kas eksportēts no citas Mealie instances.",
|
||||
"url-form-hint": "Kopējiet un ielīmējiet saiti no savas iecienītākās receptes vietnes",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Skatīt nokasītos datus",
|
||||
"trim-whitespace-description": "Apgrieziet priekšējo un aizmugurējo atstarpi, kā arī tukšas rindas",
|
||||
"trim-prefix-description": "Izgrieziet pirmo rakstzīmi no katras rindas",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "ir kā",
|
||||
"is-not-like": "nav tāds, kā"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload een recept",
|
||||
"upload-individual-zip-file": "Upload een .zip-bestand dat uit een andere Mealie-instantie is geëxporteerd.",
|
||||
"url-form-hint": "Kopieer en plak een link vanuit jouw favoriete receptenwebsite",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Kopieer en plak de bron URL van uw gegevens (optioneel)",
|
||||
"view-scraped-data": "Bekijk opgehaalde data",
|
||||
"trim-whitespace-description": "Haal witruimtes en witregels aan het begin en einde weg",
|
||||
"trim-prefix-description": "Verwijder het eerste teken van elke regel",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is zoals",
|
||||
"is-not-like": "is niet zoals"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "Dit is een verplicht veld",
|
||||
"invalid-email": "E-mailadres moet geldig zijn",
|
||||
"invalid-url": "Moet een geldige URL zijn",
|
||||
"no-whitespace": "Geen spaties toegestaan",
|
||||
"min-length": "Moet minimaal {min} tekens bevatten",
|
||||
"max-length": "Zorg dat je {max} tekens gebruikt"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@
|
||||
"breakfast": "Frokost",
|
||||
"lunch": "Lunsj",
|
||||
"dinner": "Middag",
|
||||
"snack": "Snack",
|
||||
"snack": "Snacks",
|
||||
"drink": "Drink",
|
||||
"dessert": "Dessert",
|
||||
"type-any": "Enhver",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Last opp oppskrift",
|
||||
"upload-individual-zip-file": "Last opp en individuell .zip-fil eksportert fra en annen Mealie-instans.",
|
||||
"url-form-hint": "Kopier og lim inn en lenke fra nettstedet med favorittoppskriftene dine",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Vis skrapte data",
|
||||
"trim-whitespace-description": "Fjern innledende og etterfølgende mellomrom i tillegg til tomme linjer",
|
||||
"trim-prefix-description": "Fjern første tegn fra hver linje",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "er som",
|
||||
"is-not-like": "er ikke som"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Wrzuć przepis",
|
||||
"upload-individual-zip-file": "Prześlij pojedynczy plik .zip wyeksportowany z innej instancji Mealie.",
|
||||
"url-form-hint": "Skopiuj i wklej link ze swojej ulubionej strony z przepisami",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Wyświetl zebrane dane",
|
||||
"trim-whitespace-description": "Przytnij pustą przestrzeń przed i po zawartości oraz puste linie",
|
||||
"trim-prefix-description": "Przytnij pierwszy znak z każdej linii",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "jest jak",
|
||||
"is-not-like": "nie jest jak"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"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",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Visualizar Dados Rastreados",
|
||||
"trim-whitespace-description": "Aparar o espaço em branco e à direita, bem como linhas em branco",
|
||||
"trim-prefix-description": "Aparar primeiro caractere de cada linha",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "é como",
|
||||
"is-not-like": "não é como"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Enviar uma Receita",
|
||||
"upload-individual-zip-file": "Carregar um ficheiro .zip individual, exportado de outra instância do Mealie.",
|
||||
"url-form-hint": "Copie e cole um link do seu site de receitas favorito",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Ver dados recolhidos",
|
||||
"trim-whitespace-description": "Eliminar os espaços em branco no início e no fim, bem como as linhas em branco",
|
||||
"trim-prefix-description": "Apagar o primeiro caractere de cada linha",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "é como",
|
||||
"is-not-like": "não é como"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Încarcă o rețetă",
|
||||
"upload-individual-zip-file": "Încărcaţi un fişier individual .zip exportat dintr-o altă instanţă de Mealie.",
|
||||
"url-form-hint": "Copiază și lipește un link de pe site-ul tău web preferat de rețete",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Vezi datele colectate",
|
||||
"trim-whitespace-description": "Elimină spațiile albe de la început și sfârșit precum și liniile goale",
|
||||
"trim-prefix-description": "Elimină primul caracter din fiecare linie",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "este similar",
|
||||
"is-not-like": "nu este similar"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
"log-lines": "Строки журнала",
|
||||
"not-demo": "Не демо",
|
||||
"portfolio": "Портфолио",
|
||||
"production": "Production",
|
||||
"production": "Продуктивная среда",
|
||||
"support": "Поддержка",
|
||||
"version": "Версия",
|
||||
"unknown-version": "неизвестно",
|
||||
"unknown-version": "Неизвестная версия",
|
||||
"sponsor": "Спонсор"
|
||||
},
|
||||
"asset": {
|
||||
@@ -342,9 +342,9 @@
|
||||
"breakfast": "Завтрак",
|
||||
"lunch": "Обед",
|
||||
"dinner": "Ужин",
|
||||
"snack": "Snack",
|
||||
"drink": "Drink",
|
||||
"dessert": "Dessert",
|
||||
"snack": "Закуска",
|
||||
"drink": "Напиток",
|
||||
"dessert": "Десерт",
|
||||
"type-any": "Любой",
|
||||
"day-any": "Любой",
|
||||
"editor": "Редактор",
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Загрузить рецепт",
|
||||
"upload-individual-zip-file": "Загрузить отдельный .zip файл, экспортированный из другой Mealie.",
|
||||
"url-form-hint": "Скопируйте и вставьте ссылку из вашего любимого сайта рецептов",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Просмотр отсканированных данных",
|
||||
"trim-whitespace-description": "Обрезать ведущие и конечные пробелы, а также пустые строки",
|
||||
"trim-prefix-description": "Обрезать первый символ из каждой строки",
|
||||
@@ -636,8 +637,8 @@
|
||||
"scrape-recipe-suggest-bulk-importer": "Воспользуйтесь массовым импортом",
|
||||
"scrape-recipe-have-raw-html-or-json-data": "У Вас есть данные HTML или JSON?",
|
||||
"scrape-recipe-you-can-import-from-raw-data-directly": "Вы можете импортировать напрямую из необработанных данных",
|
||||
"scrape-recipe-website-being-blocked": "Website being blocked?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.",
|
||||
"scrape-recipe-website-being-blocked": "Сайт заблокирован?",
|
||||
"scrape-recipe-try-importing-raw-html-instead": "Попробуйте импортировать необработанный HTML файл.",
|
||||
"import-original-keywords-as-tags": "Импортировать исходные ключевые слова как теги",
|
||||
"stay-in-edit-mode": "Остаться в режиме редактирования",
|
||||
"parse-recipe-ingredients-after-import": "Распознавание ингредиентов рецепта после импорта",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "содержит",
|
||||
"is-not-like": "не содержит"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Nahrať recept",
|
||||
"upload-individual-zip-file": "Nahrať súbor .zip exportovaný z inej Mealie inštalácie.",
|
||||
"url-form-hint": "Okopírujte a zložte odkaz z vašej obľúbenej webstránky",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Náhľad získaných údajov",
|
||||
"trim-whitespace-description": "Vymazať medzery a prázdne riadky na začiatku a na konci",
|
||||
"trim-prefix-description": "Vymazať prvé písmeno z každého riadku",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "je ako",
|
||||
"is-not-like": "nie je ako"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Naloži recept",
|
||||
"upload-individual-zip-file": "Naloži posamezno .zip datoteko, izvoženo iz druge Mealie namestitve.",
|
||||
"url-form-hint": "Kopiraj in prilepi povezavo iz vaše priljubljene strani z recepti",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Kopirajte in prilepite izvorni URL svojih podatkov (neobvezno)",
|
||||
"view-scraped-data": "Poglej postrgane podatke",
|
||||
"trim-whitespace-description": "Poreži začetne in končne presledke, kot tudi prazne vrstice",
|
||||
"trim-prefix-description": "Poreži prvi znak v vsaki vrstici",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "je kot",
|
||||
"is-not-like": "ni kot"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "To polje je obvezno",
|
||||
"invalid-email": "E-pošta mora biti veljavna",
|
||||
"invalid-url": "URL mora biti veljaven",
|
||||
"no-whitespace": "Presledki niso dovoljeni",
|
||||
"min-length": "Mora vsebovati vsaj {min} znakov",
|
||||
"max-length": "Lahko je največ {max} znakov"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload a Recipe",
|
||||
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
||||
"url-form-hint": "Копирајте и налепите везу са вашег омиљеног сајта за рецепте",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "View Scraped Data",
|
||||
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Ladda upp ett recept",
|
||||
"upload-individual-zip-file": "Ladda upp en individuell .zip-fil som exporteras från en annan Mealie-instans.",
|
||||
"url-form-hint": "Kopiera och klistra in en länk från din favorit recept webbplats",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Visa skrapade data",
|
||||
"trim-whitespace-description": "Ta bort inledande och avslutande blanksteg samt tomma rader",
|
||||
"trim-prefix-description": "Ta bort första tecknet från varje rad",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "är som",
|
||||
"is-not-like": "är inte som"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Tarif Yükle",
|
||||
"upload-individual-zip-file": "Başka bir Mealie örneğinden dışa aktarılan ayrı bir .zip dosyası yükleyin.",
|
||||
"url-form-hint": "Favori tarif sitenizden bir bağlantıyı kopyalayıp yapıştırın",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Kazınmış Verileri Görüntüle",
|
||||
"trim-whitespace-description": "Baştaki ve sondaki boşlukların yanı sıra boş satırları da kırpın",
|
||||
"trim-prefix-description": "Her satırın ilk karakterini kırpın",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Завантажити рецепт",
|
||||
"upload-individual-zip-file": "Завантажити окремий .zip файл, експортований з іншого Mealie.",
|
||||
"url-form-hint": "Скопіюйте та вставте посилання з вашого улюбленого кулінарного веб-сайту",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "Переглянути зібрані дані",
|
||||
"trim-whitespace-description": "Обрізати початкові та кінцеву пробілів і порожні лінії",
|
||||
"trim-prefix-description": "Обрізати перший символ з кожного рядка",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "схожий",
|
||||
"is-not-like": "не схожий"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "Upload a Recipe",
|
||||
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
|
||||
"url-form-hint": "Copy and paste a link from your favorite recipe website",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "View Scraped Data",
|
||||
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "上传食谱",
|
||||
"upload-individual-zip-file": "上传从Mealie导出的.zip文件。",
|
||||
"url-form-hint": "从您最喜爱的食谱网站复制并粘贴链接",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "查看爬取的数据",
|
||||
"trim-whitespace-description": "删除开头和结尾的空格和空行",
|
||||
"trim-prefix-description": "删除每行的首个字符",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "匹配",
|
||||
"is-not-like": "不匹配"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"upload-a-recipe": "上傳食譜",
|
||||
"upload-individual-zip-file": "上傳從另一個Mealie匯出的zip壓縮檔",
|
||||
"url-form-hint": "複製您最喜歡的食譜網站的網址並在此貼上",
|
||||
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)",
|
||||
"view-scraped-data": "查看網頁擷取資料",
|
||||
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
|
||||
"trim-prefix-description": "Trim first character from each line",
|
||||
@@ -1427,5 +1428,13 @@
|
||||
"is-like": "is like",
|
||||
"is-not-like": "is not like"
|
||||
}
|
||||
},
|
||||
"validators": {
|
||||
"required": "This Field is Required",
|
||||
"invalid-email": "Email Must Be Valid",
|
||||
"invalid-url": "Must Be A Valid URL",
|
||||
"no-whitespace": "No Whitespace Allowed",
|
||||
"min-length": "Must Be At Least {min} Characters",
|
||||
"max-length": "Must Be At Most {max} Characters"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,80 +110,6 @@ export interface CreateBackup {
|
||||
options: BackupOptions;
|
||||
templates?: string[] | null;
|
||||
}
|
||||
export interface CustomPageBase {
|
||||
name: string;
|
||||
slug: string | null;
|
||||
position: number;
|
||||
categories?: RecipeCategoryResponse[];
|
||||
}
|
||||
export interface RecipeCategoryResponse {
|
||||
name: string;
|
||||
id: string;
|
||||
groupId?: string | null;
|
||||
slug: string;
|
||||
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;
|
||||
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[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface CustomPageImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string | null;
|
||||
}
|
||||
export interface CustomPageOut {
|
||||
name: string;
|
||||
slug: string | null;
|
||||
position: number;
|
||||
categories?: RecipeCategoryResponse[];
|
||||
id: number;
|
||||
}
|
||||
export interface DebugResponse {
|
||||
success: boolean;
|
||||
response?: string | null;
|
||||
@@ -248,11 +174,6 @@ export interface Migrations {
|
||||
type: string;
|
||||
files?: MigrationFile[];
|
||||
}
|
||||
export interface NotificationImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
exception?: string | null;
|
||||
}
|
||||
export interface RecipeImport {
|
||||
name: string;
|
||||
status: boolean;
|
||||
|
||||
@@ -44,7 +44,6 @@ export interface QueryFilterJSONPart {
|
||||
attributeName?: string | null;
|
||||
relationalOperator?: RelationalKeyword | RelationalOperator | null;
|
||||
value?: string | string[] | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface SaveCookBook {
|
||||
name: string;
|
||||
|
||||
@@ -334,7 +334,6 @@ export interface IngredientUnit {
|
||||
}
|
||||
export interface IngredientUnitAlias {
|
||||
name: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface CreateIngredientUnit {
|
||||
id?: string | null;
|
||||
@@ -349,11 +348,9 @@ export interface CreateIngredientUnit {
|
||||
pluralAbbreviation?: string | null;
|
||||
useAbbreviation?: boolean;
|
||||
aliases?: CreateIngredientUnitAlias[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface CreateIngredientUnitAlias {
|
||||
name: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface IngredientFood {
|
||||
id: string;
|
||||
@@ -372,7 +369,6 @@ export interface IngredientFood {
|
||||
}
|
||||
export interface IngredientFoodAlias {
|
||||
name: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface MultiPurposeLabelSummary {
|
||||
name: string;
|
||||
@@ -391,11 +387,9 @@ export interface CreateIngredientFood {
|
||||
labelId?: string | null;
|
||||
aliases?: CreateIngredientFoodAlias[];
|
||||
householdsWithIngredientFood?: string[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface CreateIngredientFoodAlias {
|
||||
name: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface Recipe {
|
||||
id?: string | null;
|
||||
@@ -433,21 +427,18 @@ export interface Recipe {
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
comments?: RecipeCommentOut[] | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
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;
|
||||
@@ -455,7 +446,6 @@ export interface RecipeTool {
|
||||
name: string;
|
||||
slug: string;
|
||||
householdsWithTool?: string[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeStep {
|
||||
id?: string | null;
|
||||
@@ -463,11 +453,9 @@ export interface RecipeStep {
|
||||
summary?: string | null;
|
||||
text: string;
|
||||
ingredientReferences?: IngredientReferences[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface IngredientReferences {
|
||||
referenceId?: string | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface Nutrition {
|
||||
calories?: string | null;
|
||||
@@ -481,7 +469,6 @@ export interface Nutrition {
|
||||
sugarContent?: string | null;
|
||||
transFatContent?: string | null;
|
||||
unsaturatedFatContent?: string | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeSettings {
|
||||
public?: boolean;
|
||||
@@ -490,18 +477,15 @@ export interface RecipeSettings {
|
||||
landscapeView?: boolean;
|
||||
disableComments?: boolean;
|
||||
locked?: boolean;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeAsset {
|
||||
name: string;
|
||||
icon: string;
|
||||
fileName?: string | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeNote {
|
||||
title: string;
|
||||
text: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecipeCommentOut {
|
||||
recipeId: string;
|
||||
@@ -511,14 +495,12 @@ export interface RecipeCommentOut {
|
||||
updatedAt: string;
|
||||
userId: string;
|
||||
user: UserBase;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface UserBase {
|
||||
id: string;
|
||||
username?: string | null;
|
||||
admin: boolean;
|
||||
fullName?: string | null;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface ShoppingListAddRecipeParamsBulk {
|
||||
recipeIncrementQuantity?: number;
|
||||
|
||||
@@ -510,6 +510,7 @@ export interface ScrapeRecipeBase {
|
||||
export interface ScrapeRecipeData {
|
||||
includeTags?: boolean;
|
||||
data: string;
|
||||
url?: string | null;
|
||||
}
|
||||
export interface ScrapeRecipeTest {
|
||||
url: string;
|
||||
|
||||
@@ -146,8 +146,8 @@ export class RecipeAPI extends BaseCRUDAPI<CreateRecipe, Recipe, Recipe> {
|
||||
return await this.requests.post<Recipe | null>(routes.recipesTestScrapeUrl, { url, useOpenAI });
|
||||
}
|
||||
|
||||
async createOneByHtmlOrJson(data: string, includeTags: boolean) {
|
||||
return await this.requests.post<string>(routes.recipesCreateFromHtmlOrJson, { data, includeTags });
|
||||
async createOneByHtmlOrJson(data: string, includeTags: boolean, url: string | null = null) {
|
||||
return await this.requests.post<string>(routes.recipesCreateFromHtmlOrJson, { data, includeTags, url });
|
||||
}
|
||||
|
||||
async createOneByUrl(url: string, includeTags: boolean) {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { scorePassword } from "./password";
|
||||
export { required, email, whitespace, url, minLength, maxLength } from "./inputs";
|
||||
export { required, email, whitespace, url, urlOptional, minLength, maxLength } from "./inputs";
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { expect, test, vi } from "vitest";
|
||||
import enUS from "~/lang/messages/en-US.json";
|
||||
|
||||
import { required, email, whitespace, url, minLength, maxLength } from "./inputs";
|
||||
|
||||
vi.mock("~/composables/use-global-i18n", () => {
|
||||
const interpolate = (msg: string, params?: Record<string, unknown>) => {
|
||||
if (!params) return msg;
|
||||
return msg
|
||||
.replace("{min}", String(params.min ?? ""))
|
||||
.replace("{max}", String(params.max ?? ""));
|
||||
};
|
||||
|
||||
const t = (key: string, params?: Record<string, unknown>) => {
|
||||
const parts = key.split(".");
|
||||
let acc: any = enUS as any;
|
||||
for (const p of parts) acc = acc?.[p];
|
||||
const msg: string | undefined = acc;
|
||||
return interpolate(msg ?? key, params);
|
||||
};
|
||||
|
||||
return { useGlobalI18n: () => ({ t }) };
|
||||
});
|
||||
|
||||
export { scorePassword } from "./password";
|
||||
|
||||
// Tests
|
||||
|
||||
test("validator required", () => {
|
||||
const falsey = "This Field is Required";
|
||||
const falsey = enUS.validators.required;
|
||||
expect(required("123")).toBe(true);
|
||||
expect(required("")).toBe(falsey);
|
||||
expect(required(undefined)).toBe(falsey);
|
||||
@@ -14,7 +37,7 @@ test("validator required", () => {
|
||||
const nulls = [undefined, null];
|
||||
|
||||
test("validator email", () => {
|
||||
const falsey = "Email Must Be Valid";
|
||||
const falsey = enUS.validators["invalid-email"];
|
||||
expect(email("123")).toBe(falsey);
|
||||
expect(email("email@example.com")).toBe(true);
|
||||
|
||||
@@ -24,7 +47,7 @@ test("validator email", () => {
|
||||
});
|
||||
|
||||
test("whitespace", () => {
|
||||
const falsey = "No Whitespace Allowed";
|
||||
const falsey = enUS.validators["no-whitespace"];
|
||||
expect(whitespace("123")).toBe(true);
|
||||
expect(whitespace(" ")).toBe(falsey);
|
||||
expect(whitespace("123 123")).toBe(falsey);
|
||||
@@ -35,7 +58,7 @@ test("whitespace", () => {
|
||||
});
|
||||
|
||||
test("url", () => {
|
||||
const falsey = "Must Be A Valid URL";
|
||||
const falsey = enUS.validators["invalid-url"];
|
||||
expect(url("https://example.com")).toBe(true);
|
||||
expect(url("")).toBe(falsey);
|
||||
|
||||
@@ -46,7 +69,7 @@ test("url", () => {
|
||||
|
||||
test("minLength", () => {
|
||||
const min = 3;
|
||||
const falsey = `Must Be At Least ${min} Characters`;
|
||||
const falsey = enUS.validators["min-length"].replace("{min}", String(min));
|
||||
const fn = minLength(min);
|
||||
expect(fn("123")).toBe(true);
|
||||
expect(fn("12")).toBe(falsey);
|
||||
@@ -59,7 +82,7 @@ test("minLength", () => {
|
||||
|
||||
test("maxLength", () => {
|
||||
const max = 3;
|
||||
const falsey = `Must Be At Most ${max} Characters`;
|
||||
const falsey = enUS.validators["max-length"].replace("{max}", String(max));
|
||||
const fn = maxLength(max);
|
||||
expect(fn("123")).toBe(true);
|
||||
expect(fn("1234")).toBe(falsey);
|
||||
|
||||
@@ -1,28 +1,40 @@
|
||||
import { useGlobalI18n } from "~/composables/use-global-i18n";
|
||||
|
||||
const EMAIL_REGEX
|
||||
= /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
|
||||
const URL_REGEX = /[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||
const URL_REGEX = /[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||
|
||||
export function required(v: string | undefined | null) {
|
||||
return !!v || "This Field is Required";
|
||||
const i18n = useGlobalI18n();
|
||||
return !!v || i18n.t("validators.required");
|
||||
}
|
||||
|
||||
export function email(v: string | undefined | null) {
|
||||
return (!!v && EMAIL_REGEX.test(v)) || "Email Must Be Valid";
|
||||
const i18n = useGlobalI18n();
|
||||
return (!!v && EMAIL_REGEX.test(v)) || i18n.t("validators.invalid-email");
|
||||
}
|
||||
|
||||
export function whitespace(v: string | null | undefined) {
|
||||
return (!!v && v.split(" ").length <= 1) || "No Whitespace Allowed";
|
||||
const i18n = useGlobalI18n();
|
||||
return (!!v && v.split(" ").length <= 1) || i18n.t("validators.no-whitespace");
|
||||
}
|
||||
|
||||
export function url(v: string | undefined | null) {
|
||||
return (!!v && URL_REGEX.test(v)) || "Must Be A Valid URL";
|
||||
const i18n = useGlobalI18n();
|
||||
return (!!v && URL_REGEX.test(v)) || i18n.t("validators.invalid-url");
|
||||
}
|
||||
|
||||
export function urlOptional(v: string | undefined | null) {
|
||||
return v ? url(v) : true;
|
||||
}
|
||||
|
||||
export function minLength(min: number) {
|
||||
return (v: string | undefined | null) => (!!v && v.length >= min) || `Must Be At Least ${min} Characters`;
|
||||
const i18n = useGlobalI18n();
|
||||
return (v: string | undefined | null) => (!!v && v.length >= min) || i18n.t("validators.min-length", { min });
|
||||
}
|
||||
|
||||
export function maxLength(max: number) {
|
||||
return (v: string | undefined | null) => !v || v.length <= max || `Must Be At Most ${max} Characters`;
|
||||
const i18n = useGlobalI18n();
|
||||
return (v: string | undefined | null) => !v || v.length <= max || i18n.t("validators.max-length", { max });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mealie",
|
||||
"version": "3.7.0",
|
||||
"version": "3.8.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt dev",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-form
|
||||
ref="domUrlForm"
|
||||
@submit.prevent="createFromHtmlOrJson(newRecipeData, importKeywordsAsTags)"
|
||||
@submit.prevent="createFromHtmlOrJson(newRecipeData, importKeywordsAsTags, newRecipeUrl)"
|
||||
>
|
||||
<div>
|
||||
<v-card-title class="headline">
|
||||
@@ -21,14 +21,28 @@
|
||||
<v-switch
|
||||
v-model="isEditJSON"
|
||||
:label="$t('recipe.json-editor')"
|
||||
color="primary"
|
||||
class="mt-2"
|
||||
@change="handleIsEditJson"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="newRecipeUrl"
|
||||
:label="$t('new-recipe.recipe-url')"
|
||||
:prepend-inner-icon="$globals.icons.link"
|
||||
validate-on="blur"
|
||||
variant="solo-filled"
|
||||
clearable
|
||||
rounded
|
||||
:rules="[validators.urlOptional]"
|
||||
:hint="$t('new-recipe.copy-and-paste-the-source-url-of-your-data-optional')"
|
||||
persistent-hint
|
||||
class="mt-10 mb-4"
|
||||
style="max-width: 500px"
|
||||
/>
|
||||
<RecipeJsonEditor
|
||||
v-if="isEditJSON"
|
||||
v-model="newRecipeData"
|
||||
height="250px"
|
||||
class="mt-10"
|
||||
mode="code"
|
||||
:main-menu-bar="false"
|
||||
/>
|
||||
@@ -41,10 +55,7 @@
|
||||
autofocus
|
||||
variant="solo-filled"
|
||||
clearable
|
||||
class="rounded-lg mt-2"
|
||||
rounded
|
||||
:hint="$t('new-recipe.url-form-hint')"
|
||||
persistent-hint
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="importKeywordsAsTags"
|
||||
@@ -124,6 +135,7 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
const newRecipeData = ref<string | object | null>(null);
|
||||
const newRecipeUrl = ref<string | null>(null);
|
||||
|
||||
function handleIsEditJson() {
|
||||
if (state.isEditJSON) {
|
||||
@@ -148,8 +160,13 @@ export default defineNuxtComponent({
|
||||
}
|
||||
handleIsEditJson();
|
||||
|
||||
async function createFromHtmlOrJson(htmlOrJsonData: string | object | null, importKeywordsAsTags: boolean) {
|
||||
if (!htmlOrJsonData || !domUrlForm.value?.validate()) {
|
||||
async function createFromHtmlOrJson(htmlOrJsonData: string | object | null, importKeywordsAsTags: boolean, url: string | null = null) {
|
||||
if (!htmlOrJsonData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isValid = await domUrlForm.value?.validate();
|
||||
if (!isValid?.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,7 +179,7 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
state.loading = true;
|
||||
const { response } = await api.recipes.createOneByHtmlOrJson(dataString, importKeywordsAsTags);
|
||||
const { response } = await api.recipes.createOneByHtmlOrJson(dataString, importKeywordsAsTags, url);
|
||||
handleResponse(response, importKeywordsAsTags);
|
||||
}
|
||||
|
||||
@@ -172,6 +189,7 @@ export default defineNuxtComponent({
|
||||
stayInEditMode,
|
||||
parseRecipe,
|
||||
newRecipeData,
|
||||
newRecipeUrl,
|
||||
handleIsEditJson,
|
||||
createFromHtmlOrJson,
|
||||
...toRefs(state),
|
||||
|
||||
@@ -209,12 +209,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
if (!item.id) {
|
||||
continue;
|
||||
}
|
||||
await categoryStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id).filter(id => !!id);
|
||||
await categoryStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -528,9 +528,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await foodStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await foodStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -261,9 +261,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await labelStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await labelStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -249,9 +249,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await actionStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await actionStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -211,12 +211,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
if (!item.id) {
|
||||
continue;
|
||||
}
|
||||
await tagStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id).filter(id => !!id);
|
||||
await tagStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -263,9 +263,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await toolStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await toolStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -465,9 +465,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await unitActions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await unitActions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -43,22 +43,22 @@ class PostgresProvider(AbstractDBProvider, BaseSettings):
|
||||
|
||||
model_config = SettingsConfigDict(arbitrary_types_allowed=True, extra="allow")
|
||||
|
||||
def _parse_override_url(self, url: str) -> str:
|
||||
if not url.startswith("postgresql://"):
|
||||
raise ValueError("POSTGRES_URL_OVERRIDE scheme must be postgresql")
|
||||
|
||||
scheme, remainder = url.split("://", 1)
|
||||
if "@" in remainder and ":" in remainder.split("@")[0]:
|
||||
credentials, host_part = remainder.rsplit("@", 1)
|
||||
user, password = credentials.split(":", 1)
|
||||
return f"{scheme}://{user}:{urlparse.quote(password, safe='')}@{host_part}"
|
||||
|
||||
return url
|
||||
|
||||
@property
|
||||
def db_url(self) -> str:
|
||||
if self.POSTGRES_URL_OVERRIDE:
|
||||
url = self.POSTGRES_URL_OVERRIDE
|
||||
|
||||
scheme, remainder = url.split("://", 1)
|
||||
if scheme != "postgresql":
|
||||
raise ValueError("POSTGRES_URL_OVERRIDE scheme must be postgresql")
|
||||
|
||||
remainder = remainder.split(":", 1)[1]
|
||||
password = remainder[: remainder.rfind("@")]
|
||||
quoted_password = urlparse.quote(password)
|
||||
|
||||
safe_url = url.replace(password, quoted_password)
|
||||
|
||||
return safe_url
|
||||
return self._parse_override_url(self.POSTGRES_URL_OVERRIDE)
|
||||
|
||||
return str(
|
||||
PostgresDsn.build(
|
||||
|
||||
@@ -15927,8 +15927,8 @@
|
||||
"vitamin c": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vitamin c",
|
||||
"plural_name": "vitamin cs"
|
||||
"name": "βιταμίνη C",
|
||||
"plural_name": "βιταμίνες C"
|
||||
},
|
||||
"acai powder": {
|
||||
"aliases": [],
|
||||
@@ -16119,8 +16119,8 @@
|
||||
"vitamin e": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "vitamin e",
|
||||
"plural_name": "vitamin es"
|
||||
"name": "βιταμίνη Ε",
|
||||
"plural_name": "βιταμίνες E"
|
||||
},
|
||||
"wine yeast": {
|
||||
"aliases": [],
|
||||
@@ -16156,7 +16156,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "βιταμίνη d",
|
||||
"plural_name": "vitamin ds"
|
||||
"plural_name": "βιταμίνες D"
|
||||
},
|
||||
"calcium lactate": {
|
||||
"aliases": [],
|
||||
@@ -16191,20 +16191,20 @@
|
||||
"magnesium": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "magnesium",
|
||||
"plural_name": "magnesiums"
|
||||
"name": "μαγνήσιο",
|
||||
"plural_name": "μαγνήσια"
|
||||
},
|
||||
"creatine": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "creatine",
|
||||
"plural_name": "creatines"
|
||||
"name": "κρεατίνη",
|
||||
"plural_name": "κρεατίνες"
|
||||
},
|
||||
"daily vitamin": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "daily vitamin",
|
||||
"plural_name": "daily vitamins"
|
||||
"name": "καθημερινή βιταμίνη",
|
||||
"plural_name": "καθημερινές βιταμίνες"
|
||||
},
|
||||
"moringa powder": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -1115,8 +1115,8 @@
|
||||
"finger lime": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "finger lime",
|
||||
"plural_name": "finger limes"
|
||||
"name": "fingurlímóna",
|
||||
"plural_name": "fingurlímónur"
|
||||
},
|
||||
"bitter orange": {
|
||||
"aliases": [],
|
||||
@@ -1223,8 +1223,8 @@
|
||||
"green ume plum": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "green ume plum",
|
||||
"plural_name": "green ume plums"
|
||||
"name": "græn japönsk plóma",
|
||||
"plural_name": "grænar japanskar plómur"
|
||||
},
|
||||
"kiwano": {
|
||||
"aliases": [],
|
||||
@@ -1323,14 +1323,14 @@
|
||||
"shimeji mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "shimeji mushroom",
|
||||
"plural_name": "shimeji mushrooms"
|
||||
"name": "shimeji sveppur",
|
||||
"plural_name": "shimeji sveppir"
|
||||
},
|
||||
"straw mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "straw mushroom",
|
||||
"plural_name": "straw mushrooms"
|
||||
"name": "matsokka",
|
||||
"plural_name": "matsokka"
|
||||
},
|
||||
"dried chinese mushroom": {
|
||||
"aliases": [],
|
||||
@@ -1407,8 +1407,8 @@
|
||||
"djon djon mushroom": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "djon djon mushroom",
|
||||
"plural_name": "djon djon mushrooms"
|
||||
"name": "djon djon sveppur",
|
||||
"plural_name": "djon djon sveppir"
|
||||
},
|
||||
"mixed asian mushroom": {
|
||||
"aliases": [],
|
||||
@@ -1543,20 +1543,20 @@
|
||||
"freeze-dried raspberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "freeze-dried raspberry",
|
||||
"plural_name": "freeze-dried raspberries"
|
||||
"name": "frostþurrkað hindber",
|
||||
"plural_name": "frostþurrkuð hindber"
|
||||
},
|
||||
"lingonberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lingonberry",
|
||||
"plural_name": "lingonberries"
|
||||
"name": "rauðber",
|
||||
"plural_name": "rauðber"
|
||||
},
|
||||
"canned sour cherry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "canned sour cherry",
|
||||
"plural_name": "canned sour cherries"
|
||||
"name": "niðursoðin súr kirsuber",
|
||||
"plural_name": "niðursoðin súr kirsuber"
|
||||
},
|
||||
"mulberry": {
|
||||
"aliases": [],
|
||||
@@ -1727,38 +1727,38 @@
|
||||
"almond": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "almond",
|
||||
"plural_name": "almonds"
|
||||
"name": "mandla",
|
||||
"plural_name": "möndlur"
|
||||
},
|
||||
"sesame seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sesame seed",
|
||||
"plural_name": "sesame seeds"
|
||||
"name": "sesam fræ",
|
||||
"plural_name": "sesam fræ"
|
||||
},
|
||||
"cashew": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cashew",
|
||||
"plural_name": "cashews"
|
||||
"name": "kasúhneta",
|
||||
"plural_name": "kasúhnetur"
|
||||
},
|
||||
"pine nut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pine nut",
|
||||
"plural_name": "pine nuts"
|
||||
"name": "furuhneta",
|
||||
"plural_name": "furuhnetur"
|
||||
},
|
||||
"pistachio": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "pistachio",
|
||||
"plural_name": "pistachios"
|
||||
"name": "pistasía",
|
||||
"plural_name": "pistasíur"
|
||||
},
|
||||
"peanut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "peanut",
|
||||
"plural_name": "peanuts"
|
||||
"name": "jarðhneta",
|
||||
"plural_name": "jarðhnetur"
|
||||
},
|
||||
"chia": {
|
||||
"aliases": [],
|
||||
@@ -15455,8 +15455,8 @@
|
||||
"lime soda": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lime soda",
|
||||
"plural_name": "lime sodas"
|
||||
"name": "límónu sódavatn",
|
||||
"plural_name": "límónu sódavatn"
|
||||
},
|
||||
"raspberry juice": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "paprika",
|
||||
"plural_name": "paprikas"
|
||||
"plural_name": "paprika's"
|
||||
},
|
||||
"carrot": {
|
||||
"aliases": [],
|
||||
@@ -292,7 +292,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "puntpaprika",
|
||||
"plural_name": "puntpaprikas"
|
||||
"plural_name": "puntpaprika's"
|
||||
},
|
||||
"serrano pepper": {
|
||||
"aliases": [],
|
||||
@@ -352,7 +352,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "spaghettipompoen",
|
||||
"plural_name": "spaghettipompoenen"
|
||||
"plural_name": "spaghetti pompoenen"
|
||||
},
|
||||
"butter lettuce": {
|
||||
"aliases": [],
|
||||
@@ -4034,7 +4034,7 @@
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "schapenvlees",
|
||||
"plural_name": "muttons"
|
||||
"plural_name": "schapenvlees"
|
||||
},
|
||||
"ham steak": {
|
||||
"aliases": [],
|
||||
@@ -4051,8 +4051,8 @@
|
||||
"bratwurst": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "bratwurst",
|
||||
"plural_name": "bratwursts"
|
||||
"name": "braadworst",
|
||||
"plural_name": "braadworsten"
|
||||
},
|
||||
"pulled pork": {
|
||||
"aliases": [],
|
||||
@@ -7650,7 +7650,7 @@
|
||||
"flour": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "flour",
|
||||
"name": "bloem",
|
||||
"plural_name": "flours"
|
||||
},
|
||||
"vanilla extract": {
|
||||
|
||||
@@ -1609,8 +1609,8 @@
|
||||
"barberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "barberry",
|
||||
"plural_name": "barberries"
|
||||
"name": "Барбарис",
|
||||
"plural_name": "Ягоды барбариса"
|
||||
},
|
||||
"dried berry": {
|
||||
"aliases": [],
|
||||
@@ -1621,38 +1621,38 @@
|
||||
"sea buckthorn": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sea buckthorn",
|
||||
"plural_name": "sea buckthorns"
|
||||
"name": "Облепиха",
|
||||
"plural_name": "Ягоды облепихи"
|
||||
},
|
||||
"saskatoon berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "saskatoon berry",
|
||||
"plural_name": "saskatoon berries"
|
||||
"name": "Ирга ольхолистная",
|
||||
"plural_name": "Ягоды ирга ольхолистная"
|
||||
},
|
||||
"rosehip": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "rosehip",
|
||||
"plural_name": "rosehips"
|
||||
"name": "Шиповник",
|
||||
"plural_name": "Плоды шиповника"
|
||||
},
|
||||
"hawthorn": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hawthorn",
|
||||
"plural_name": "hawthorns"
|
||||
"name": "Боя́рышник",
|
||||
"plural_name": "Плоды боярышника"
|
||||
},
|
||||
"boysenberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "boysenberry",
|
||||
"plural_name": "boysenberries"
|
||||
"name": "Бойзенова ягода",
|
||||
"plural_name": "Бойзеновы ягоды"
|
||||
},
|
||||
"cloudberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "cloudberry",
|
||||
"plural_name": "cloudberries"
|
||||
"name": "Морошка",
|
||||
"plural_name": "Ягоды морошки"
|
||||
},
|
||||
"freeze-dried berry": {
|
||||
"aliases": [],
|
||||
@@ -1663,50 +1663,50 @@
|
||||
"aronia berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "aronia berry",
|
||||
"plural_name": "aronia berries"
|
||||
"name": "Ягода арония",
|
||||
"plural_name": "Ягоды аронии"
|
||||
},
|
||||
"chokeberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "chokeberry",
|
||||
"plural_name": "chokeberries"
|
||||
"name": "Ягода арония черноплодная",
|
||||
"plural_name": "Ягоды аронии черноплодной"
|
||||
},
|
||||
"loganberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "loganberry",
|
||||
"plural_name": "loganberries"
|
||||
"name": "Логанова ягода",
|
||||
"plural_name": "Логановы ягоды"
|
||||
},
|
||||
"blackcurrant leaf": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "blackcurrant leaf",
|
||||
"plural_name": "blackcurrant leaves"
|
||||
"name": "Лист черной смородины",
|
||||
"plural_name": "Листья черной смородины"
|
||||
},
|
||||
"haskap berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "haskap berry",
|
||||
"plural_name": "haskap berries"
|
||||
"name": "Жимолость голубая",
|
||||
"plural_name": "Ягоды жимолости голубой"
|
||||
},
|
||||
"dewberry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "dewberry",
|
||||
"plural_name": "dewberries"
|
||||
"name": "Ягода рубуса (малинника)",
|
||||
"plural_name": "Ягоды рубуса (малинника)"
|
||||
},
|
||||
"sloe berry": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "sloe berry",
|
||||
"plural_name": "sloe berries"
|
||||
"name": "Плод тёрна",
|
||||
"plural_name": "Плоды тёрна"
|
||||
},
|
||||
"oregon grape": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "oregon grape",
|
||||
"plural_name": "oregon grapes"
|
||||
"name": "Ягода магонии (орегонский виноград)",
|
||||
"plural_name": "Ягоды магонии (орегонский виноград)"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1775,8 +1775,8 @@
|
||||
"slivered almond": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "slivered almond",
|
||||
"plural_name": "slivered almonds"
|
||||
"name": "Рубленный миндаль",
|
||||
"plural_name": "Рубленный миндаль"
|
||||
},
|
||||
"pumpkin seed": {
|
||||
"aliases": [],
|
||||
@@ -1823,14 +1823,14 @@
|
||||
"hemp heart": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "hemp heart",
|
||||
"plural_name": "hemp hearts"
|
||||
"name": "Семя конопли",
|
||||
"plural_name": "Семена конопли"
|
||||
},
|
||||
"nigella seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "nigella seed",
|
||||
"plural_name": "nigella seeds"
|
||||
"name": "Калинджи (чернушка посевная)",
|
||||
"plural_name": "Плоды калинджи (чернушки посевной)"
|
||||
},
|
||||
"mixed nut": {
|
||||
"aliases": [],
|
||||
@@ -1847,8 +1847,8 @@
|
||||
"mixed seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "mixed seed",
|
||||
"plural_name": "mixed seeds"
|
||||
"name": "Смесь семян ",
|
||||
"plural_name": "Смесь семян "
|
||||
},
|
||||
"onion seed": {
|
||||
"aliases": [],
|
||||
@@ -1865,8 +1865,8 @@
|
||||
"honey-roasted peanut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "honey-roasted peanut",
|
||||
"plural_name": "honey-roasted peanuts"
|
||||
"name": "Жареный арахис с мёдом",
|
||||
"plural_name": "Жареный арахис с мёдом"
|
||||
},
|
||||
"melon seed": {
|
||||
"aliases": [],
|
||||
@@ -1877,20 +1877,20 @@
|
||||
"lotus seed": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "lotus seed",
|
||||
"plural_name": "lotus seeds"
|
||||
"name": "Семя лотоса",
|
||||
"plural_name": "Семена лотоса"
|
||||
},
|
||||
"white chia": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "white chia",
|
||||
"plural_name": "white chias"
|
||||
"name": "Семя чиа",
|
||||
"plural_name": "Семена чиа"
|
||||
},
|
||||
"trail mix": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "trail mix",
|
||||
"plural_name": "trail mixes"
|
||||
"name": "Трейл-микс (смесь орехов и сухофруктов)",
|
||||
"plural_name": "Трейл-микс (смесь орехов и сухофруктов)"
|
||||
},
|
||||
"basil seed": {
|
||||
"aliases": [],
|
||||
@@ -1901,8 +1901,8 @@
|
||||
"candlenut": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "candlenut",
|
||||
"plural_name": "candlenuts"
|
||||
"name": "Семя лумбанга (тунга молуккского)",
|
||||
"plural_name": "Семена лумбанга (тунга молуккского)"
|
||||
},
|
||||
"peanut brittle": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -4165,14 +4165,14 @@
|
||||
"raw chorizo": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "raw chorizo",
|
||||
"name": "rå chorizo",
|
||||
"plural_name": "råa chorizoer"
|
||||
},
|
||||
"beef liver": {
|
||||
"aliases": [],
|
||||
"description": "",
|
||||
"name": "beef liver",
|
||||
"plural_name": "beef livers"
|
||||
"plural_name": "nötlevern"
|
||||
},
|
||||
"pastrami": {
|
||||
"aliases": [],
|
||||
|
||||
@@ -2,6 +2,7 @@ from functools import cached_property
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.core.dependencies.dependencies import get_temporary_zip_path
|
||||
from mealie.core.security import create_file_token
|
||||
@@ -48,14 +49,15 @@ class RecipeBulkActionsController(BaseUserController):
|
||||
with get_temporary_zip_path() as temp_path:
|
||||
self.service.export_recipes(temp_path, export_recipes.recipes)
|
||||
|
||||
@router.get("/export/download")
|
||||
def get_exported_data_token(self, path: Path):
|
||||
@router.get("/export/{export_id}/download")
|
||||
def get_exported_data_token(self, export_id: UUID4):
|
||||
"""Returns a token to download a file"""
|
||||
path = Path(path).resolve()
|
||||
|
||||
if not path.is_relative_to(self.folders.DATA_DIR):
|
||||
raise HTTPException(400, "path must be relative to data directory")
|
||||
export = self.service.get_export(export_id)
|
||||
if not export:
|
||||
raise HTTPException(404, "export not found")
|
||||
|
||||
path = Path(export.path).resolve()
|
||||
return {"fileToken": create_file_token(path)}
|
||||
|
||||
@router.get("/export", response_model=list[GroupDataExport])
|
||||
|
||||
@@ -148,7 +148,7 @@ class RecipeController(BaseRecipeController):
|
||||
async def _create_recipe_from_web(self, req: ScrapeRecipe | ScrapeRecipeData):
|
||||
if isinstance(req, ScrapeRecipeData):
|
||||
html = req.data
|
||||
url = ""
|
||||
url = req.url or ""
|
||||
else:
|
||||
html = None
|
||||
url = req.url
|
||||
|
||||
@@ -17,8 +17,12 @@ async def download_file(file_path: Path = Depends(validate_file_token)):
|
||||
file_path = Path(file_path).resolve()
|
||||
|
||||
dirs = get_app_dirs()
|
||||
allowed_dirs = [
|
||||
dirs.BACKUP_DIR, # admin backups
|
||||
dirs.GROUPS_DIR, # group exports
|
||||
]
|
||||
|
||||
if not file_path.is_relative_to(dirs.DATA_DIR):
|
||||
if not any(file_path.is_relative_to(allowed_dir) for allowed_dir in allowed_dirs):
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not file_path.is_file():
|
||||
|
||||
@@ -3,11 +3,11 @@ from .datetime_parse import DateError, DateTimeError, DurationError, TimeError
|
||||
from .mealie_model import HasUUID, MealieModel, SearchType
|
||||
|
||||
__all__ = [
|
||||
"HasUUID",
|
||||
"MealieModel",
|
||||
"SearchType",
|
||||
"DateError",
|
||||
"DateTimeError",
|
||||
"DurationError",
|
||||
"TimeError",
|
||||
"HasUUID",
|
||||
"MealieModel",
|
||||
"SearchType",
|
||||
]
|
||||
|
||||
@@ -5,49 +5,35 @@ from .debug import DebugResponse
|
||||
from .email import EmailReady, EmailSuccess, EmailTest
|
||||
from .maintenance import MaintenanceLogs, MaintenanceStorageDetails, MaintenanceSummary
|
||||
from .migration import ChowdownURL, MigrationFile, MigrationImport, Migrations
|
||||
from .restore import (
|
||||
CommentImport,
|
||||
CustomPageImport,
|
||||
GroupImport,
|
||||
ImportBase,
|
||||
NotificationImport,
|
||||
RecipeImport,
|
||||
SettingsImport,
|
||||
UserImport,
|
||||
)
|
||||
from .settings import CustomPageBase, CustomPageOut
|
||||
from .restore import CommentImport, GroupImport, ImportBase, RecipeImport, SettingsImport, UserImport
|
||||
|
||||
__all__ = [
|
||||
"MaintenanceLogs",
|
||||
"MaintenanceStorageDetails",
|
||||
"MaintenanceSummary",
|
||||
"ChowdownURL",
|
||||
"MigrationFile",
|
||||
"MigrationImport",
|
||||
"Migrations",
|
||||
"CustomPageBase",
|
||||
"CustomPageOut",
|
||||
"CommentImport",
|
||||
"CustomPageImport",
|
||||
"GroupImport",
|
||||
"ImportBase",
|
||||
"NotificationImport",
|
||||
"RecipeImport",
|
||||
"SettingsImport",
|
||||
"UserImport",
|
||||
"AllBackups",
|
||||
"BackupFile",
|
||||
"BackupOptions",
|
||||
"CreateBackup",
|
||||
"ImportJob",
|
||||
"MaintenanceLogs",
|
||||
"MaintenanceStorageDetails",
|
||||
"MaintenanceSummary",
|
||||
"AdminAboutInfo",
|
||||
"AppInfo",
|
||||
"AppStartupInfo",
|
||||
"AppStatistics",
|
||||
"AppTheme",
|
||||
"CheckAppConfig",
|
||||
"DebugResponse",
|
||||
"EmailReady",
|
||||
"EmailSuccess",
|
||||
"EmailTest",
|
||||
"DebugResponse",
|
||||
"ChowdownURL",
|
||||
"MigrationFile",
|
||||
"MigrationImport",
|
||||
"Migrations",
|
||||
"CommentImport",
|
||||
"GroupImport",
|
||||
"ImportBase",
|
||||
"RecipeImport",
|
||||
"SettingsImport",
|
||||
"UserImport",
|
||||
]
|
||||
|
||||
@@ -25,11 +25,3 @@ class GroupImport(ImportBase):
|
||||
|
||||
class UserImport(ImportBase):
|
||||
pass
|
||||
|
||||
|
||||
class CustomPageImport(ImportBase):
|
||||
pass
|
||||
|
||||
|
||||
class NotificationImport(ImportBase):
|
||||
pass
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
from typing import Annotated
|
||||
|
||||
from pydantic import ConfigDict, Field, field_validator
|
||||
from slugify import slugify
|
||||
|
||||
from mealie.schema._mealie import MealieModel
|
||||
|
||||
from ..recipe.recipe_category import RecipeCategoryResponse
|
||||
|
||||
|
||||
class CustomPageBase(MealieModel):
|
||||
name: str
|
||||
slug: Annotated[str | None, Field(validate_default=True)]
|
||||
position: int
|
||||
categories: list[RecipeCategoryResponse] = []
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@field_validator("slug", mode="before")
|
||||
def validate_slug(slug: str, values):
|
||||
name: str = values["name"]
|
||||
calc_slug: str = slugify(name)
|
||||
|
||||
if slug != calc_slug:
|
||||
slug = calc_slug
|
||||
|
||||
return slug
|
||||
|
||||
|
||||
class CustomPageOut(CustomPageBase):
|
||||
id: int
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -7,13 +7,13 @@ from .group_seeder import SeederConfig
|
||||
from .group_statistics import GroupStorage
|
||||
|
||||
__all__ = [
|
||||
"GroupDataExport",
|
||||
"CreateGroupPreferences",
|
||||
"ReadGroupPreferences",
|
||||
"UpdateGroupPreferences",
|
||||
"GroupStorage",
|
||||
"GroupDataExport",
|
||||
"DataMigrationCreate",
|
||||
"SupportedMigrations",
|
||||
"SeederConfig",
|
||||
"GroupAdminUpdate",
|
||||
"GroupStorage",
|
||||
]
|
||||
|
||||
@@ -70,6 +70,15 @@ from .invite_token import CreateInviteToken, EmailInitationResponse, EmailInvita
|
||||
from .webhook import CreateWebhook, ReadWebhook, SaveWebhook, WebhookPagination, WebhookType
|
||||
|
||||
__all__ = [
|
||||
"CreateHouseholdPreferences",
|
||||
"ReadHouseholdPreferences",
|
||||
"SaveHouseholdPreferences",
|
||||
"UpdateHouseholdPreferences",
|
||||
"CreateWebhook",
|
||||
"ReadWebhook",
|
||||
"SaveWebhook",
|
||||
"WebhookPagination",
|
||||
"WebhookType",
|
||||
"GroupEventNotifierCreate",
|
||||
"GroupEventNotifierOptions",
|
||||
"GroupEventNotifierOptionsOut",
|
||||
@@ -79,40 +88,7 @@ __all__ = [
|
||||
"GroupEventNotifierSave",
|
||||
"GroupEventNotifierUpdate",
|
||||
"GroupEventPagination",
|
||||
"CreateGroupRecipeAction",
|
||||
"GroupRecipeActionOut",
|
||||
"GroupRecipeActionPagination",
|
||||
"GroupRecipeActionPayload",
|
||||
"GroupRecipeActionType",
|
||||
"SaveGroupRecipeAction",
|
||||
"CreateWebhook",
|
||||
"ReadWebhook",
|
||||
"SaveWebhook",
|
||||
"WebhookPagination",
|
||||
"WebhookType",
|
||||
"CreateHouseholdPreferences",
|
||||
"ReadHouseholdPreferences",
|
||||
"SaveHouseholdPreferences",
|
||||
"UpdateHouseholdPreferences",
|
||||
"HouseholdCreate",
|
||||
"HouseholdInDB",
|
||||
"HouseholdPagination",
|
||||
"HouseholdRecipeBase",
|
||||
"HouseholdRecipeCreate",
|
||||
"HouseholdRecipeOut",
|
||||
"HouseholdRecipeSummary",
|
||||
"HouseholdRecipeUpdate",
|
||||
"HouseholdSave",
|
||||
"HouseholdSummary",
|
||||
"HouseholdUserSummary",
|
||||
"UpdateHousehold",
|
||||
"UpdateHouseholdAdmin",
|
||||
"HouseholdStatistics",
|
||||
"CreateInviteToken",
|
||||
"EmailInitationResponse",
|
||||
"EmailInvitation",
|
||||
"ReadInviteToken",
|
||||
"SaveInviteToken",
|
||||
"ShoppingListAddRecipeParams",
|
||||
"ShoppingListAddRecipeParamsBulk",
|
||||
"ShoppingListCreate",
|
||||
@@ -136,5 +112,29 @@ __all__ = [
|
||||
"ShoppingListSave",
|
||||
"ShoppingListSummary",
|
||||
"ShoppingListUpdate",
|
||||
"HouseholdCreate",
|
||||
"HouseholdInDB",
|
||||
"HouseholdPagination",
|
||||
"HouseholdRecipeBase",
|
||||
"HouseholdRecipeCreate",
|
||||
"HouseholdRecipeOut",
|
||||
"HouseholdRecipeSummary",
|
||||
"HouseholdRecipeUpdate",
|
||||
"HouseholdSave",
|
||||
"HouseholdSummary",
|
||||
"HouseholdUserSummary",
|
||||
"UpdateHousehold",
|
||||
"UpdateHouseholdAdmin",
|
||||
"CreateGroupRecipeAction",
|
||||
"GroupRecipeActionOut",
|
||||
"GroupRecipeActionPagination",
|
||||
"GroupRecipeActionPayload",
|
||||
"GroupRecipeActionType",
|
||||
"SaveGroupRecipeAction",
|
||||
"CreateInviteToken",
|
||||
"EmailInitationResponse",
|
||||
"EmailInvitation",
|
||||
"ReadInviteToken",
|
||||
"SaveInviteToken",
|
||||
"SetPermissions",
|
||||
]
|
||||
|
||||
@@ -12,9 +12,6 @@ from .plan_rules import PlanRulesCreate, PlanRulesDay, PlanRulesOut, PlanRulesPa
|
||||
from .shopping_list import ListItem, ShoppingListIn, ShoppingListOut
|
||||
|
||||
__all__ = [
|
||||
"ListItem",
|
||||
"ShoppingListIn",
|
||||
"ShoppingListOut",
|
||||
"CreatePlanEntry",
|
||||
"CreateRandomEntry",
|
||||
"PlanEntryPagination",
|
||||
@@ -28,4 +25,7 @@ __all__ = [
|
||||
"PlanRulesPagination",
|
||||
"PlanRulesSave",
|
||||
"PlanRulesType",
|
||||
"ListItem",
|
||||
"ShoppingListIn",
|
||||
"ShoppingListOut",
|
||||
]
|
||||
|
||||
@@ -89,8 +89,27 @@ from .recipe_tool import RecipeToolCreate, RecipeToolOut, RecipeToolResponse, Re
|
||||
from .request_helpers import RecipeDuplicate, RecipeSlug, SlugResponse, UpdateImageResponse
|
||||
|
||||
__all__ = [
|
||||
"IngredientReferences",
|
||||
"RecipeStep",
|
||||
"RecipeToolCreate",
|
||||
"RecipeToolOut",
|
||||
"RecipeToolResponse",
|
||||
"RecipeToolSave",
|
||||
"RecipeTimelineEventCreate",
|
||||
"RecipeTimelineEventIn",
|
||||
"RecipeTimelineEventOut",
|
||||
"RecipeTimelineEventPagination",
|
||||
"RecipeTimelineEventUpdate",
|
||||
"TimelineEventImage",
|
||||
"TimelineEventType",
|
||||
"RecipeAsset",
|
||||
"RecipeSettings",
|
||||
"RecipeShareToken",
|
||||
"RecipeShareTokenCreate",
|
||||
"RecipeShareTokenSave",
|
||||
"RecipeShareTokenSummary",
|
||||
"RecipeDuplicate",
|
||||
"RecipeSlug",
|
||||
"SlugResponse",
|
||||
"UpdateImageResponse",
|
||||
"RecipeNote",
|
||||
"CategoryBase",
|
||||
"CategoryIn",
|
||||
@@ -102,22 +121,23 @@ __all__ = [
|
||||
"TagIn",
|
||||
"TagOut",
|
||||
"TagSave",
|
||||
"RecipeAsset",
|
||||
"RecipeTimelineEventCreate",
|
||||
"RecipeTimelineEventIn",
|
||||
"RecipeTimelineEventOut",
|
||||
"RecipeTimelineEventPagination",
|
||||
"RecipeTimelineEventUpdate",
|
||||
"TimelineEventImage",
|
||||
"TimelineEventType",
|
||||
"RecipeSuggestionQuery",
|
||||
"RecipeSuggestionResponse",
|
||||
"RecipeSuggestionResponseItem",
|
||||
"RecipeCommentCreate",
|
||||
"RecipeCommentOut",
|
||||
"RecipeCommentPagination",
|
||||
"RecipeCommentSave",
|
||||
"RecipeCommentUpdate",
|
||||
"UserBase",
|
||||
"AssignCategories",
|
||||
"AssignSettings",
|
||||
"AssignTags",
|
||||
"DeleteRecipes",
|
||||
"ExportBase",
|
||||
"ExportRecipes",
|
||||
"ExportTypes",
|
||||
"IngredientReferences",
|
||||
"RecipeStep",
|
||||
"RecipeImageTypes",
|
||||
"Nutrition",
|
||||
"RecipeShareToken",
|
||||
"RecipeShareTokenCreate",
|
||||
"RecipeShareTokenSave",
|
||||
"RecipeShareTokenSummary",
|
||||
"CreateIngredientFood",
|
||||
"CreateIngredientFoodAlias",
|
||||
"CreateIngredientUnit",
|
||||
@@ -140,13 +160,9 @@ __all__ = [
|
||||
"SaveIngredientFood",
|
||||
"SaveIngredientUnit",
|
||||
"UnitFoodBase",
|
||||
"RecipeCommentCreate",
|
||||
"RecipeCommentOut",
|
||||
"RecipeCommentPagination",
|
||||
"RecipeCommentSave",
|
||||
"RecipeCommentUpdate",
|
||||
"UserBase",
|
||||
"RecipeSettings",
|
||||
"RecipeSuggestionQuery",
|
||||
"RecipeSuggestionResponse",
|
||||
"RecipeSuggestionResponseItem",
|
||||
"CreateRecipe",
|
||||
"CreateRecipeBulk",
|
||||
"CreateRecipeByUrlBulk",
|
||||
@@ -164,20 +180,4 @@ __all__ = [
|
||||
"ScrapeRecipeBase",
|
||||
"ScrapeRecipeData",
|
||||
"ScrapeRecipeTest",
|
||||
"AssignCategories",
|
||||
"AssignSettings",
|
||||
"AssignTags",
|
||||
"DeleteRecipes",
|
||||
"ExportBase",
|
||||
"ExportRecipes",
|
||||
"ExportTypes",
|
||||
"RecipeToolCreate",
|
||||
"RecipeToolOut",
|
||||
"RecipeToolResponse",
|
||||
"RecipeToolSave",
|
||||
"RecipeImageTypes",
|
||||
"RecipeDuplicate",
|
||||
"RecipeSlug",
|
||||
"SlugResponse",
|
||||
"UpdateImageResponse",
|
||||
]
|
||||
|
||||
@@ -117,9 +117,9 @@ class RecipeSummary(MealieModel):
|
||||
id: UUID4 | None = None
|
||||
_normalize_search: ClassVar[bool] = True
|
||||
|
||||
user_id: UUID4 = Field(default_factory=uuid4, validate_default=True)
|
||||
household_id: UUID4 = Field(default_factory=uuid4, validate_default=True)
|
||||
group_id: UUID4 = Field(default_factory=uuid4, validate_default=True)
|
||||
user_id: Annotated[UUID4, Field(default_factory=uuid4, validate_default=True)]
|
||||
household_id: Annotated[UUID4, Field(default_factory=uuid4, validate_default=True)]
|
||||
group_id: Annotated[UUID4, Field(default_factory=uuid4, validate_default=True)]
|
||||
|
||||
name: str | None = None
|
||||
slug: Annotated[str, Field(validate_default=True)] = ""
|
||||
@@ -134,7 +134,7 @@ class RecipeSummary(MealieModel):
|
||||
perform_time: str | None = None
|
||||
|
||||
description: str | None = ""
|
||||
recipe_category: Annotated[list[RecipeCategory] | None, Field(validate_default=True)] | None = []
|
||||
recipe_category: Annotated[list[RecipeCategory] | None, Field(validate_default=True)] = []
|
||||
tags: Annotated[list[RecipeTag] | None, Field(validate_default=True)] = []
|
||||
tools: list[RecipeTool] = []
|
||||
rating: float | None = None
|
||||
|
||||
@@ -27,3 +27,6 @@ class ScrapeRecipe(ScrapeRecipeBase):
|
||||
class ScrapeRecipeData(ScrapeRecipeBase):
|
||||
data: str
|
||||
"""HTML data or JSON string of a https://schema.org/Recipe object"""
|
||||
|
||||
url: str | None = None
|
||||
"""Optional URL of the recipe source"""
|
||||
|
||||
@@ -21,6 +21,10 @@ from .responses import ErrorResponse, FileTokenResponse, SuccessResponse
|
||||
from .validation import ValidationResponse
|
||||
|
||||
__all__ = [
|
||||
"ErrorResponse",
|
||||
"FileTokenResponse",
|
||||
"SuccessResponse",
|
||||
"SearchFilter",
|
||||
"LogicalOperator",
|
||||
"QueryFilterBuilder",
|
||||
"QueryFilterBuilderComponent",
|
||||
@@ -28,15 +32,11 @@ __all__ = [
|
||||
"QueryFilterJSONPart",
|
||||
"RelationalKeyword",
|
||||
"RelationalOperator",
|
||||
"ValidationResponse",
|
||||
"OrderByNullPosition",
|
||||
"OrderDirection",
|
||||
"PaginationBase",
|
||||
"PaginationQuery",
|
||||
"RecipeSearchQuery",
|
||||
"RequestQuery",
|
||||
"SearchFilter",
|
||||
"ErrorResponse",
|
||||
"FileTokenResponse",
|
||||
"SuccessResponse",
|
||||
"ValidationResponse",
|
||||
]
|
||||
|
||||
@@ -38,18 +38,12 @@ from .user_passwords import (
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"ForgotPassword",
|
||||
"PasswordResetToken",
|
||||
"PrivatePasswordResetToken",
|
||||
"ResetPassword",
|
||||
"SavePasswordResetToken",
|
||||
"ValidateResetToken",
|
||||
"CreateUserRegistration",
|
||||
"CredentialsRequest",
|
||||
"CredentialsRequestForm",
|
||||
"Token",
|
||||
"TokenData",
|
||||
"UnlockResults",
|
||||
"CreateUserRegistration",
|
||||
"ChangePassword",
|
||||
"CreateToken",
|
||||
"DeleteTokenResponse",
|
||||
@@ -75,4 +69,10 @@ __all__ = [
|
||||
"UserRatings",
|
||||
"UserSummary",
|
||||
"UserSummaryPagination",
|
||||
"ForgotPassword",
|
||||
"PasswordResetToken",
|
||||
"PrivatePasswordResetToken",
|
||||
"ResetPassword",
|
||||
"SavePasswordResetToken",
|
||||
"ValidateResetToken",
|
||||
]
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.core.exceptions import UnexpectedNone
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.schema.group.group_exports import GroupDataExport
|
||||
from mealie.schema.recipe import CategoryBase
|
||||
from mealie.schema.recipe.recipe_category import TagBase
|
||||
from mealie.schema.recipe.recipe_settings import RecipeSettings
|
||||
from mealie.schema.response.pagination import PaginationQuery
|
||||
from mealie.schema.user.user import GroupInDB, PrivateUser
|
||||
from mealie.services._base_service import BaseService
|
||||
from mealie.services.exporter import Exporter, RecipeExporter
|
||||
@@ -25,7 +28,11 @@ class RecipeBulkActionsService(BaseService):
|
||||
exporter.run(self.repos)
|
||||
|
||||
def get_exports(self) -> list[GroupDataExport]:
|
||||
return self.repos.group_exports.multi_query({"group_id": self.group.id})
|
||||
exports_page = self.repos.group_exports.page_all(PaginationQuery(per_page=-1))
|
||||
return exports_page.items
|
||||
|
||||
def get_export(self, id: UUID4) -> GroupDataExport | None:
|
||||
return self.repos.group_exports.get_one(id)
|
||||
|
||||
def purge_exports(self) -> int:
|
||||
all_exports = self.get_exports()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "mealie"
|
||||
version = "3.7.0"
|
||||
version = "3.8.0"
|
||||
description = "A Recipe Manager"
|
||||
authors = [{ name = "Hayden", email = "hay-kot@pm.me" }]
|
||||
license = "AGPL-3.0-only"
|
||||
@@ -17,7 +17,7 @@ dependencies = [
|
||||
"apprise==1.9.6",
|
||||
"bcrypt==5.0.0",
|
||||
"extruct==0.18.0",
|
||||
"fastapi==0.124.2",
|
||||
"fastapi==0.125.0",
|
||||
"httpx==0.28.1",
|
||||
"lxml==6.0.2",
|
||||
"orjson==3.11.5",
|
||||
@@ -30,19 +30,19 @@ dependencies = [
|
||||
"python-slugify==8.0.4",
|
||||
"recipe-scrapers==15.11.0",
|
||||
"requests==2.32.5",
|
||||
"tzdata==2025.2",
|
||||
"tzdata==2025.3",
|
||||
"uvicorn[standard]==0.38.0",
|
||||
"beautifulsoup4==4.14.3",
|
||||
"isodate==0.7.2",
|
||||
"text-unidecode==1.3",
|
||||
"rapidfuzz==3.14.3",
|
||||
"authlib==1.6.5",
|
||||
"authlib==1.6.6",
|
||||
"html2text==2025.4.15",
|
||||
"paho-mqtt==1.6.1",
|
||||
"pydantic-settings==2.12.0",
|
||||
"pillow-heif==1.1.1",
|
||||
"pyjwt==2.10.1",
|
||||
"openai==2.11.0",
|
||||
"openai==2.13.0",
|
||||
"typing-extensions==4.15.0",
|
||||
"itsdangerous==2.2.0",
|
||||
"ingredient-parser-nlp==2.4.0",
|
||||
@@ -61,13 +61,13 @@ dev = [
|
||||
"coverage==7.13.0",
|
||||
"coveragepy-lcov==0.1.2",
|
||||
"mkdocs-material==9.7.0",
|
||||
"mypy==1.19.0",
|
||||
"pre-commit==4.5.0",
|
||||
"mypy==1.19.1",
|
||||
"pre-commit==4.5.1",
|
||||
"pylint==4.0.4",
|
||||
"pytest==9.0.2",
|
||||
"pytest-asyncio==1.3.0",
|
||||
"rich==14.2.0",
|
||||
"ruff==0.14.9",
|
||||
"ruff==0.14.10",
|
||||
"types-PyYAML==6.0.12.20250915",
|
||||
"types-python-dateutil==2.9.0.20251115",
|
||||
"types-python-slugify==8.0.2.20240310",
|
||||
|
||||
@@ -123,11 +123,12 @@ def test_bulk_export_recipes(api_client: TestClient, unique_user: TestUser, ten_
|
||||
response_data = response.json()
|
||||
assert len(response_data) == 1
|
||||
|
||||
export_id = response_data[0]["id"]
|
||||
export_path = response_data[0]["path"]
|
||||
|
||||
# Get Export Token
|
||||
response = api_client.get(
|
||||
f"{api_routes.recipes_bulk_actions_export_download}?path={export_path}", headers=unique_user.token
|
||||
f"{api_routes.recipes_bulk_actions_export_export_id_download(export_id)}", headers=unique_user.token
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -58,6 +59,14 @@ psql_validation_cases = [
|
||||
"postgresql://mealie:P%40ssword%21%40%23%24%25%25%5E%5E%26%26%2A%2A%28%29%2B%3B%27%22%27%3C%3E%3F%7B%7D%5B%5D@postgres:5432/mealie",
|
||||
],
|
||||
),
|
||||
(
|
||||
"unencoded_to_encoded_no_port_url",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://mealie:P@ssword!@#$%%^^&&**()+;'\"'<>?{}[]@postgres/mealie",
|
||||
"postgresql://mealie:P%40ssword%21%40%23%24%25%25%5E%5E%26%26%2A%2A%28%29%2B%3B%27%22%27%3C%3E%3F%7B%7D%5B%5D@postgres/mealie",
|
||||
],
|
||||
),
|
||||
(
|
||||
"no_encode_needed_password",
|
||||
[
|
||||
@@ -74,6 +83,54 @@ psql_validation_cases = [
|
||||
"postgresql://mealie:MyPassword@postgres:5432/mealie",
|
||||
],
|
||||
),
|
||||
(
|
||||
"no_password_url",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://mealie@postgres:5432/mealie",
|
||||
"postgresql://mealie@postgres:5432/mealie",
|
||||
],
|
||||
),
|
||||
(
|
||||
"no_password_no_port_url",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://mealie@postgres/mealie",
|
||||
"postgresql://mealie@postgres/mealie",
|
||||
],
|
||||
),
|
||||
(
|
||||
"unix_socket_with_empty_password",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://mealie:@/mealie?host=/run/postgresql",
|
||||
"postgresql://mealie:@/mealie?host=/run/postgresql",
|
||||
],
|
||||
),
|
||||
(
|
||||
"unix_socket_no_password",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://mealie@/mealie?host=/run/postgresql",
|
||||
"postgresql://mealie@/mealie?host=/run/postgresql",
|
||||
],
|
||||
),
|
||||
(
|
||||
"no_credentials_at_all",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql:///mealie?host=/run/postgresql",
|
||||
"postgresql:///mealie?host=/run/postgresql",
|
||||
],
|
||||
),
|
||||
(
|
||||
"query_params_with_colon",
|
||||
[
|
||||
"POSTGRES_URL_OVERRIDE",
|
||||
"postgresql://user@host/db?sslmode=require&connect_timeout=10",
|
||||
"postgresql://user@host/db?sslmode=require&connect_timeout=10",
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
psql_cases = [x[1] for x in psql_validation_cases]
|
||||
@@ -174,11 +231,11 @@ def test_smtp_enable_with_bad_data_tls(data: SMTPValidationCase):
|
||||
@dataclass(slots=True)
|
||||
class EnvVar:
|
||||
name: str
|
||||
value: any
|
||||
value: Any
|
||||
|
||||
|
||||
class LDAPValidationCase:
|
||||
settings = list[EnvVar]
|
||||
settings: list[EnvVar]
|
||||
is_valid: bool
|
||||
|
||||
def __init__(
|
||||
@@ -222,7 +279,7 @@ def test_ldap_settings_validation(data: LDAPValidationCase, monkeypatch: pytest.
|
||||
|
||||
|
||||
class OIDCValidationCase:
|
||||
settings = list[EnvVar]
|
||||
settings: list[EnvVar]
|
||||
is_valid: bool
|
||||
|
||||
def __init__(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user