Compare commits

..

50 Commits

Author SHA1 Message Date
Hayden
845b2c2c73 fix(docs): restore classic Material look under Zensical's modern theme
Zensical ships a redesigned "modern" theme: a flat header that uses the page
background color and the Inter typeface, rather than Material's colored app-bar
and Roboto, and it keeps links / the nav active-item pill / the announce banner
on its default indigo accent. The mealie palette and custom.css load fine, but
the modern theme no longer wires --md-primary-fg-color to the header, and the
indigo accent clashes with the brand orange.

- mkdocs.yml: set theme.font to Roboto / Roboto Mono (Zensical honors theme.font)
- custom.css:
  - restore the orange app-bar (.md-header/.md-tabs) from --md-primary-fg-color
  - brand the accent (links, nav active pill, announce banner) by overriding
    --md-typeset-a-color and --md-accent-fg-color[--transparent]; the
    [scheme][primary] selector matches the theme's own (0,2,0) rules so it wins
    in both light (mealie) and dark (slate) modes
  - make the announce banner text adaptive so it is readable in light mode
    (was hardcoded light-gray, invisible on the modern theme's light banner)
- ai-providers.md: fix a broken self-referential link surfaced by Zensical's
  build check ("backend configuration" now points to backend-config.md)

Verified with headless-Chrome screenshots in both light and dark mode:
`zensical build` is clean ("No issues found"); Roboto fonts, orange header/tabs,
orange links, and a readable announce banner in both schemes.
2026-05-31 10:23:37 -05:00
Hayden
15b3e59c55 chore(docs): migrate documentation from MkDocs to Zensical
Material for MkDocs is in maintenance mode; Zensical is its successor from
the same maintainers. Zensical reads the existing mkdocs.yml natively, so
this is a tooling swap rather than a config rewrite.

- pyproject.toml: replace mkdocs-material with zensical in docs/dev groups
- Taskfile/CI/netlify: swap `mkdocs build|serve` for `zensical build|serve`
- mkdocs.yml: move custom `demo_url` under `extra:` (Zensical doesn't expose
  custom top-level config keys to templates); move `custom_dir` out of the
  docs source tree so raw templates aren't published as static files
- home.html: use `config.extra.demo_url`; replace the non-functional
  `lang.t('source.link.title')` (a Python call MiniJinja can't run, already
  rendering as literal text) with a static tooltip

Verified: `zensical build` exits clean ("No issues found"), 46 pages, with
mermaid, admonitions, content tabs, task lists, nav tabs, code-copy, custom
homepage, and announce banner all rendering at parity with the prior build.
2026-05-31 10:10:54 -05:00
Arsène Reymond
0af9633193 fix: add missing dependencies in package.json (#7709)
Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
2026-05-31 14:25:00 +00:00
mealie-actions[bot]
b5987f5a46 chore(l10n): Crowdin locale sync (#7713)
Co-authored-by: GitHub Action <action@github.com>
2026-05-31 03:13:02 +00:00
mealie-commit-bot[bot]
e24187fefb chore: bump version to v3.19.2 2026-05-29 04:11:50 +00:00
Michael Genson
396fcd5ee4 fix: Ensure secret key is not empty (#7701) 2026-05-28 23:09:31 -05:00
renovate[bot]
5a3d202879 chore(deps): lock file maintenance (#7697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 20:09:07 +00:00
renovate[bot]
62377ae7ad fix(deps): update dependency ingredient-parser-nlp to v2.7.0 (#7695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 19:34:54 +00:00
renovate[bot]
7498e22278 fix(deps): update dependency sqlalchemy to v2.0.50 (#7693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 19:34:00 +00:00
renovate[bot]
af6c9e074e fix(deps): update dependency uvicorn to v0.48.0 (#7696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 19:33:15 +00:00
renovate[bot]
71dba654b8 chore(deps): update dependency coverage to v7.14.1 (#7691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 19:31:38 +00:00
renovate[bot]
ba69fcf824 fix(deps): update dependency fastapi to v0.136.3 (#7692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 19:31:05 +00:00
Michael Genson
8219ac0168 dev: Set renovarte bot PRs to "immediate" (#7690) 2026-05-27 14:11:10 -05:00
mealie-commit-bot[bot]
47f66676e4 chore: bump version to v3.19.1 2026-05-27 16:49:42 +00:00
Hayden
31d9479d17 chore(l10n): New Crowdin updates (#7687) 2026-05-27 11:48:54 -05:00
Michael Genson
6a8eae7ce4 fix: Make most recipe action columns filterable (#7689) 2026-05-27 11:47:29 -05:00
Hayden
3bddfc21ce chore(l10n): New Crowdin updates (#7661)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
2026-05-27 04:13:05 +00:00
renovate[bot]
975a16c74b chore(deps): update dependency ruff to v0.15.14 (#7678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:38:12 +00:00
renovate[bot]
840da0e935 fix(deps): update dependency python-ldap to v3.4.7 (#7680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:38:02 +00:00
renovate[bot]
0e22f3f8fa fix(deps): update dependency orjson to v3.11.9 (#7672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:37:11 +00:00
renovate[bot]
ff67fb6a4f chore(deps): update dependency types-python-dateutil to v2.9.0.20260518 (#7669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:10:36 +00:00
renovate[bot]
97f37d0def chore(deps): update dependency types-requests to v2.33.0.20260518 (#7671)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:10:24 +00:00
renovate[bot]
37171d174b fix(deps): update dependency openai to v2.38.0 (#7677)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:09:45 +00:00
renovate[bot]
f010c13661 chore(deps): update node.js to 8530f76 (#7668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:06:37 +00:00
renovate[bot]
84622af5f8 fix(deps): update dependency pydantic to v2.13.4 (#7673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 23:02:10 +00:00
renovate[bot]
024dad6663 chore(deps): lock file maintenance (#7685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 22:49:52 +00:00
renovate[bot]
f1998121aa fix(deps): update dependency pyjwt to v2.13.0 (#7682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:57:36 +00:00
renovate[bot]
94ca311616 chore(deps): update dependency mypy to v2.1.0 (#7681)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:57:32 +00:00
renovate[bot]
44c4bbb9ab chore(deps): update dependency coverage to v7.14.0 (#7676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:55:43 +00:00
renovate[bot]
0c263c98c9 fix(deps): update dependency requests to v2.34.2 (#7683)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:55:22 +00:00
renovate[bot]
c235dc8d4d fix(deps): update dependency uvicorn to v0.47.0 (#7684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:51:54 +00:00
renovate[bot]
1b7eda0f2c fix(deps): update dependency python-multipart to v0.0.29 (#7675)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:51:31 +00:00
renovate[bot]
f3725b7184 fix(deps): update dependency lxml to v6.1.1 (#7679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:48:28 +00:00
renovate[bot]
00a4b51ec1 fix(deps): update dependency pydantic-settings to v2.14.1 (#7674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:46:54 +00:00
renovate[bot]
2cf042fce9 chore(deps): update dependency types-pyyaml to v6.0.12.20260518 (#7670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:44:36 +00:00
renovate[bot]
55a8fdfee5 chore(deps): update dependency nuxt to v4.4.6 [security] (#7667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-26 21:07:29 +00:00
Michael Genson
1ab5323f34 dev: Disable approvals for lockfile maintenance PR creation (#7666) 2026-05-26 16:11:03 -05:00
Hayden
fb4ba490af chore(l10n): New Crowdin updates (#7660) 2026-05-24 20:56:08 -05:00
mealie-commit-bot[bot]
d70978cd8b chore: bump version to v3.19.0 2026-05-24 19:30:20 +00:00
Michael Genson
3b2bcca639 fix: Prevent swiping AND scrolling on shopping list (#7659) 2026-05-24 13:28:58 -05:00
Hayden
16163a9189 chore(l10n): New Crowdin updates (#7653)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
2026-05-24 16:50:04 +00:00
mealie-actions[bot]
5ce448af7a chore(l10n): Crowdin locale sync (#7655)
Co-authored-by: GitHub Action <action@github.com>
2026-05-24 03:11:27 +00:00
Michael Genson
c3f87736d0 feat: In-app AI Provider Configuration (#7650) 2026-05-23 11:13:10 -05:00
Hayden
f6fe92b400 chore(l10n): New Crowdin updates (#7652) 2026-05-23 10:54:10 -05:00
Hayden
823b938a2c fix: enforce organize-group-data permission on food/tag/category mutations (#7651) 2026-05-23 05:32:57 +00:00
Hayden
8eb00c3dc0 chore(l10n): New Crowdin updates (#7649) 2026-05-22 11:06:43 -05:00
Michael Genson
642c826f2b fix: Protect sensitive data in query filter API (GHSA-8m57-7cv5-rjp8) (#7629)
Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
2026-05-21 21:08:41 +00:00
Hayden
493154caa8 chore(l10n): New Crowdin updates (#7646) 2026-05-21 15:27:16 -05:00
Hayden
71e0d99a46 chore(l10n): New Crowdin updates (#7643) 2026-05-20 22:35:33 -05:00
Michael Genson
c52a4e10c9 fix: Inconsistent "from an image" vs "from images" translation (#7642) 2026-05-20 13:45:42 -05:00
187 changed files with 8895 additions and 3866 deletions

View File

@@ -63,7 +63,7 @@ task setup # Install all dependencies (Python + Node)
task dev:services # Start Postgres & Mailpit containers
task py # Start FastAPI backend (port 9000)
task ui # Start Nuxt frontend (port 3000)
task docs # Start MkDocs documentation server
task docs # Start Zensical documentation server
```
**Code generation (REQUIRED after schema changes):**

View File

@@ -30,7 +30,7 @@ jobs:
run: uv sync --only-group docs --no-install-project
- name: Build docs
run: uv run --no-project mkdocs build -d site
run: uv run --no-project zensical build
working-directory: docs
- name: Upload artifact

View File

@@ -29,7 +29,7 @@ tasks:
desc: runs the documentation server
dir: docs
cmds:
- uv run python -m mkdocs serve
- uv run zensical serve
setup:ui:
desc: setup frontend dependencies

View File

@@ -1,7 +1,7 @@
###############################################
# Frontend Build
###############################################
FROM node:24@sha256:050bf2bbe33c1d6754e060bec89378a79ed831f04a7bb1a53fe45e997df7b3bb \
FROM node:24@sha256:8530f76a96d88820d288761f022e318970dda93d01536919fbc16076b7983e63 \
AS frontend-builder
WORKDIR /frontend

View File

@@ -58,9 +58,6 @@ load_secrets() {
"OIDC_CONFIGURATION_URL"
"OIDC_CLIENT_ID"
"OIDC_CLIENT_SECRET"
"OPENAI_BASE_URL"
"OPENAI_API_KEY"
)
# If any secrets are set, prefer them over base environment variables.

View File

@@ -17,6 +17,31 @@
--md-default-accent-bg-color: #1f1e1e;
}
/*
* Zensical's "modern" theme ships a flat header that uses the page background
* color. Restore the classic Material colored app-bar (and matching nav tabs)
* driven by the brand orange, and brand the link color to match.
*/
.md-header,
.md-tabs {
background-color: var(--md-primary-fg-color);
color: var(--md-primary-bg-color);
}
/*
* Brand the accent colors. The modern theme leaves links, the nav active-item
* pill, and the announce banner on its default indigo accent (the latter two
* via --md-accent-fg-color--transparent), which clashes with the orange. The
* [scheme][primary] selector matches the theme's own (0,2,0) accent rules so
* the override wins in both light (mealie) and dark (slate) modes.
*/
[data-md-color-scheme="mealie"][data-md-color-primary="indigo"],
[data-md-color-scheme="slate"][data-md-color-primary="indigo"] {
--md-typeset-a-color: var(--md-primary-fg-color);
--md-accent-fg-color: #e58325;
--md-accent-fg-color--transparent: #e583251a;
}
/* frontpage elements */
.tx-hero h1 {
font-size: 2.41rem !important;
@@ -64,7 +89,7 @@ th {
}
.announce-left > a {
color: #e0e0e0;
color: var(--md-default-fg-color);
font-weight: bold;
}

View File

@@ -1,10 +1,10 @@
!!! info
This guide was submitted by a community member. Find something wrong? Submit a PR to get it fixed!
An easy way to add recipes to Mealie from an Apple device is via an Apple Shortcut. This is a short guide to install an configure a shortcut able to add recipes via a link or image(s).
An easy way to add recipes to Mealie from an Apple device is via an Apple Shortcut. This is a short guide to install an configure a shortcut able to add recipes via a link or image(s).
!!! note
If adding via images make sure to enable [Mealie's OpenAI Integration](https://docs.mealie.io/documentation/getting-started/installation/open-ai/)
If adding via images make sure to enable [Mealie's AI Integration](https://docs.mealie.io/documentation/getting-started/installation/ai-providers)
## Javascript can only be run via Shortcuts on the Safari browser on MacOS and iOS. If you do not use Safari you may skip this section
Some sites have begun blocking AI scraping bots, inadvertently blocking the recipe scraping library Mealie uses as well. To circumvent this, the shortcut uses javascript to capture the raw html loaded in the browser and sends that to mealie when possible.
@@ -23,7 +23,7 @@ An API key is needed to authenticate with mealie. To create an api key for a use
The shortcut can be installed via **[This link](https://www.icloud.com/shortcuts/52834724050b42aebe0f2efd8d067360)**. Upon install, replace "MEALIE_API_KEY" with the API key generated previously and "MEALIE_URI" with the full URL used to access your mealie instance e.g. "http://10.0.0.5:9000" or "https://mealie.domain.com".
## Using the Shortcut
Once installed, the shortcut will automatically appear as an option when sharing an image or webpage. It can also be useful to add the shortcut to the home screen of your device. If selected from the home screen or shortcuts app, a menu will appear with prompts to import via **taking photo(s)**, **selecting photo(s)**, **scanning a URL**, or **pasting a URL**.
Once installed, the shortcut will automatically appear as an option when sharing an image or webpage. It can also be useful to add the shortcut to the home screen of your device. If selected from the home screen or shortcuts app, a menu will appear with prompts to import via **taking photo(s)**, **selecting photo(s)**, **scanning a URL**, or **pasting a URL**.
!!! note
Despite the Mealie API being able to accept multiple recipe images for import it is currently impossible to send multiple files in 1 web request via Shortcuts. Instead, the shortcut combines the images into a singular, vertically-concatenated image to send to mealie. This can result in slightly less-accurate text recognition.
Despite the Mealie API being able to accept multiple recipe images for import it is currently impossible to send multiple files in 1 web request via Shortcuts. Instead, the shortcut combines the images into a singular, vertically-concatenated image to send to mealie. This can result in slightly less-accurate text recognition.

View File

@@ -33,7 +33,7 @@
6. Click the Edit button/icon again
7. Scroll to the ingredients and you should see new fields for Amount, Unit, Food, and Note. The Note in particular will contain the original text of the Recipe.
8. Click `Parse` and you will be taken to the ingredient parsing page.
9. Choose your parser. The `Natural Language Parser` works very well, but you can also use the `Brute Parser`, or the `OpenAI Parser` if you've [enabled OpenAI support](./installation/backend-config.md#openai).
9. Choose your parser. The `Natural Language Parser` works very well, but you can also use the `Brute Parser`, or the `OpenAI Parser` if you've [enabled AI support](./installation/ai-providers.md).
10. Click `Parse All`, and your ingredients should be separated out into Units and Foods based on your seeding in Step 1 above.
11. For ingredients where the Unit or Food was not found, you can click a button to accept an automatically suggested Food to add to the database. Or, manually enter the Unit/Food and hit `Enter` (or click `Create`) to add it to the database
12. When done, click `Save All` and you will be taken back to the recipe. Now the Unit and Food fields of the recipe should be filled out.

View File

@@ -11,7 +11,7 @@ Mealie offers several ways to create recipes:
- **Recipe HTML or JSON:** Copy/paste structured HTML or JSON and Mealie can import it.
- **Manual Editor:** Create recipes from scratch using the integrated editor.
Mealie's [AI integration](./installation/open-ai.md) greatly expands the ways you can create recipes:
Mealie's [AI integration](./installation/ai-providers.md) greatly expands the ways you can create recipes:
- **Image Import:** Upload an image of a written or typed recipe and Mealie will use OCR and AI to import it.
- **Video URL Import:** Provide a video URL (e.g., YouTube) and Mealie will transcribe the audio and turn it into a recipe.

View File

@@ -0,0 +1,29 @@
# AI Integration
:octicons-tag-24: v1.7.0
Mealie's AI integration enables several features and enhancements throughout the application. To enable AI features, you must have access to an AI provider (such as OpenAI). Mealie works with any OpenAI-compatible API.
## Configuration
To set up AI providers, visit your group settings.
[Group Settings Demo](https://demo.mealie.io/group){ .md-button .md-button--primary }
- To enable AI features at all, you *must* set a default provider (e.g. `gpt-5`)
- To enable image recognition features, such as creating a recipe from an image, configure a provider capable of image recognition (e.g. `gpt-5`)
- To enable audio transcription features, such as importing a recipe from a video, configure a provider capable of audio transcriptions (e.g. `whisper-1`)
For most users, choosing an OpenAI model (such as `gpt-5`) and supplying the OpenAI API key is all you need to do. Note that while OpenAI has a free tier, it's not sufficiently capable for Mealie (or most other production use cases). For more information, check out [OpenAI's rate limits](https://platform.openai.com/docs/guides/rate-limits). If you deposit $5 into your OpenAI account, you will be permanently bumped up to Tier 1, which is sufficient for Mealie. Cost per-request is dependant on many factors, but Mealie tries to keep token counts conservative.
If you have another provider you'd like to use, such as Azure, you can configure Mealie to use that instead as long as it has an OpenAI-compatible API. For instance, a common self-hosted alternative to OpenAI is [Ollama](https://ollama.com/). To use Ollama with Mealie, set your `base_url` to `http://localhost:11434/v1` (where `http://localhost:11434` is wherever you're hosting Ollama, and `/v1` enables the OpenAI-compatible endpoints). Note that you *must* provide an API key, even though it is ultimately ignored by Ollama.
Note that some models are capable of handling multiple features (e.g. `gpt-5` can handle both normal chat requests and image recognition requests). You may configure one provider for multiple provider features.
While Mealie has prompts for each AI task, you can override these with your own prompts if you'd like. For more information, check out the [backend configuration](./backend-config.md).
## AI Features
- The OpenAI Ingredient Parser can be used as an alternative to the NLP and Brute Force parsers. Simply choose the OpenAI parser while parsing ingredients (:octicons-tag-24: v1.7.0)
- When importing a recipe via URL, if the default recipe scraper is unable to read the recipe data from a webpage, the webpage contents will be parsed by OpenAI (:octicons-tag-24: v1.9.0)
- You can import an image of a written recipe, which is sent to OpenAI and imported into Mealie. The recipe can be hand-written or typed, as long as the text is in the picture. You can also optionally have OpenAI translate the recipe into your own language (:octicons-tag-24: v1.12.0)
- You can import a recipe via a video URL (e.g., a YouTube link). The video is transcribed AI, and the transcription is parsed into a recipe (:octicons-tag-24: v3.13.0)

View File

@@ -120,22 +120,10 @@ For usage, see [Usage - OpenID Connect](../authentication/oidc-v2.md)
:octicons-tag-24: v1.7.0
Mealie supports various integrations using OpenAI. For more information, check out our [OpenAI documentation](./open-ai.md).
For custom mapping variables (e.g. OPENAI_CUSTOM_HEADERS) you should pass values as JSON encoded strings (e.g. `OPENAI_CUSTOM_PARAMS='{"k1": "v1", "k2": "v2"}'`)
Mealie supports various integrations using OpenAI. For more information, check out our [OpenAI documentation](./ai-providers.md).
| Variables | Default | Description |
|-------------------------------------------------------------------------|:-----------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| OPENAI_BASE_URL<super>[&dagger;][secrets]</super> | None | The base URL for the OpenAI API. If you're not sure, leave this empty to use the standard OpenAI platform |
| OPENAI_API_KEY<super>[&dagger;][secrets]</super> | None | Your OpenAI API Key. Enables OpenAI-related features |
| OPENAI_MODEL | gpt-4o | Which OpenAI model to use. If you're not sure, leave this empty |
| OPENAI_AUDIO_MODEL <br/> :octicons-tag-24: v3.13.0 | whisper-1 | Which OpenAI model to use for audio transcriptions, if enabled. If you're not sure, leave this empty |
| OPENAI_CUSTOM_HEADERS <br/> :octicons-tag-24: v2.0.0 | None | Custom HTTP headers to add to all OpenAI requests. This should generally be left empty unless your custom service requires them |
| OPENAI_CUSTOM_PARAMS <br/> :octicons-tag-24: v2.0.0 | None | Custom HTTP query params to add to all OpenAI requests. This should generally be left empty unless your custom service requires them |
| OPENAI_ENABLE_IMAGE_SERVICES <br/> :octicons-tag-24: v1.12.0 | True | Whether to enable OpenAI image services, such as creating recipes via image. Leave this enabled unless your custom model doesn't support it, or you want to reduce costs |
| OPENAI_ENABLE_TRANSCRIPTION_SERVICES <br/> :octicons-tag-24: v3.13.0 | True | Whether to enable OpenAI transcription services, such as creating recipes via video URL. Leave this enabled unless your custom model doesn't support it, or you want to reduce costs |
| OPENAI_WORKERS | 2 | Number of OpenAI workers per request. Higher values may increase processing speed, but will incur additional API costs |
| OPENAI_SEND_DATABASE_DATA | True | Whether to send Mealie data to OpenAI to improve request accuracy. This will incur additional API costs |
| OPENAI_REQUEST_TIMEOUT | 300 | The number of seconds to wait for an OpenAI request to complete before cancelling the request. Leave this empty unless you're running into timeout issues on slower hardware |
| OPENAI_CUSTOM_PROMPT_DIR <br/> :octicons-tag-24: v3.10.0 | None. | Path to custom prompt files. Only existing files in your custom directory will override the defaults; any missing or empty custom files will automatically fall back to the system defaults. See https://github.com/mealie-recipes/mealie/tree/mealie-next/mealie/services/openai/prompts for expected file names. |
### Theming
@@ -315,7 +303,6 @@ at least these sensitive environment variables when working within shared enviro
- `POSTGRES_PASSWORD`
- `SMTP_PASSWORD`
- `LDAP_QUERY_PASSWORD`
- `OPENAI_API_KEY`
[docker-secrets]: https://docs.docker.com/compose/use-secrets/
[secrets]: #docker-secrets

View File

@@ -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.18.0`
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.19.2`
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

View File

@@ -1,24 +0,0 @@
# OpenAI Integration
:octicons-tag-24: v1.7.0
Mealie's OpenAI integration enables several features and enhancements throughout the application. To enable OpenAI features, you must have an account with OpenAI and configure Mealie to use the OpenAI API key (for more information, check out the [backend configuration](./backend-config.md#openai)).
## Configuration
For most users, supplying the OpenAI API key is all you need to do; you will use the regular OpenAI service with the default language model. Note that while OpenAI has a free tier, it's not sufficiently capable for Mealie (or most other production use cases). For more information, check out [OpenAI's rate limits](https://platform.openai.com/docs/guides/rate-limits). If you deposit $5 into your OpenAI account, you will be permanently bumped up to Tier 1, which is sufficient for Mealie. Cost per-request is dependant on many factors, but Mealie tries to keep token counts conservative.
Alternatively, if you have another service you'd like to use in-place of OpenAI, you can configure Mealie to use that instead, as long as it has an OpenAI-compatible API. For instance, a common self-hosted alternative to OpenAI is [Ollama](https://ollama.com/). To use Ollama with Mealie, change your `OPENAI_BASE_URL` to `http://localhost:11434/v1` (where `http://localhost:11434` is wherever you're hosting Ollama, and `/v1` enables the OpenAI-compatible endpoints). Note that you *must* provide an API key, even though it is ultimately ignored by Ollama.
If you wish to disable image recognition features (to save costs, or because your custom model doesn't support them) you can set `OPENAI_ENABLE_IMAGE_SERVICES` to `False`.
If you wish to disable transcription features (to save costs, or because your custom model doesn't support them) you can set `OPENAI_ENABLE_TRANSCRIPTION_SERVICES` to `False`.
For more information on what configuration options are available, check out the [backend configuration](./backend-config.md#openai).
## OpenAI Features
- The OpenAI Ingredient Parser can be used as an alternative to the NLP and Brute Force parsers. Simply choose the OpenAI parser while parsing ingredients (:octicons-tag-24: v1.7.0)
- When importing a recipe via URL, if the default recipe scraper is unable to read the recipe data from a webpage, the webpage contents will be parsed by OpenAI (:octicons-tag-24: v1.9.0)
- You can import an image of a written recipe, which is sent to OpenAI and imported into Mealie. The recipe can be hand-written or typed, as long as the text is in the picture. You can also optionally have OpenAI translate the recipe into your own language (:octicons-tag-24: v1.12.0)
- You can import a recipe via a video URL (e.g., a YouTube link). The video is transcribed using OpenAI's Whisper model, and the transcription is parsed into a recipe (:octicons-tag-24: v3.13.0)

View File

@@ -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.18.0 # (3)
image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
container_name: mealie
restart: always
ports:

View File

@@ -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.18.0 # (3)
image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
container_name: mealie
restart: always
ports:

View File

@@ -1,5 +1,4 @@
site_name: Mealie
demo_url: https://demo.mealie.io
site_url: https://docs.mealie.io
use_directory_urls: true
theme:
@@ -16,7 +15,7 @@ theme:
toggle:
icon: material/weather-sunny
name: Switch to light mode
custom_dir: docs/overrides
custom_dir: overrides
features:
- content.code.annotate
- content.code.copy
@@ -28,6 +27,9 @@ theme:
- navigation.tabs.sticky
favicon: assets/img/favicon.png
name: material
font:
text: Roboto
code: Roboto Mono
icon:
logo: material/silverware-variant
@@ -50,6 +52,8 @@ markdown_extensions:
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.details
extra:
demo_url: https://demo.mealie.io
extra_css:
- assets/stylesheets/custom.css
extra_javascript:
@@ -76,7 +80,7 @@ nav:
- Backend Configuration: "documentation/getting-started/installation/backend-config.md"
- Security: "documentation/getting-started/installation/security.md"
- Logs: "documentation/getting-started/installation/logs.md"
- OpenAI: "documentation/getting-started/installation/open-ai.md"
- AI Providers: "documentation/getting-started/installation/ai-providers.md"
- Usage:
- Backup and Restoring: "documentation/getting-started/usage/backups-and-restoring.md"
- Permissions and Public Access: "documentation/getting-started/usage/permissions-and-public-access.md"

View File

@@ -228,7 +228,7 @@
class="md-button md-button--primary">
Get started
</a>
<a href="{{ config.demo_url }}" title="{{ lang.t('source.link.title') }}" target="_blank" class="md-button">
<a href="{{ config.extra.demo_url }}" title="View the Mealie demo" target="_blank" class="md-button">
View the Demo
</a>
</div>

View File

@@ -0,0 +1,63 @@
<template>
<div>
<p>AI providers can now be configured directly in Mealie, without managing environment variables or secrets.</p>
<div class="mb-2">
AI providers enable features such as:
<ul class="ml-6">
<li>Creating recipes from images</li>
<li>Importing recipes from videos (YouTube, TikTok, etc.)</li>
<li>Enhanced ingredient parsing</li>
<li>And more!</li>
</ul>
</div>
<hr class="mt-2 mb-4">
<p>
<span v-if="group?.aiProviderSettings?.aiEnabled">
Your group already has AI providers configured.
</span>
<span v-else>
Your group does not currently have any AI providers configured.
</span>
<span v-if="user?.canManage">
You can manage them here:
<br>
<v-btn class="mt-2" color="primary" to="/group">
{{ $t("profile.group-settings") }}
</v-btn>
</span>
<span v-else-if="!group?.aiProviderSettings?.aiEnabled">
Contact a group manager or server admin to set up AI providers for your group.
</span>
</p>
<div v-if="user?.admin">
<br>
<p>
As an admin, you can configure AI providers for any group. Unlike the old environment variable approach, providers are configured per-group:
<br>
<v-btn class="mt-2" color="primary" to="/admin/manage/groups">
{{ $t("group.admin-group-management") }}
</v-btn>
</p>
</div>
</div>
</template>
<script setup lang="ts">
import { useGroupSelf } from "~/composables/use-groups";
import type { AnnouncementMeta } from "~/composables/use-announcements";
const { user } = useMealieAuth();
const { group } = useGroupSelf();
</script>
<script lang="ts">
export const meta: AnnouncementMeta = {
title: "Improved AI Provider Configuration",
};
</script>
<style scoped lang="css">
p {
padding-bottom: 8px;
}
</style>

View File

@@ -0,0 +1,204 @@
<template>
<BaseDialog
v-model="dialog"
:title="isEdit ? $t('group.ai-provider-settings.edit-provider') : $t('group.ai-provider-settings.create-provider')"
:icon="$globals.icons.robot"
:loading="loading"
can-submit
:submit-icon="isEdit ? $globals.icons.save : $globals.icons.createAlt"
:submit-text="isEdit ? $t('general.update') : $t('general.create')"
:submit-disabled="submitDisabled"
@submit="handleSubmit"
@close="resetForm"
>
<v-card-text v-if="init" style="max-height: 70vh; overflow-y: auto;">
<v-form ref="form" v-no-autofill>
<v-text-field
v-model="formData.name"
:label="$t('group.ai-provider-settings.provider-name')"
:rules="[validators.required]"
density="compact"
variant="outlined"
class="mb-4"
/>
<v-text-field
v-model="formData.model"
:label="$t('group.ai-provider-settings.model')"
:hint="$t('group.ai-provider-settings.model-description')"
:rules="[validators.required]"
density="compact"
variant="outlined"
class="mb-4"
/>
<v-text-field
v-model="formData.apiKey"
:label="$t('group.ai-provider-settings.api-key')"
:hint="$t(
isEdit
? 'group.ai-provider-settings.api-key-description-edit'
: 'group.ai-provider-settings.api-key-description-create',
)"
:persistent-hint="isEdit"
:rules="isEdit ? [] : [validators.required]"
density="compact"
variant="outlined"
type="password"
class="mb-4"
/>
<v-text-field
v-model="formData.baseUrl"
:label="$t('group.ai-provider-settings.base-url')"
:hint="$t('group.ai-provider-settings.base-url-description')"
density="compact"
variant="outlined"
class="mb-4"
/>
<v-number-input
v-model.number="formData.timeout"
:label="$t('group.ai-provider-settings.request-timeout-seconds')"
type="number"
:min="0"
hide-details
control-variant="stacked"
density="compact"
variant="outlined"
class="mb-4"
/>
<v-expansion-panels v-model="advancedPanel" variant="accordion">
<v-expansion-panel>
<v-expansion-panel-title class="text-subtitle-2" expand-icon="$expand" collapse-icon="$expand">
{{ $t('search.advanced') }}
</v-expansion-panel-title>
<v-expansion-panel-text class="px-0">
<div class="mb-2 text-subtitle-2">
{{ $t('group.ai-provider-settings.request-headers') }}
</div>
<BaseKeyValueEditor
v-model="formData.requestHeaders"
class="mb-4"
/>
<v-divider class="mb-4" />
<div class="mb-2 text-subtitle-2">
{{ $t('group.ai-provider-settings.request-params') }}
</div>
<BaseKeyValueEditor
v-model="formData.requestParams"
/>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-form>
</v-card-text>
<AppLoader v-else waiting-text="" />
</BaseDialog>
</template>
<script setup lang="ts">
import { useAIProviders } from "~/composables/use-ai-providers";
import { validators } from "~/composables/use-validators";
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
const props = withDefaults(defineProps<{
providerId?: string;
}>(), {
providerId: undefined,
});
const emit = defineEmits<{
(e: "create", data: AIProviderCreate): void;
(e: "update", id: string, data: AIProviderUpdate): void;
}>();
const dialog = defineModel<boolean>({ default: false });
const { $globals } = useNuxtApp();
const { loading, getOne } = useAIProviders();
const init = ref(false);
const form = ref();
const advancedPanel = ref<number | undefined>(undefined);
const isEdit = computed(() => !!props.providerId);
const defaultForm = () => ({
name: "",
model: "",
apiKey: "",
baseUrl: "",
timeout: 300,
requestHeaders: {} as Record<string, string>,
requestParams: {} as Record<string, string>,
});
const formData = reactive(defaultForm());
const submitDisabled = computed(() => {
return !formData.name?.trim() || !formData.model?.trim() || (!isEdit.value && !formData.apiKey?.trim());
});
// Fetch existing provider when editing; reset form for create mode
watch(
() => [dialog.value, props.providerId] as const,
async ([open, id]) => {
if (!open) return;
if (!id) {
// Create mode — just show the empty form
resetForm();
init.value = true;
return;
}
init.value = false;
const { data } = await getOne(id);
init.value = true;
if (data) {
formData.name = data.name;
formData.model = data.model;
formData.apiKey = "";
formData.baseUrl = data.baseUrl ?? "";
formData.timeout = data.timeout ?? 300;
formData.requestHeaders = { ...(data.requestHeaders ?? {}) };
formData.requestParams = { ...(data.requestParams ?? {}) };
}
},
{ immediate: true },
);
function handleSubmit() {
// Required field guard (button is also disabled, but keep as a safeguard)
if (!formData.name?.trim() || !formData.model?.trim()) return;
if (!isEdit.value && !formData.apiKey?.trim()) return;
if (isEdit.value && props.providerId) {
const payload: AIProviderUpdate & { apiKey?: string } = {
name: formData.name,
model: formData.model,
baseUrl: formData.baseUrl || null,
timeout: formData.timeout,
requestHeaders: Object.keys(formData.requestHeaders).length ? formData.requestHeaders : undefined,
requestParams: Object.keys(formData.requestParams).length ? formData.requestParams : undefined,
};
if (formData.apiKey) {
payload.apiKey = formData.apiKey;
}
emit("update", props.providerId, payload);
}
else {
const createPayload = {
name: formData.name,
model: formData.model,
apiKey: formData.apiKey,
baseUrl: formData.baseUrl || null,
timeout: formData.timeout,
requestHeaders: Object.keys(formData.requestHeaders).length ? formData.requestHeaders : undefined,
requestParams: Object.keys(formData.requestParams).length ? formData.requestParams : undefined,
};
emit("create", createPayload as AIProviderCreate);
}
}
function resetForm() {
Object.assign(formData, defaultForm());
form.value?.reset();
advancedPanel.value = undefined;
}
</script>

View File

@@ -0,0 +1,170 @@
<template>
<div v-if="providerSettings">
<BaseCardSectionTitle v-if="!hideHeader" :title="$t('group.ai-provider-settings.ai-provider-settings')">
<template v-if="noDefaultProviderWarning" #append-title>
<v-tooltip location="bottom" color="warning">
<template #activator="{ props: tooltipProps }">
<v-icon v-bind="tooltipProps" size="small" color="warning" class="ms-2">
{{ $globals.icons.alert }}
</v-icon>
</template>
<span>{{ $t('group.ai-provider-settings.no-default-provider-warning') }}</span>
</v-tooltip>
</template>
</BaseCardSectionTitle>
<v-card-text v-if="!hideHeader" class="pt-0 pb-10 px-0">
{{ $t("group.ai-provider-settings.ai-provider-settings-description") }}
</v-card-text>
<v-row class="mb-4">
<v-col cols="12">
<v-autocomplete
v-model="local.defaultProviderId"
:label="$t('group.ai-provider-settings.default-provider')"
:items="local.providers"
item-title="name"
item-value="id"
clearable
hide-details
density="compact"
variant="outlined"
/>
<v-card-subtitle class="mt-1">
{{ $t("group.ai-provider-settings.default-provider-description") }}
</v-card-subtitle>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="local.audioProviderId"
:label="$t('group.ai-provider-settings.audio-provider')"
:items="local.providers"
item-title="name"
item-value="id"
clearable
hide-details
density="compact"
variant="outlined"
/>
<v-card-subtitle class="mt-1">
{{ $t("group.ai-provider-settings.audio-provider-description") }}
</v-card-subtitle>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="local.imageProviderId"
:label="$t('group.ai-provider-settings.image-provider')"
:items="local.providers"
item-title="name"
item-value="id"
clearable
hide-details
density="compact"
variant="outlined"
/>
<v-card-subtitle class="mt-1">
{{ $t("group.ai-provider-settings.image-provider-description") }}
</v-card-subtitle>
</v-col>
</v-row>
<GroupAIProviderDialog
v-model="dialogOpen"
:provider-id="editingProviderId ?? undefined"
@create="(data) => $emit('create', data)"
@update="(id, data) => $emit('update', id, data)"
/>
<BaseCardSectionTitle
:title="$t('group.ai-provider-settings.providers')"
size="medium"
class="pt-2"
>
<template #append-title>
<BaseButton
:text="$t('group.ai-provider-settings.create-provider')"
class="ms-auto my-2"
create
small
@click="openCreate"
/>
</template>
</BaseCardSectionTitle>
<v-card
v-for="provider in local.providers"
:key="provider.id"
variant="tonal"
class="pa-0 mb-4"
>
<v-row no-gutters>
<v-col :cols="10">
<v-card-text>
{{ provider.name }}
</v-card-text>
</v-col>
<v-col :cols="2">
<BaseButtonGroup
:buttons="[
{
icon: $globals.icons.edit,
text: $t('general.edit'),
event: 'edit',
},
{
icon: $globals.icons.delete,
text: $t('general.delete'),
event: 'delete',
},
]"
@edit="openEdit(provider.id)"
@delete="$emit('delete', provider.id)"
/>
</v-col>
</v-row>
</v-card>
</div>
</template>
<script setup lang="ts">
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
import type { AIProviderSettingsOut } from "~/lib/api/types/user";
const providerSettings = defineModel<AIProviderSettingsOut>({ required: true });
const props = withDefaults(defineProps<{
hideHeader?: boolean;
}>(), {
hideHeader: false,
});
const { hideHeader } = toRefs(props);
const local = reactive({ ...providerSettings.value });
watch(local, (newVal) => { providerSettings.value = { ...newVal }; });
// Sync back when the parent refreshes after create/update/delete
watch(providerSettings, (newVal) => { if (newVal) Object.assign(local, newVal); });
const noDefaultProviderWarning = computed(
() => local.providers.length > 0 && !local.defaultProviderId,
);
defineEmits<{
(e: "create", data: AIProviderCreate): void;
(e: "update", id: string, data: AIProviderUpdate): void;
(e: "delete", id: string): void;
}>();
const dialogOpen = ref(false);
const editingProviderId = ref<string | null>(null);
function openCreate() {
editingProviderId.value = null;
dialogOpen.value = true;
}
function openEdit(id: string) {
editingProviderId.value = id;
dialogOpen.value = true;
}
</script>

View File

@@ -200,6 +200,7 @@ import { useUserApi } from "~/composables/api";
import { useIngredientTextParser } from "~/composables/recipes";
import { useFoodData, useFoodStore, useUnitData, useUnitStore } from "~/composables/store";
import { useGlobalI18n } from "~/composables/use-global-i18n";
import { useGroupSelf } from "~/composables/use-groups";
import { alert } from "~/composables/use-toast";
import { useParsingPreferences } from "~/composables/use-users/preferences";
@@ -215,7 +216,7 @@ const emit = defineEmits<{
(e: "save", value: NoUndefinedField<RecipeIngredient[]>): void;
}>();
const { $appInfo } = useNuxtApp();
const { group } = useGroupSelf();
const i18n = useGlobalI18n();
const api = useUserApi();
const drag = ref(false);
@@ -240,7 +241,7 @@ const availableParsers = computed(() => {
{
text: i18n.t("recipe.parser.openai-parser"),
value: "openai",
hide: !$appInfo.enableOpenai,
hide: !group.value?.aiProviderSettings?.aiEnabled,
},
];
});

View File

@@ -10,24 +10,9 @@
}"
>
<v-row
v-touch="{
move: ({ originalEvent: { touches: [{ screenX, screenY }] } }) => {
swipeInfo.touchendX = screenX;
swipeInfo.touchendY = screenY;
},
start: ({ originalEvent: { touches: [{ screenX, screenY }] } }) => {
swipeInfo.touchstartX = screenX;
swipeInfo.touchstartY = screenY;
},
end: () => {
if (swiping < SWIPE_THRESHOLD) {
swipeInfo = {};
return;
}
swipeInfo = {};
toggleChecked();
},
}"
ref="swipeRowRef"
v-touch="{ move: onSwipeMove, start: onSwipeStart, end: onSwipeEnd }"
style="touch-action: pan-y;"
no-gutters
class="flex-nowrap align-center"
>
@@ -214,9 +199,23 @@ const emit = defineEmits<{
}>();
const SWIPE_THRESHOLD = 50;
const SCROLL_THRESHOLD = 50;
const { isRtl } = useRtl();
const swipeRowRef = ref<InstanceType<typeof import("vuetify/components").VRow> | null>(null);
onMounted(() => {
const el = swipeRowRef.value?.$el as HTMLElement | undefined;
if (!el) return;
el.addEventListener(
"touchmove",
(e: TouchEvent) => {
if (swipeInfo.value.gesture === "swipe") {
e.preventDefault();
}
},
{ passive: false },
);
});
const i18n = useI18n();
const displayRecipeRefs = ref(false);
const itemLabelCols = computed<string>(() => (model.value?.checked ? "auto" : "6"));
@@ -267,22 +266,66 @@ function save() {
edit.value = false;
}
const swipeInfo: Ref<{ touchstartX?: number; touchendX?: number; touchstartY?: number; touchendY?: number }> = ref({});
const swiping = computed(() => {
const { touchstartX, touchendX, touchstartY, touchendY } = swipeInfo.value ?? {};
if (touchstartX === undefined || touchendX === undefined) {
return 0;
}
const deltaX = isRtl.value ? touchstartX - touchendX : touchendX - touchstartX;
type SwipeGesture = null | "scroll" | "swipe";
// If there's significant vertical movement, treat as a scroll gesture and ignore
if (touchstartY !== undefined && touchendY !== undefined) {
const deltaY = Math.abs(touchendY - touchstartY);
if (deltaY > SCROLL_THRESHOLD) {
return 0;
const swipeInfo = ref({
touchstartX: 0,
touchstartY: 0,
touchendX: 0,
touchendY: 0,
gesture: null as SwipeGesture,
});
function getSwipePoint(e: any) {
const touch = e?.touches?.[0] ?? e?.changedTouches?.[0] ?? e;
return { x: touch?.clientX ?? 0, y: touch?.clientY ?? 0 };
}
function resetSwipe() {
swipeInfo.value = { touchstartX: 0, touchstartY: 0, touchendX: 0, touchendY: 0, gesture: null };
}
function onSwipeStart(payload: any) {
const { x, y } = getSwipePoint(payload.originalEvent);
swipeInfo.value = { touchstartX: x, touchstartY: y, touchendX: x, touchendY: y, gesture: null };
}
function onSwipeMove(payload: any) {
const { x, y } = getSwipePoint(payload.originalEvent);
swipeInfo.value.touchendX = x;
swipeInfo.value.touchendY = y;
if (!swipeInfo.value.gesture) {
const deltaX = Math.abs(x - swipeInfo.value.touchstartX);
const deltaY = Math.abs(y - swipeInfo.value.touchstartY);
if (deltaY > 8 && deltaY > deltaX) {
swipeInfo.value.gesture = "scroll";
}
else if (deltaX > 8 && deltaX > deltaY) {
swipeInfo.value.gesture = "swipe";
}
else if (deltaX > 8 || deltaY > 8) {
// Diagonal / ambiguous — default to scroll
swipeInfo.value.gesture = "scroll";
}
}
return Math.min(Math.max(0, deltaX), 100);
}
function onSwipeEnd() {
if (swipeInfo.value.gesture === "swipe" && swiping.value >= SWIPE_THRESHOLD) {
toggleChecked();
}
resetSwipe();
}
const swiping = computed(() => {
if (swipeInfo.value.gesture !== "swipe") {
return 0;
}
const deltaX = isRtl.value
? swipeInfo.value.touchstartX - swipeInfo.value.touchendX
: swipeInfo.value.touchendX - swipeInfo.value.touchstartX;
return Math.max(0, Math.min(deltaX, 100));
});
const recipeList = computed<RecipeSummary[]>(() => {

View File

@@ -4,7 +4,7 @@
style="border-color: lightgrey;"
:to="link.to"
height="100%"
class="d-flex flex-column mt-4"
class="d-flex flex-column mt-4 pa-2"
>
<div
v-if="$vuetify.display.smAndDown"

View File

@@ -96,15 +96,17 @@
<script setup lang="ts">
import { useLoggedInState } from "~/composables/use-logged-in-state";
import type { SideBarLink } from "~/types/application-types";
import { useGroupSelf } from "~/composables/use-groups";
import { useCookbookPreferences } from "~/composables/use-users/preferences";
import { useCookbookStore, usePublicCookbookStore } from "~/composables/store/use-cookbook-store";
import type { ReadCookBook } from "~/lib/api/types/cookbook";
const i18n = useI18n();
const { $appInfo, $globals } = useNuxtApp();
const { $globals } = useNuxtApp();
const display = useDisplay();
const auth = useMealieAuth();
const { isOwnGroup } = useLoggedInState();
const { group } = useGroupSelf();
const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug as string || auth.user.value?.groupSlug || "");
@@ -131,7 +133,7 @@ const cookbooks = computed(() => {
return [];
});
const showImageImport = computed(() => $appInfo.enableOpenaiImageServices);
const showImageImport = computed(() => group.value?.aiProviderSettings?.imageProviderEnabled);
const sidebar = ref<boolean>(false);
onMounted(() => {
@@ -205,7 +207,7 @@ const createLinks = computed(() => [
insertDivider: false,
icon: $globals.icons.fileImage,
title: i18n.t("recipe.create-from-images"),
subtitle: i18n.t("recipe.create-recipe-from-an-image"),
subtitle: i18n.t("recipe.create-recipe-from-images"),
to: `/g/${groupSlug.value}/r/create/image`,
restricted: true,
hide: !showImageImport.value,

View File

@@ -7,7 +7,8 @@
'mt-8': section,
}"
>
<v-card-title class="text-h5 pl-0 py-0" style="font-weight: normal;">
<v-card-title :class="`text-title-${size} pl-0 py-0 d-flex align-center`" style="font-weight: normal;">
<slot name="prepend-title" />
<v-icon
v-if="icon"
size="small"
@@ -16,6 +17,7 @@
{{ icon }}
</v-icon>
{{ title }}
<slot name="append-title" />
</v-card-title>
<v-card-text
v-if="$slots.default"
@@ -30,11 +32,17 @@
</template>
<script setup lang="ts">
type Size = "large" | "medium" | "small";
defineProps({
title: {
type: String,
required: true,
},
size: {
type: String as () => Size,
default: "large",
},
icon: {
type: String,
default: "",

View File

@@ -0,0 +1,127 @@
<template>
<div>
<div
v-for="(value, key) in (modelValue ?? {})"
:key="key"
class="d-flex align-center mb-2 gap-2"
>
<v-text-field
:model-value="key"
:label="resolvedKeyLabel"
density="compact"
variant="outlined"
hide-details
readonly
class="me-3 flex-grow-1"
/>
<v-text-field
:model-value="value"
:label="resolvedValueLabel"
density="compact"
variant="outlined"
hide-details
class="ms-3 flex-grow-1"
@update:model-value="updateValue(key, $event)"
/>
<v-btn
icon
variant="text"
color="error"
size="small"
@click="removeEntry(key)"
>
<v-icon>{{ $globals.icons.delete }}</v-icon>
</v-btn>
</div>
<div class="d-flex align-center mt-2 gap-2" @focusout="onNewEntryFocusOut">
<v-text-field
v-model="newKey"
:label="resolvedKeyLabel"
density="compact"
variant="outlined"
hide-details
class="me-3 flex-grow-1"
@keydown.enter.prevent="addEntry"
/>
<v-text-field
v-model="newValue"
:label="resolvedValueLabel"
density="compact"
variant="outlined"
hide-details
class="ms-3 flex-grow-1"
@keydown.enter.prevent="addEntry"
/>
<v-btn
icon
variant="text"
color="primary"
size="small"
:disabled="!newKey?.trim()"
@click="addEntry"
>
<v-icon>{{ $globals.icons.createAlt }}</v-icon>
</v-btn>
</div>
</div>
</template>
<script setup lang="ts">
import { useGlobalI18n } from "~/composables/use-global-i18n";
const i18n = useGlobalI18n();
const props = defineProps<{
modelValue?: Record<string, string> | null;
keyLabel?: string;
valueLabel?: string;
}>();
const emit = defineEmits<{
(e: "update:modelValue", value: Record<string, string>): void;
}>();
const { $globals } = useNuxtApp();
const resolvedKeyLabel = computed(() => props.keyLabel ?? i18n.t("general.key"));
const resolvedValueLabel = computed(() => props.valueLabel ?? i18n.t("general.value"));
const newKey = ref("");
const newValue = ref("");
function current(): Record<string, string> {
return { ...(props.modelValue ?? {}) };
}
function addEntry() {
const key = newKey.value?.trim();
if (!key) return;
const updated = current();
updated[key] = newValue.value;
emit("update:modelValue", updated);
newKey.value = "";
newValue.value = "";
}
function onNewEntryFocusOut(e: FocusEvent) {
const relatedTarget = e.relatedTarget as HTMLElement | null;
const currentTarget = e.currentTarget as HTMLElement;
if (!relatedTarget || !currentTarget.contains(relatedTarget)) {
addEntry();
}
}
function updateValue(key: string, value: string) {
const updated = current();
updated[key] = value;
emit("update:modelValue", updated);
}
function removeEntry(key: string) {
const updated = current();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete updated[key];
emit("update:modelValue", updated);
}
</script>

View File

@@ -0,0 +1,55 @@
import { useUserApi } from "~/composables/api";
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
export function useAIProviders() {
const api = useUserApi();
const loading = ref(false);
async function getOne(id: string) {
loading.value = true;
try {
return await api.aiProviders.getOne(id);
}
finally {
loading.value = false;
}
}
async function createOne(payload: AIProviderCreate) {
loading.value = true;
try {
return await api.aiProviders.createOne(payload);
}
finally {
loading.value = false;
}
}
async function updateOne(id: string, payload: AIProviderUpdate) {
loading.value = true;
try {
return await api.aiProviders.updateOne(id, payload);
}
finally {
loading.value = false;
}
}
async function deleteOne(id: string) {
loading.value = true;
try {
return await api.aiProviders.deleteOne(id);
}
finally {
loading.value = false;
}
}
return {
loading: readonly(loading),
getOne,
createOne,
updateOne,
deleteOne,
};
}

View File

@@ -22,7 +22,10 @@ const allAnnouncements: Announcement[] = Object.entries(_announcementsUnsorted)
.map(([path, mod]) => {
const key = path.split("/").at(-1)!.replace(".vue", "");
const parsed = new Date(key.split("_", 1)[0]!);
const dateParts = key.split("_", 1)[0]!.split("-").map(Number);
const parsed = dateParts.length === 3
? new Date(dateParts[0]!, dateParts[1]! - 1, dateParts[2]!)
: new Date(NaN);
const date = isNaN(parsed.getTime()) ? undefined : parsed;
return {

View File

@@ -42,6 +42,25 @@ export const useGroupSelf = function () {
return data || undefined;
},
async updateAIProviderSettings() {
if (!groupSelfRef.value) {
await refreshGroupSelf();
}
if (!groupSelfRef.value?.aiProviderSettings) {
return;
}
const { data } = await api.groups.setAIProviderSettings(groupSelfRef.value.aiProviderSettings);
if (data) {
groupSelfRef.value.aiProviderSettings = data;
}
return data || undefined;
},
async refresh() {
await refreshGroupSelf();
},
};
const group = actions.get();

View File

@@ -3,7 +3,7 @@ export const LOCALES = [
{
name: "繁體中文 (Chinese traditional)",
value: "zh-TW",
progress: 98,
progress: 97,
dir: "ltr",
pluralFoodHandling: "never",
},
@@ -24,21 +24,21 @@ export const LOCALES = [
{
name: "Українська (Ukrainian)",
value: "uk-UA",
progress: 86,
progress: 85,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "Türkçe (Turkish)",
value: "tr-TR",
progress: 54,
progress: 53,
dir: "ltr",
pluralFoodHandling: "never",
},
{
name: "Svenska (Swedish)",
value: "sv-SE",
progress: 75,
progress: 76,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -59,14 +59,14 @@ export const LOCALES = [
{
name: "Slovenčina (Slovak)",
value: "sk-SK",
progress: 61,
progress: 60,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "Pусский (Russian)",
value: "ru-RU",
progress: 59,
progress: 58,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -80,14 +80,14 @@ export const LOCALES = [
{
name: "Português (Portuguese)",
value: "pt-PT",
progress: 57,
progress: 56,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "Português do Brasil (Brazilian Portuguese)",
value: "pt-BR",
progress: 99,
progress: 98,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -101,7 +101,7 @@ export const LOCALES = [
{
name: "Norsk (Norwegian)",
value: "no-NO",
progress: 60,
progress: 59,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -129,7 +129,7 @@ export const LOCALES = [
{
name: "한국어 (Korean)",
value: "ko-KR",
progress: 55,
progress: 54,
dir: "ltr",
pluralFoodHandling: "never",
},
@@ -143,7 +143,7 @@ export const LOCALES = [
{
name: "Italiano (Italian)",
value: "it-IT",
progress: 73,
progress: 72,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -157,21 +157,21 @@ export const LOCALES = [
{
name: "Magyar (Hungarian)",
value: "hu-HU",
progress: 61,
progress: 62,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "Hrvatski (Croatian)",
value: "hr-HR",
progress: 42,
progress: 41,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "עברית (Hebrew)",
value: "he-IL",
progress: 73,
progress: 72,
dir: "rtl",
pluralFoodHandling: "always",
},
@@ -192,7 +192,7 @@ export const LOCALES = [
{
name: "Français canadien (Canadian French)",
value: "fr-CA",
progress: 90,
progress: 89,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -206,7 +206,7 @@ export const LOCALES = [
{
name: "Suomi (Finnish)",
value: "fi-FI",
progress: 99,
progress: 98,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -241,7 +241,7 @@ export const LOCALES = [
{
name: "Ελληνικά (Greek)",
value: "el-GR",
progress: 57,
progress: 58,
dir: "ltr",
pluralFoodHandling: "always",
},
@@ -269,28 +269,28 @@ export const LOCALES = [
{
name: "Català (Catalan)",
value: "ca-ES",
progress: 60,
progress: 59,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "Български (Bulgarian)",
value: "bg-BG",
progress: 71,
progress: 72,
dir: "ltr",
pluralFoodHandling: "always",
},
{
name: "العربية (Arabic)",
value: "ar-SA",
progress: 98,
progress: 97,
dir: "rtl",
pluralFoodHandling: "always",
},
{
name: "Afrikaans (Afrikaans)",
value: "af-ZA",
progress: 37,
progress: 36,
dir: "ltr",
pluralFoodHandling: "always",
},

View File

@@ -223,7 +223,9 @@
"show-advanced": "Wys uitgebreide",
"add-field": "Voeg veld by",
"date-created": "Datum Geskep",
"date-updated": "Datum Opgedateer"
"date-updated": "Datum Opgedateer",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Is jy seker jy wil <b>{groupName}<b/> uitvee?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Veranderinge aan hierdie groep sal onmiddellik weerspieël word.",
"group-id-value": "Groep-Id: {0}",
"total-households": "Total Households",
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Household",
@@ -628,7 +663,7 @@
"create-recipe-description": "Create a new recipe from scratch.",
"create-recipes": "Create Recipes",
"import-with-zip": "Voer in met .zip",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "إظهار متقدمة",
"add-field": "إضافة حقل",
"date-created": "تاريخ الإنشاء",
"date-updated": "تاريخ التحديث"
"date-updated": "تاريخ التحديث",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "هل انت متأكد من رغبتك في حذف <b>{groupName}<b/>؟",
@@ -283,7 +285,40 @@
"admin-group-management-text": "التغييرات التي ستطرأ على هذه المجموعة ستنعكس على الفور.",
"group-id-value": "معرف المجموعة: {0}",
"total-households": "مجموع المنزل",
"you-must-select-a-group-before-selecting-a-household": "يجب عليك تحديد مجموعة قبل تحديد المنزل"
"you-must-select-a-group-before-selecting-a-household": "يجب عليك تحديد مجموعة قبل تحديد المنزل",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "المنزل",
@@ -628,7 +663,7 @@
"create-recipe-description": "إنشاء وصفة جديدة من الصفر.",
"create-recipes": "إنشاء الوصفات",
"import-with-zip": "الاستيراد باستخدام zip.",
"create-recipe-from-an-image": "إنشاء وصفة عن طريق صورة",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "قم بقص الصورة وتدويرها بحيث يظهر النص فقط، ويكون في الاتجاه الصحيح.",
"create-from-images": "إنشاء عن طريق صور",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "أنا بالفعل جاهز، فقط أحضر ني إلى الصفحة الرئيسية",
"common-settings-for-new-sites": "فيما يلي بعض الإعدادات الشائعة للمواقع الجديدة",
"setup-complete": "تمت الإعدادات!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "إليك بعض الأشياء لمساعدتك على البدء مع ميالي",
"restore-from-v1-backup": "لديك نسخة احتياطية من مثيل سابق لـ Mealie v1؟ يمكنك استعادتها هنا.",
"manage-profile-or-get-invite-link": "إدارة الملف الشخصي الخاص بك، أو التقط رابط دعوة للمشاركة مع الآخرين."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Разширени настройки",
"add-field": "Добави поле",
"date-created": "Дата на създаване",
"date-updated": "Дата на актуализация"
"date-updated": "Дата на актуализация",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Сигурни ли сте, че искате да изтриете <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Промените по тази група ще бъдат отразени моментално.",
"group-id-value": "ID на Групата: {0}",
"total-households": "Общ брой домакинства",
"you-must-select-a-group-before-selecting-a-household": "Трябва да изберете група, преди да изберете домакинство"
"you-must-select-a-group-before-selecting-a-household": "Трябва да изберете група, преди да изберете домакинство",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Домакинство",
@@ -628,7 +663,7 @@
"create-recipe-description": "Създайте нова рецепта от чернова.",
"create-recipes": "Създайте рецепти",
"import-with-zip": "Импортирай от .zip",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Изрежете и завъртете изображението, така че да се вижда само текстът и той да е в правилната ориентация.",
"create-from-images": "Създаване от изображения",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Вече съм настроен, просто ме отведете до началната страница",
"common-settings-for-new-sites": "Ето някои общи настройки за нови сайтове",
"setup-complete": "Настройката е завършена!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Ето няколко неща, които ще Ви помогнат да започнете с Mealie",
"restore-from-v1-backup": "Имате резервно копие от предишна инстанция на Mealie v1? Можете да го възстановите тук.",
"manage-profile-or-get-invite-link": "Управлявайте собствения си профил или вземете връзка за покана, която да споделите с други."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostrar els paràmetres avançats",
"add-field": "Afegir camp",
"date-created": "Data de creació",
"date-updated": "Data dactualització"
"date-updated": "Data dactualització",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Esteu segur de voler suprimir el grup <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Els canvis en aquest grup s'actualitzaran immediatament.",
"group-id-value": "ID del grup: {0}",
"total-households": "Llars totals",
"you-must-select-a-group-before-selecting-a-household": "Heu de seleccionar un grup abans de seleccionar una llar"
"you-must-select-a-group-before-selecting-a-household": "Heu de seleccionar un grup abans de seleccionar una llar",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Llar",
@@ -628,7 +663,7 @@
"create-recipe-description": "Crea una nova recepta des de zero.",
"create-recipes": "Crea Receptes",
"import-with-zip": "Importar amb un .zip",
"create-recipe-from-an-image": "Crear una recepta a partir d'una imatge",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Crear una recepta pujant una imatge d'ella. Mealie intentarà extreure el text de la imatge mitjançant IA i crear-ne la recepta.",
"crop-and-rotate-the-image": "Retalla i rota la imatge, per tal que només el text sigui visible, i estigui orientat correctament.",
"create-from-images": "Crear una recepta a partir d'una imatge",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Ja ho tinc configurat, porta'm a la pàgina principal",
"common-settings-for-new-sites": "Aquí hi ha algunes configuracions comunes per noves pàgines",
"setup-complete": "Configuració completada!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aquí hi ha unes quantes coses per ajudar-te a posar Mealie en marxa",
"restore-from-v1-backup": "Tens una còpia de seguretat d'una instància prèvia de Mealie v1? Pots restaurar-la aquí.",
"manage-profile-or-get-invite-link": "Gestiona el teu propi perfil, o agafa un enllaç d'invitació per compartir amb altres."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Zobrazit pokročilé",
"add-field": "Přidat pole",
"date-created": "Datum vytvoření",
"date-updated": "Datum aktualizace"
"date-updated": "Datum aktualizace",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Jste si jisti, že chcete smazat <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Změny v této skupině budou okamžitě zohledněny.",
"group-id-value": "ID skupiny: {0}",
"total-households": "Celkem domácností",
"you-must-select-a-group-before-selecting-a-household": "Před výběrem domácnosti musíte vybrat skupinu"
"you-must-select-a-group-before-selecting-a-household": "Před výběrem domácnosti musíte vybrat skupinu",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Domácnost",
@@ -628,7 +663,7 @@
"create-recipe-description": "Vytvořit nový recept od nuly.",
"create-recipes": "Vytvořit recepty",
"import-with-zip": "Importovat pomocí .zip",
"create-recipe-from-an-image": "Vytvořit recept z obrázku",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Vytvořte recept nahráním obrázku. Mealie se pokusí z obrázku extrahovat text pomocí AI a vytvořit z něj recept.",
"crop-and-rotate-the-image": "Oříznout a otočit obrázek tak, aby byl viditelný pouze text a aby byl ve správné orientaci.",
"create-from-images": "Vytvořit z obrázků",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Již mám nastaveno, vezmi mě na domovskou stránku",
"common-settings-for-new-sites": "Zde jsou některá běžná nastavení pro nové stránky",
"setup-complete": "Nastavení dokončeno!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Zde je několik věcí, které vám pomohou začít s Mealie",
"restore-from-v1-backup": "Máte zálohu z předchozí instance Mealie v1? Můžete ji obnovit zde.",
"manage-profile-or-get-invite-link": "Spravujte svůj vlastní profil, nebo přidejte pozvánku ke sdílení s ostatními."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Vis avanceret",
"add-field": "Tilføj felt",
"date-created": "Oprettet",
"date-updated": "Opdateret"
"date-updated": "Opdateret",
"key": "Nøgle",
"value": "Værdi"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Er du sikker på, du vil slette <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Ændringer i denne gruppe vil træde i kraft øjeblikkeligt.",
"group-id-value": "Gruppe-ID: {0}",
"total-households": "Husstande i Alt",
"you-must-select-a-group-before-selecting-a-household": "Du skal vælge en gruppe, før du vælger en husstand"
"you-must-select-a-group-before-selecting-a-household": "Du skal vælge en gruppe, før du vælger en husstand",
"ai-provider-settings": {
"ai-provider-settings": "AI-udbyderindstillinger",
"ai-provider": "AI-udbyder",
"ai-providers": "AI-udbydere",
"ai-provider-settings-description": "Konfigurér AI-udbydere for at slå AI-funktioner til, såsom forbedret ingredienshåndtering, at oprette opskrifter fra videoer med mere.",
"providers": "Udbydere",
"create-provider": "Opret udbyder",
"edit-provider": "Redigér udbyder",
"default-provider": "Standardudbyder",
"default-provider-description": "Påkrævet for at slå AI-funktioner til",
"audio-provider": "Lydudbyder",
"audio-provider-description": "Slå lydtranskriberingsfunktioner til, såsom at oprette opskrifter fra videoer",
"image-provider": "Billedudbyder",
"image-provider-description": "Slår billedgenkendelsesfunktioner til, såsom at oprette opskrifter fra billeder",
"provider-name": "Udbydernavn",
"api-key": "API-nøgle",
"api-key-description-create": "Din udbyders API-nøgle til godkendelse. Hvis din udbyder ikke benytter en API-nøgle (eks. Ollama), skal du stadig skrive ét eller andet,",
"api-key-description-edit": "Undlad at udfylde dette, medmindre du vil ændre det.",
"base-url": "Basis-URL",
"base-url-description": "Undlad at udfylde, hvis du benytter OpenAI. Skal være et OpenAI-kompatibelt endpoint (eks. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Hvilken model skal din udbyder benytte (eks. \"gpt-5\")?",
"request-timeout-seconds": "Forespørgsels-time-out",
"provider-created": "Udbyder oprettet",
"provider-updated": "Udbyder opdateret",
"provider-deleted": "Udbyder slettet",
"provider-create-failed": "Kunne ikke oprette udbyder",
"provider-update-failed": "Kunne ikke opdatere udbyder",
"provider-delete-failed": "Kunne ikke slette udbyder",
"request-headers": "Forespørgsels-headers",
"request-params": "Forespørgselsparametre",
"no-default-provider-warning": "Du har ikke sat en standardudbyder, så AI-funktioner er slået fra"
}
},
"household": {
"household": "Husstand",
@@ -628,7 +663,7 @@
"create-recipe-description": "Opret ny opskrift fra bunden.",
"create-recipes": "Opret opskrift",
"import-with-zip": "Importér fra ZIP-fil",
"create-recipe-from-an-image": "Opret opskrift fra et billede",
"create-recipe-from-images": "Opret opskrift fra billeder",
"create-recipe-from-an-image-description": "Opret en opskrift ved at overføre et billede af den. Mealie vil forsøge at udtrække teksten fra billedet med AI og oprette en opskrift fra det.",
"crop-and-rotate-the-image": "Beskær og roter billedet, så kun teksten er synlig, og det vises i den rigtige retning.",
"create-from-images": "Opret fra billede",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jeg er allerede oprettet, bare bringe mig til startsiden",
"common-settings-for-new-sites": "Her er nogle almindelige indstillinger for nye sites",
"setup-complete": "Opsætning færdig!",
"ai-providers-description": "Konfigurér valgfrit AI-udbydere for din gruppe. AI-udbydere muliggør handlinger, såsom at oprette opskrifter fra billeder, importere opskrifter fra videoer, og forbedret håndtering af ingredienser. Det er altid muligt at konfigurere dette senere under dine gruppeindstillinger.",
"here-are-a-few-things-to-help-you-get-started": "Her er et par ting, der kan hjælpe dig i gang med Mealie",
"restore-from-v1-backup": "Har du en sikkerhedskopi fra en tidligere udgave af Mealie v1? Du kan gendanne den her.",
"manage-profile-or-get-invite-link": "Administrer din egen profil, eller tag et invitationslink til at dele med andre."

View File

@@ -169,7 +169,7 @@
"token": "Token",
"tuesday": "Dienstag",
"type": "Typ",
"undo": "Undo",
"undo": "Rückgängig",
"update": "Aktualisieren",
"updated": "Aktualisiert",
"upload": "Hochladen",
@@ -223,7 +223,9 @@
"show-advanced": "Erweiterte Optionen anzeigen",
"add-field": "Feld Hinzufügen",
"date-created": "Erstellungsdatum",
"date-updated": "Aktualisiert am"
"date-updated": "Aktualisiert am",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Bist du dir sicher, dass du die Gruppe <b>{groupName}<b/> löschen möchtest?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Änderungen an dieser Gruppe sind sofort wirksam.",
"group-id-value": "Gruppen ID: {0}",
"total-households": "Haushalte insgesamt",
"you-must-select-a-group-before-selecting-a-household": "Du musst eine Gruppe auswählen, bevor du einen Haushalt auswählst"
"you-must-select-a-group-before-selecting-a-household": "Du musst eine Gruppe auswählen, bevor du einen Haushalt auswählst",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Haushalt",
@@ -628,7 +663,7 @@
"create-recipe-description": "Erstelle ein neues Rezept von Grund auf.",
"create-recipes": "Rezepte erstellen",
"import-with-zip": "Von .zip importieren",
"create-recipe-from-an-image": "Rezept von einem Bild erstellen",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Erstelle ein Rezept, indem du ein Bild hochlädst. Mealie wird versuchen, den Text aus dem Bild mit Hilfe von KI zu extrahieren und ein Rezept daraus zu erstellen.",
"crop-and-rotate-the-image": "Beschneide und drehe das Bild so, dass nur der Text zu sehen ist und die Ausrichtung stimmt.",
"create-from-images": "Aus Bildern erstellen",
@@ -917,7 +952,7 @@
"quantity": "Menge: {0}",
"shopping-list": "Einkaufsliste",
"shopping-lists": "Einkaufslisten",
"add-item": "Add item",
"add-item": "Eintrag hinzufügen",
"food": "Lebensmittel",
"note": "Notiz",
"label": "Kategorie",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Ich habe schon alles eingerichtet, bring mich zur Startseite",
"common-settings-for-new-sites": "Hier sind einige allgemeine Einstellungen für neue Seiten",
"setup-complete": "Einrichtung abgeschlossen!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Hier sind einige Funktionen, die dich beim Start mit Mealie unterstützen",
"restore-from-v1-backup": "Hast du ein Backup von einer früheren v1 Instanz von Mealie? Hier kannst du es wiederherstellen.",
"manage-profile-or-get-invite-link": "Verwalte dein eigenes Profil oder erstelle einen Einladungslink, den du an andere weitergeben kannst."
@@ -1478,10 +1514,10 @@
"max-length": "Muss maximal {max} Zeichen haben|Muss maximal {max} Zeichen haben"
},
"announcements": {
"announcements": "Announcements",
"all-announcements": "All announcements",
"announcements": "Ankündigungen",
"all-announcements": "Alle Ankündigungen",
"mark-all-as-read": "Alle als gelesen markieren",
"show-announcements-from-mealie": "Show announcements from Mealie",
"show-announcements-setting-description": "Whether or not you want to allow users to see announcements from Mealie. When enabled users can still opt-out from seeing them in their user settings"
"show-announcements-from-mealie": "Ankündigung von Mealie anzeigen",
"show-announcements-setting-description": "Lege fest, ob Benutzer Ankündigungen von Mealie sehen dürfen. Wenn aktiviert, können Benutzer die Anzeige in ihren Benutzereinstellungen immer noch deaktivieren"
}
}

View File

@@ -169,7 +169,7 @@
"token": "Token",
"tuesday": "Τρίτη",
"type": "Τύπος",
"undo": "Undo",
"undo": "Αναίρεση",
"update": "Ενημέρωση",
"updated": "Ενημερώθηκε",
"upload": "Ανέβασμα",
@@ -223,7 +223,9 @@
"show-advanced": "Εμφάνιση προχωρημένων επιλογών",
"add-field": "Προσθήκη πεδίου",
"date-created": "Ημερομηνία δημιουργίας",
"date-updated": "Ημερομηνία ενημέρωσης"
"date-updated": "Ημερομηνία ενημέρωσης",
"key": "Κλειδί",
"value": "Τιμή"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Θέλετε σίγουρα να διαγράψετε αυτό τον ασφαλή σύνδεσμο <b>{groupName}<b/>;",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Οι αλλαγές σε αυτή την ομάδα θα αντικατοπτρίζονται αμέσως.",
"group-id-value": "ID ομάδας: {0}",
"total-households": "Σύνολο νοικοκυριών",
"you-must-select-a-group-before-selecting-a-household": "Πρέπει να επιλέξετε μια ομάδα πριν επιλέξετε ένα νοικοκυριό"
"you-must-select-a-group-before-selecting-a-household": "Πρέπει να επιλέξετε μια ομάδα πριν επιλέξετε ένα νοικοκυριό",
"ai-provider-settings": {
"ai-provider-settings": "Ρυθμίσεις παρόχου τεχνητής νοημοσύνης",
"ai-provider": "Πάροχος τεχνητής νοημοσύνης",
"ai-providers": "Πάροχοι τεχνητής νοημοσύνης",
"ai-provider-settings-description": "Ρυθμίστε τους παρόχους τεχνητής νοημοσύνης για να ενεργοποιήσετε τις λειτουργίες AI, όπως βελτιωμένη ανάλυση συστατικών, δημιουργία συνταγών από βίντεο και πολλά άλλα!",
"providers": "Πάροχοι",
"create-provider": "Δημιουργία παρόχου",
"edit-provider": "Επεξεργασία παρόχου",
"default-provider": "Προεπιλεγμένος πάροχος",
"default-provider-description": "Απαιτείται για την ενεργοποίηση των χαρακτηριστικών τεχνητής νοημοσύνης",
"audio-provider": "Πάροχος ήχου",
"audio-provider-description": "Ενεργοποιεί λειτουργίες μεταγραφής ήχου, όπως η δημιουργία συνταγών από βίντεο",
"image-provider": "Πάροχος εικόνων",
"image-provider-description": "Ενεργοποιεί δυνατότητες αναγνώρισης εικόνας, όπως η δημιουργία συνταγών από εικόνες",
"provider-name": "Ονομα παρόχου",
"api-key": "Κλειδί API",
"api-key-description-create": "Το κλειδί API του παρόχου σας για έλεγχο ταυτότητας. Αν η υπηρεσία σας (π.χ. Ollama) δεν χρησιμοποιεί ένα κλειδί API, πρέπει να βάλετε κάτι εδώ.",
"api-key-description-edit": "Αφήστε το κενό εκτός αν θέλετε να το αλλάξετε.",
"base-url": "Βασική διεύθυνση URL",
"base-url-description": "Αν χρησιμοποιείτε το OpenAI αφήστε αυτό το κενό. Πρέπει να είναι ένα OpenAI συμβατό endpoint (π.χ. \"http://localhost:11434/v1\").",
"model": "Μοντέλο",
"model-description": "Ποιο μοντέλο θα πρέπει να χρησιμοποιήσει ο πάροχος τεχνητής νοημοσύνης σας (π.χ. \"gpt-5\").",
"request-timeout-seconds": "Χρονικό όριο αιτήματος (δευτερόλεπτα)",
"provider-created": "Ο πάροχος δημιουργήθηκε",
"provider-updated": "Ο πάροχος ενημερώθηκε",
"provider-deleted": "Ο πάροχος διαγράφτηκε",
"provider-create-failed": "Αποτυχία δημιουργίας παρόχου",
"provider-update-failed": "Αποτυχία ενημέρωσης παρόχου",
"provider-delete-failed": "Αποτυχία διαγραφής παρόχου",
"request-headers": "Κεφαλίδες αιτήματος",
"request-params": "Παράμετροι αιτήματος",
"no-default-provider-warning": "Δεν έχετε ορίσει προεπιλεγμένο πάροχο, οπότε οι λειτουργίες τεχνητής νοημοσύνης είναι απενεργοποιημένες"
}
},
"household": {
"household": "Νοικοκυριό",
@@ -628,7 +663,7 @@
"create-recipe-description": "Δημιουργήστε μια νέα συνταγή από το μηδέν.",
"create-recipes": "Δημιουργία Συνταγών",
"import-with-zip": "Εισαγωγή μέσω .zip",
"create-recipe-from-an-image": "Δημιουργία συνταγής από μια εικόνα",
"create-recipe-from-images": "Δημιουργία συνταγής από εικόνες",
"create-recipe-from-an-image-description": "Δημιουργήστε μια συνταγή ανεβάζοντας μια εικόνα της. Το Mealie θα προσπαθήσει να εξάγει το κείμενο από την εικόνα χρησιμοποιώντας τεχνητή νοημοσύνη και να δημιουργήσει μια συνταγή από αυτό.",
"crop-and-rotate-the-image": "Περικοπή και περιστροφή της εικόνας, έτσι ώστε να είναι μόνο το κείμενο ορατό και να είναι στο σωστό προσανατολισμό.",
"create-from-images": "Δημιουργία από εικόνες",
@@ -917,7 +952,7 @@
"quantity": "Ποσότητα: {0}",
"shopping-list": "Λίστα για ψώνια",
"shopping-lists": "Λίστες για ψώνια",
"add-item": "Add item",
"add-item": "Προσθήκη στοιχείου",
"food": "Τρόφιμο",
"note": "Σημείωση",
"label": "Ετικέτα",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Εχω ήδη κάνει εγκατάσταση, απλά πήγαινέ με στην αρχική σελίδα",
"common-settings-for-new-sites": "Εδώ είναι μερικές κοινές ρυθμίσεις για νέους ιστότοπους",
"setup-complete": "Η εγκατάσταση ολοκληρώθηκε!",
"ai-providers-description": "Προαιρετικά ρυθμίστε τους παρόχους τεχνητής νοημοσύνης για την ομάδα σας. Οι πάροχοι τεχνητής νοημοσύνης ενεργοποιούν λειτουργίες όπως η δημιουργία συνταγών από εικόνες, η εισαγωγή συνταγών από βίντεο και η βελτιωμένη ανάλυση συστατικών. Αυτό μπορείτε πάντα να το διαμορφώσετε αργότερα από τις ρυθμίσεις της ομάδας σας.",
"here-are-a-few-things-to-help-you-get-started": "Εδώ είναι μερικά πράγματα που θα σας βοηθήσουν να ξεκινήσετε με το Mealie",
"restore-from-v1-backup": "Εχετε ένα αντίγραφο ασφαλείας από μια προηγούμενη υπόσταση του Mealie v1; Μπορείτε να το επαναφέρετε εδώ.",
"manage-profile-or-get-invite-link": "Διαχειριστείτε το δικό σας προφίλ, ή λάβετε έναν σύνδεσμο πρόσκλησης για να μοιραστείτε με άλλους."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Show Advanced",
"add-field": "Add Field",
"date-created": "Date Created",
"date-updated": "Date Updated"
"date-updated": "Date Updated",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Changes to this group will be reflected immediately.",
"group-id-value": "Group ID: {0}",
"total-households": "Total Households",
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Household",
@@ -628,7 +663,7 @@
"create-recipe-description": "Create a new recipe from scratch.",
"create-recipes": "Create Recipes",
"import-with-zip": "Import with .zip",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Show Advanced",
"add-field": "Add Field",
"date-created": "Date Created",
"date-updated": "Date Updated"
"date-updated": "Date Updated",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Changes to this group will be reflected immediately.",
"group-id-value": "Group Id: {0}",
"total-households": "Total Households",
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Household",
@@ -628,7 +663,7 @@
"create-recipe-description": "Create a new recipe from scratch.",
"create-recipes": "Create Recipes",
"import-with-zip": "Import with .zip",
"create-recipe-from-an-image": "Create Recipe from Images",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading images of the recipe text. Mealie will attempt to extract the text from the images using AI and create a new recipe from it.",
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,8 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostrar Avanzado",
"add-field": "Añadir campo",
"date-created": "Fecha de creación",
"date-updated": "Fecha de actualización"
"date-updated": "Fecha de actualización",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Por favor, confirma que deseas eliminar <b>{groupName}<b/>",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Los cambios en este grupo se reflejarán inmediatamente.",
"group-id-value": "Id del Grupo: {0}",
"total-households": "Total de Casas",
"you-must-select-a-group-before-selecting-a-household": "Debe seleccionar un grupo antes de seleccionar un hogar"
"you-must-select-a-group-before-selecting-a-household": "Debe seleccionar un grupo antes de seleccionar un hogar",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Casa",
@@ -628,7 +663,7 @@
"create-recipe-description": "Crear nueva receta desde cero.",
"create-recipes": "Crear Recetas",
"import-with-zip": "Importar desde .zip",
"create-recipe-from-an-image": "Crear receta a partir de una imagen",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Crea una receta cargando una imagen de ella. Mealie intentará extraer el texto de la imagen usando IA y crear una receta de ella.",
"crop-and-rotate-the-image": "Recortar y rotar la imagen de manera que sólo el texto sea visible, y esté en la orientación correcta.",
"create-from-images": "Crear a partir de imágenes",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Estoy bien, solo llévame al Inicio",
"common-settings-for-new-sites": "Aquí hay algunos ajustes comunes para sitios nuevos",
"setup-complete": "¡Configuración completada!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aquí hay algunas cosas para ayudarte a empezar con Mealie",
"restore-from-v1-backup": "¿Tienes una copia de seguridad de Mealie v1? Puedes restaurarla aquí.",
"manage-profile-or-get-invite-link": "Gestiona tu perfil, o usa un enlace de invitación para compartir con otros."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Kuva täpsemad sätted",
"add-field": "Lisa väli",
"date-created": "Loomise kuupäev",
"date-updated": "Üleslaadimise kuupäev"
"date-updated": "Üleslaadimise kuupäev",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Kas oled kindel, et tahad kustutada <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Selle grupi muudatused on koheselt nähtavad",
"group-id-value": "Grupi ID: {0}",
"total-households": "Kokku leibkondi",
"you-must-select-a-group-before-selecting-a-household": "Sa pead valima grupi enne leibkonna valimist"
"you-must-select-a-group-before-selecting-a-household": "Sa pead valima grupi enne leibkonna valimist",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Leibkond",
@@ -628,7 +663,7 @@
"create-recipe-description": "Loo uus retsept algusest",
"create-recipes": "Loo retseptid",
"import-with-zip": "Impordi .zip failist",
"create-recipe-from-an-image": "Retsepti loomine pildist",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Retsepti loomiseks lae üles selle pilt. Mealie üritab ekstraheerida pildil oleva teksti ning luua retsepti sellest kasutades AI-d.",
"crop-and-rotate-the-image": "Kärpige ja pöörake pilti nii, et ainult tekst oleks nähtaval ja see oleks suunatud ülespoole.",
"create-from-images": "Retsepti loomine pildist",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Ma olen juba vajalikud asjad seadistanud, vii mind pealehele",
"common-settings-for-new-sites": "Siin on mõned harilikud sätted uute lehekülgede jaoks",
"setup-complete": "Seadistus valmis!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Siin on mõned asjad mis aitavad sul teha algust Mealie-ga",
"restore-from-v1-backup": "Kas sul on tagavarakoopia varasemast Mealie v1 instantsist? Sa saad taastada selle siin.",
"manage-profile-or-get-invite-link": "Halda oma profiili, või haara kutselink teistega jagamiseks."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Näytä Lisäasetukset",
"add-field": "Lisää Kenttä",
"date-created": "Luontipäivä",
"date-updated": "Päivitetty"
"date-updated": "Päivitetty",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Haluatko varmasti poistaa ryhmän <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Muutokset tähän ryhmään tulevat näkymään välittömästi.",
"group-id-value": "Ryhmän tunniste: {0}",
"total-households": "Kotitaloudet Yhteensä",
"you-must-select-a-group-before-selecting-a-household": "Sinun tulee valita ryhmä ennen kuin valitset kotitalouden"
"you-must-select-a-group-before-selecting-a-household": "Sinun tulee valita ryhmä ennen kuin valitset kotitalouden",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Kotitalous",
@@ -628,7 +663,7 @@
"create-recipe-description": "Luo resepti alusta.",
"create-recipes": "Luo reseptejä",
"import-with-zip": "Tuo .zip:llä",
"create-recipe-from-an-image": "Luo resepti kuvasta",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Luo resepti tuomalla siitä kuva. Mealie pyrkii poimimaan tekstin kuvasta tekoälyllä ja luomaan siitä reseptin.",
"crop-and-rotate-the-image": "Rajaa ja kierrä kuvaa niin, että vain teksti näkyy, ja että se on oikein päin.",
"create-from-images": "Luo resepti kuvasta",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Olen jo valmis, vie minut kotisivulle",
"common-settings-for-new-sites": "Tässä muutamia yleisiä asetuksia uusille sivustoille",
"setup-complete": "Asennus valmis.",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Näillä muutamilla asioilla pääset alkuun",
"restore-from-v1-backup": "Onko sinulla varmuuskopio aiemmasta Mealie v1 -instanssista? Palauta se tästä.",
"manage-profile-or-get-invite-link": "Hallitse profiiliasi tai hanki kutsulinkki muille."

View File

@@ -169,7 +169,7 @@
"token": "Jeton",
"tuesday": "Mardi",
"type": "Type",
"undo": "Undo",
"undo": "Annuler",
"update": "Mettre à jour",
"updated": "Mis à jour",
"upload": "Importer",
@@ -223,7 +223,9 @@
"show-advanced": "Afficher les paramètres avancés",
"add-field": "Ajouter un champ",
"date-created": "Date de création",
"date-updated": "Date de mise à jour"
"date-updated": "Date de mise à jour",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Voulez-vous vraiment supprimer <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Les modifications apportées à ce groupe seront immédiatement prises en compte.",
"group-id-value": "ID groupe: {0}",
"total-households": "Nombre de foyers",
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer"
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Foyer",
@@ -628,7 +663,7 @@
"create-recipe-description": "Créer une nouvelle recette de zéro.",
"create-recipes": "Créer des recettes",
"import-with-zip": "Importer un .zip",
"create-recipe-from-an-image": "Créer une recette à partir dune image",
"create-recipe-from-images": "Créer une recette depuis une image",
"create-recipe-from-an-image-description": "Créez une recette en téléchargeant une image de celle-ci. Mealie utilisera lIA pour tenter dextraire le texte et de créer une recette.",
"crop-and-rotate-the-image": "Rogner et pivoter limage pour que seul le texte soit visible, et quil soit dans la bonne orientation.",
"create-from-images": "Créer à partir dune image",
@@ -943,7 +978,7 @@
"are-you-sure-you-want-to-uncheck-all-items": "Voulez-vous vraiment désélectionner tous les éléments ?",
"are-you-sure-you-want-to-delete-checked-items": "Voulez-vous vraiment supprimer tous les éléments sélectionnés ?",
"no-shopping-lists-found": "Aucune liste de courses trouvée",
"item-checked-off": "Checked off {item}"
"item-checked-off": "{item} coché"
},
"sidebar": {
"all-recipes": "Recettes",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jai déjà tout configuré, amenez moi à lécran daccueil",
"common-settings-for-new-sites": "Voici quelques paramètres courants pour les nouveaux sites",
"setup-complete": "Configuration terminée !",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Voici quelques trucs pour vous aider à commencer avec Mealie",
"restore-from-v1-backup": "Vous avez une sauvegarde dune précédente instance de Mealie v1 ? Vous pouvez la restaurer ici.",
"manage-profile-or-get-invite-link": "Gérez votre propre profil, ou récupérez un lien dinvitation à partager avec dautres."

View File

@@ -169,7 +169,7 @@
"token": "Jeton",
"tuesday": "Mardi",
"type": "Type",
"undo": "Undo",
"undo": "Annuler",
"update": "Mettre à jour",
"updated": "Mis à jour",
"upload": "Importer",
@@ -223,7 +223,9 @@
"show-advanced": "Afficher les paramètres avancés",
"add-field": "Ajouter un champ",
"date-created": "Date de création",
"date-updated": "Date de mise à jour"
"date-updated": "Date de mise à jour",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Êtes-vous certain de vouloir supprimer <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Les modifications apportées à ce groupe seront immédiatement prises en compte.",
"group-id-value": "ID groupe: {0}",
"total-households": "Nombre de foyers",
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer"
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Foyer",
@@ -628,7 +663,7 @@
"create-recipe-description": "Créer une nouvelle recette à partir de zéro.",
"create-recipes": "Créer des recettes",
"import-with-zip": "Importer un .zip",
"create-recipe-from-an-image": "Créer une recette à partir dune image",
"create-recipe-from-images": "Créer une recette depuis une image",
"create-recipe-from-an-image-description": "Créez une recette en téléversant une image de celle-ci. Mealie utilisera lIA pour tenter dextraire le texte et de créer une recette.",
"crop-and-rotate-the-image": "Rogner et pivoter limage pour que seul le texte soit visible et quil soit dans la bonne orientation.",
"create-from-images": "Créer à partir dimages",
@@ -943,7 +978,7 @@
"are-you-sure-you-want-to-uncheck-all-items": "Voulez-vous vraiment désélectionner tous les éléments ?",
"are-you-sure-you-want-to-delete-checked-items": "Voulez-vous vraiment supprimer tous les éléments sélectionnés ?",
"no-shopping-lists-found": "Aucune liste de courses trouvée",
"item-checked-off": "Checked off {item}"
"item-checked-off": "{item} coché"
},
"sidebar": {
"all-recipes": "Les recettes",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jai déjà tout configuré, amenez moi à lécran daccueil",
"common-settings-for-new-sites": "Voici quelques paramètres communs pour les nouveaux sites",
"setup-complete": "Configuration terminée!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Voici quelques trucs pour vous aider à commencer avec Mealie",
"restore-from-v1-backup": "Vous avez une sauvegarde dune précédente instance de Mealie v1 ? Vous pouvez la restaurer ici.",
"manage-profile-or-get-invite-link": "Gérez votre propre profil, ou récupérez un lien dinvitation à partager avec dautres."

View File

@@ -169,7 +169,7 @@
"token": "Jeton",
"tuesday": "Mardi",
"type": "Type",
"undo": "Undo",
"undo": "Annuler",
"update": "Mettre à jour",
"updated": "Mis à jour",
"upload": "Importer",
@@ -223,7 +223,9 @@
"show-advanced": "Afficher les paramètres avancés",
"add-field": "Ajouter un champ",
"date-created": "Date de création",
"date-updated": "Date de mise à jour"
"date-updated": "Date de mise à jour",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Voulez-vous vraiment supprimer <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Les modifications apportées à ce groupe seront immédiatement prises en compte.",
"group-id-value": "ID groupe: {0}",
"total-households": "Nombre de foyers",
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer"
"you-must-select-a-group-before-selecting-a-household": "Vous devez sélectionner un groupe avant de sélectionner un foyer",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Foyer",
@@ -628,7 +663,7 @@
"create-recipe-description": "Créer une nouvelle recette de zéro.",
"create-recipes": "Créer des recettes",
"import-with-zip": "Importer un .zip",
"create-recipe-from-an-image": "Créer une recette à partir dune image",
"create-recipe-from-images": "Créer une recette depuis une image",
"create-recipe-from-an-image-description": "Créez une recette en téléchargeant une image de celle-ci. Mealie utilisera lIA pour tenter dextraire le texte et de créer une recette.",
"crop-and-rotate-the-image": "Rogner et pivoter limage pour que seul le texte soit visible, et quil soit dans la bonne orientation.",
"create-from-images": "Créer à partir dimages",
@@ -943,7 +978,7 @@
"are-you-sure-you-want-to-uncheck-all-items": "Voulez-vous vraiment désélectionner tous les éléments ?",
"are-you-sure-you-want-to-delete-checked-items": "Voulez-vous vraiment supprimer tous les éléments sélectionnés ?",
"no-shopping-lists-found": "Aucune liste de courses trouvée",
"item-checked-off": "Checked off {item}"
"item-checked-off": "{item} coché"
},
"sidebar": {
"all-recipes": "Recettes",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jai déjà tout configuré, amenez-moi à lécran daccueil",
"common-settings-for-new-sites": "Voici quelques paramètres courants pour les nouveaux sites",
"setup-complete": "Configuration terminée !",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Voici quelques trucs pour vous aider à commencer avec Mealie",
"restore-from-v1-backup": "Vous avez une sauvegarde dune précédente instance de Mealie v1 ? Vous pouvez la restaurer ici.",
"manage-profile-or-get-invite-link": "Gérez votre propre profil, ou récupérez un lien dinvitation à partager avec dautres."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostrar Avanzadas",
"add-field": "Adicionar Campo",
"date-created": "Data de Creación",
"date-updated": "Data de Atualización"
"date-updated": "Data de Atualización",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Estás seguro de que queres eliminar <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Os cambios neste grupo reflectiranse inmediatamente.",
"group-id-value": "Id do grupo: {0}",
"total-households": "Casas Totais",
"you-must-select-a-group-before-selecting-a-household": "Tes que selecionar un grupo antes de selecionar unha casa"
"you-must-select-a-group-before-selecting-a-household": "Tes que selecionar un grupo antes de selecionar unha casa",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Casa",
@@ -628,7 +663,7 @@
"create-recipe-description": "Crear unha receita en branco.",
"create-recipes": "Crear Receitas",
"import-with-zip": "Importar con .zip",
"create-recipe-from-an-image": "Crear receita a partir dunha imaxen",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Cree unha receita cargando unha imaxen da mesma. O Mealie tentará extrair o texto da imaxen utilizando IA e creará unha receita a partir da mesma.",
"crop-and-rotate-the-image": "Recorte e vire a imaxen de modo a que só o texto sexa visível e na orientación correta.",
"create-from-images": "Crear a partir de imaxens",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Xa estou listo, levame para a páxina inicial",
"common-settings-for-new-sites": "Aqui están algunhas configuracións comuns para sites novos",
"setup-complete": "Configuración Concluída!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aqui están algunhas cousas para axudar a comezar co Mealie",
"restore-from-v1-backup": "Ten unha copia de seguranza dunha instancia do Mealie v1? Pode restaurala aqui.",
"manage-profile-or-get-invite-link": "Xestione o seu proprio perfil ou obteña unha ligazón de convite para compartir con outras persoas."

View File

@@ -223,7 +223,9 @@
"show-advanced": "הצג הגדרות מתקדמות",
"add-field": "הוסף שדה",
"date-created": "תאריך יצירה",
"date-updated": "תאריך עדכון"
"date-updated": "תאריך עדכון",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "למחוק את <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "שינויים לקבוצה זו ישתקפו מיידית.",
"group-id-value": "מזהה קבוצה: {0}",
"total-households": "סך כל משקי בית",
"you-must-select-a-group-before-selecting-a-household": "חובה לבחור קבוצה לפני בחירת משק בית"
"you-must-select-a-group-before-selecting-a-household": "חובה לבחור קבוצה לפני בחירת משק בית",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "משק בית",
@@ -628,7 +663,7 @@
"create-recipe-description": "יצירת מתכון חדש מאפס.",
"create-recipes": "יצירת מתכונים",
"import-with-zip": "ייבא באמצעות zip",
"create-recipe-from-an-image": "יצירת מתכון מתמונה",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "יצירת מתכון ע\"י העלאת תמונה שלו. Mealie תנסה לחלץ את הטקסט מהתמונה באמצעות AI ותייצר ממנו מתכון.",
"crop-and-rotate-the-image": "נא לחתוך ולסובב את התמונה כך שרואים רק את הטקסט, והוא בכיוון הנכון.",
"create-from-images": "יצירה מתמונה",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "כבר הגדרתי הכל, תעבירו אותי לעמוד הבית",
"common-settings-for-new-sites": "הגדרות נפוצות לאתרים חדשים יופיעו כאן",
"setup-complete": "ההגדרה הושלמה!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "כמה דברים שיעזרו לך להתחיל להשתמש ב-Mealie",
"restore-from-v1-backup": "יש לך גיבוי משרת Mealie v1? ניתן לשחזר אותו כאן.",
"manage-profile-or-get-invite-link": "ניתן לנהל את הפרופיל שלך, או לשתף את לינק ההזמנה לאחרים."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Prikaži napredno",
"add-field": "Dodaj polje",
"date-created": "Datum kreiranja",
"date-updated": "Datum ažuriranja"
"date-updated": "Datum ažuriranja",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Jeste li sigurni da želite izbrisati <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Promjene u ovoj grupi će se odmah odraziti.",
"group-id-value": "Id grupe: {0}",
"total-households": "Ukupno kućanstava",
"you-must-select-a-group-before-selecting-a-household": "Prije odabira kućanstva morate odabrati grupu"
"you-must-select-a-group-before-selecting-a-household": "Prije odabira kućanstva morate odabrati grupu",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Domaćinstvo",
@@ -628,7 +663,7 @@
"create-recipe-description": "Izradi novi recept od početka",
"create-recipes": "Kreiraj recept",
"import-with-zip": "Učitaj pomoću .zip-a",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Obreži i rotiraj sliku tako da bude vidljiv samo tekst i da bude u ispravnoj orijentaciji.",
"create-from-images": "Izradi na temelju fotografije",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Haladó beállítások megjelenítése",
"add-field": "Mező hozzáadása",
"date-created": "Létrehozás dátuma",
"date-updated": "Frissítés dátuma"
"date-updated": "Frissítés dátuma",
"key": "Kulcs",
"value": "Érték"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Biztosan törölni szeretnéd ezt: <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "A csoporthoz tartozó változtatások azonnal megjelennek.",
"group-id-value": "Csoport azonosító: {0}",
"total-households": "Háztartások száma",
"you-must-select-a-group-before-selecting-a-household": "A háztartás kiválasztása előtt ki kell választania egy csoportot"
"you-must-select-a-group-before-selecting-a-household": "A háztartás kiválasztása előtt ki kell választania egy csoportot",
"ai-provider-settings": {
"ai-provider-settings": "AI szolgáltató beállítások",
"ai-provider": "AI szolgáltató",
"ai-providers": "AI szolgáltató",
"ai-provider-settings-description": "Állítsa be az AI-szolgáltatókat az AI-alapú funkciók, például a továbbfejlesztett összetevő-elemzés, a videókból történő receptkészítés és még sok más használatához!",
"providers": "Szolgáltatók",
"create-provider": "Szolgáltató létrehozása",
"edit-provider": "Szolgáltató szerkesztése",
"default-provider": "Alapértelmezett szolgáltató",
"default-provider-description": "Az AI-funkciók használatához szükséges",
"audio-provider": "Audió szolgáltató",
"audio-provider-description": "Engedélyezi az audió-átírási funkciókat, például a videókból származó receptek létrehozását",
"image-provider": "Kép szolgáltató",
"image-provider-description": "Engedélyezi a képfelismerési funkciókat, például a képek alapján történő receptkészítést",
"provider-name": "Szolgáltató neve",
"api-key": "API Kulcs",
"api-key-description-create": "A szolgáltató hitelesítési API-kulcsa. Ha a szolgáltatása (pl. Ollama) nem használ API-kulcsot, akkor is be kell írnia ide valamit.",
"api-key-description-edit": "Ha nem szeretné módosítani, hagyja üresen.",
"base-url": "Alap URL",
"base-url-description": "Ha az OpenAI-t használja, hagyja üresen ezt a mezőt. Az endpointnak OpenAI-kompatibilisnek kell lennie (pl. „http://localhost:11434/v1”).",
"model": "Modell",
"model-description": "Melyik modellt kell használnia az AI-szolgáltatónak (pl. „gpt-5”).",
"request-timeout-seconds": "A kérés időtúllépése (másodpercben)",
"provider-created": "Szolgáltató létrehozva",
"provider-updated": "Szolgáltató frissítve",
"provider-deleted": "Szolgáltató törölve",
"provider-create-failed": "A szolgáltató létrehozása sikertelen",
"provider-update-failed": "A szolgáltató frissítése sikertelen",
"provider-delete-failed": "A szolgáltató törlése sikertelen",
"request-headers": "Kérés fejléce",
"request-params": "Kérelem paraméterek",
"no-default-provider-warning": "Mivel nem állított be alapértelmezett szolgáltatót, az AI-funkciók le vannak tiltva"
}
},
"household": {
"household": "Háztartás",
@@ -628,7 +663,7 @@
"create-recipe-description": "Adj hozzá egy új receptet a nulláról kezdve.",
"create-recipes": "Receptek létrehozása",
"import-with-zip": "Importálás .zip formátummal",
"create-recipe-from-an-image": "Recept készítése képről",
"create-recipe-from-images": "Recept létrehozása képek alapján",
"create-recipe-from-an-image-description": "Hozzon létre egy receptet egy kép feltöltésével. A Mealie megpróbálja a kép szövegét mesterséges intelligencia segítségével kinyerni, és létrehozni belőle a receptet.",
"crop-and-rotate-the-image": "Vágja ki és forgassa el a képet úgy, hogy csak a szöveg legyen látható, és megfelelő tájolásban legyen.",
"create-from-images": "Létrehozás képekről",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Már kész is vagyok, vigyél az új kezdőoldalamra",
"common-settings-for-new-sites": "Itt van egy pár alap beállítás az új oldaladhoz",
"setup-complete": "Beállítás kész!",
"ai-providers-description": "Opcionálisan konfigurálhatja az AI-szolgáltatókat a csoportjához. Az AI-szolgáltatók olyan funkciókat tesznek lehetővé, mint a képekből történő receptkészítés, a videókból történő receptimportálás és a továbbfejlesztett hozzávalóelemzés. Ezt később bármikor beállíthatja a csoportbeállítások menüpontban.",
"here-are-a-few-things-to-help-you-get-started": "Itt van egy pár dolog ami segíthet a kezdésben a Mealie-vel",
"restore-from-v1-backup": "Van egy korábbi Mealie v1 biztonsági másolatod? Itt visszaállíthatod.",
"manage-profile-or-get-invite-link": "Alakítsa a profilját vagy szerezze meg a meghívó link-jét hogy megoszthassa másokkal."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Ítarlegar stillingar",
"add-field": "Bæta við dálk",
"date-created": "Búið til",
"date-updated": "Dagsetning uppfærð"
"date-updated": "Dagsetning uppfærð",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Ertu viss um að þú viljir eyða <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Breytingar á þessum hóp koma strax fram.",
"group-id-value": "Hóp ID: {0}",
"total-households": "Fjöldi heimila",
"you-must-select-a-group-before-selecting-a-household": "Þú verður að velja hóp áður en þú velur heimili"
"you-must-select-a-group-before-selecting-a-household": "Þú verður að velja hóp áður en þú velur heimili",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Heimili",
@@ -628,7 +663,7 @@
"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": "Stofna uppskrift út frá mynd",
"create-recipe-from-images": "Create Recipe from Images",
"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",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Allt er þegar klárt hjá mér, sendu mig á heimasíðuna",
"common-settings-for-new-sites": "Hér eru nokkrar algengar stillingar fyrir nýjar síður",
"setup-complete": "Uppsetningu lokið",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Hér eru nokkur atriði til að hjálpa þér að byrja á því að nota Mealie",
"restore-from-v1-backup": "Ertu með öryggisafrit af eldri útgáfur af Mealie útgáfu 1? Þú getur endurheimt hana hér.",
"manage-profile-or-get-invite-link": "Stilltu eigin prófil, eða sæktu boðs-tengil til að deila með öðrum."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostra Avanzate",
"add-field": "Aggiungi campo",
"date-created": "Data di Creazione",
"date-updated": "Data di aggiornamento"
"date-updated": "Data di aggiornamento",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Sei sicuro di volerlo eliminare <b>{groupName}<b/>'?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Le modifiche a questo gruppo si rifletteranno immediatamente.",
"group-id-value": "Id Gruppo: {0}",
"total-households": "Famiglie Totali",
"you-must-select-a-group-before-selecting-a-household": "Devi selezionare un gruppo prima di selezionare una famiglia"
"you-must-select-a-group-before-selecting-a-household": "Devi selezionare un gruppo prima di selezionare una famiglia",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Famiglia",
@@ -628,7 +663,7 @@
"create-recipe-description": "Crea una nuova ricetta da zero.",
"create-recipes": "Crea Ricette",
"import-with-zip": "Importa da .zip",
"create-recipe-from-an-image": "Crea ricetta da un'immagine",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Crea una ricetta caricando un'immagine di essa. Mealie tenterà di estrarre il testo dall'immagine usando l'IA e creare una ricetta da esso.",
"crop-and-rotate-the-image": "Ritaglia e ruota l'immagine in modo che solo il testo sia visibile e che sia orientato correttamente.",
"create-from-images": "Crea da immagini",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Ho già configurato tutto, portami alla pagina iniziale",
"common-settings-for-new-sites": "Ecco alcune impostazioni comuni per i nuovi siti",
"setup-complete": "Configurazione completata!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Qui ci sono alcune cose per aiutarvi a iniziare con Mealie",
"restore-from-v1-backup": "Hai un backup da un'istanza precedente di Mealie v1? Puoi ripristinarlo qui.",
"manage-profile-or-get-invite-link": "Gestisci il tuo profilo, o parti da un link di invito per condividere con gli altri."

View File

@@ -223,7 +223,9 @@
"show-advanced": "詳細を表示",
"add-field": "フィールドを追加",
"date-created": "作成日",
"date-updated": "更新日"
"date-updated": "更新日",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "<b>{groupName}<b/> を削除しますか?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "このグループへの変更はすぐに反映されます。",
"group-id-value": "グループID: {0}",
"total-households": "世帯数",
"you-must-select-a-group-before-selecting-a-household": "世帯を選択する前にグループを選択する必要があります"
"you-must-select-a-group-before-selecting-a-household": "世帯を選択する前にグループを選択する必要があります",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "世帯",
@@ -628,7 +663,7 @@
"create-recipe-description": "新しいレシピを一から作成します。",
"create-recipes": "レシピを作成する",
"import-with-zip": ".zip でインポート",
"create-recipe-from-an-image": "画像からレシピを作成",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "画像をアップロードしてレシピを作成します。 Mealieは、AIを使用して画像からテキストを抽出し、そこからレシピを作成しようとします。",
"crop-and-rotate-the-image": "テキストのみが表示され、正しい方向になるように画像をトリミングして回転します。",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "すでに設定は完了しています。ホームページにアクセスしてください",
"common-settings-for-new-sites": "新しいサイトの一般的な設定は次のとおりです",
"setup-complete": "セットアップ完了!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Mealieを始めるのに役立つことがいくつかあります",
"restore-from-v1-backup": "Mealie v1以前のインスタンスからのバックアップはありますかここで復元できます。",
"manage-profile-or-get-invite-link": "自分のプロフィールを管理するか、招待リンクを取得して他の人と共有します。"

View File

@@ -223,7 +223,9 @@
"show-advanced": "고급 표시",
"add-field": "필드 추가",
"date-created": "작성 날짜",
"date-updated": "업데이트 일자"
"date-updated": "업데이트 일자",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "<b>{groupName}<b/>을(를) 삭제하시겠습니까?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "이 그룹에 대한 변경 사항은 즉시 반영됩니다.",
"group-id-value": "그룹 Id: {0}",
"total-households": "전체 가구 수",
"you-must-select-a-group-before-selecting-a-household": "가구를 선택하기 전에 반드시 그룹을 선택해야 합니다."
"you-must-select-a-group-before-selecting-a-household": "가구를 선택하기 전에 반드시 그룹을 선택해야 합니다.",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "가구",
@@ -628,7 +663,7 @@
"create-recipe-description": "처음부터 새로운 레시피를 만드세요.",
"create-recipes": "레시피 생성",
"import-with-zip": ".zip 파일로 가져오기",
"create-recipe-from-an-image": "이미지에서 레시피 생성",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "레시피 텍스트 이미지를 업로드하여 레시피를 생성하세요. Mealie는 AI를 사용하여 이미지에서 텍스트를 추출하고 이를 통해 새로운 레시피를 생성하려고 시도합니다.",
"crop-and-rotate-the-image": "이미지를 잘라내고 회전시켜 텍스트만 보이도록 하고 올바른 방향으로 배치하십시오.",
"create-from-images": "이미지에서 생성",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "설정은 이미 완료되었으니, 그냥 홈페이지로 이동해 주세요",
"common-settings-for-new-sites": "새 사이트에 대한 일반적인 설정은 다음과 같습니다",
"setup-complete": "설정 완료",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Mealie를 시작하는 데 도움이 될 몇 가지 사항입니다.",
"restore-from-v1-backup": "이전 버전의 Mealie v1 백업본이 있으신가요? 여기서 복원할 수 있습니다.",
"manage-profile-or-get-invite-link": "자신의 프로필을 관리하거나, 다른 사람들과 공유할 초대 링크를 가져가세요."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Rodyti plačiau",
"add-field": "Pridėti lauką",
"date-created": "Sukūrimo data",
"date-updated": "Atnaujinimo data"
"date-updated": "Atnaujinimo data",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Ar tikrai norite ištrinti <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Pakeitimai šiai grupei pritaikomi iš karto.",
"group-id-value": "Grupės ID: {0}",
"total-households": "Iš viso namų ūkių",
"you-must-select-a-group-before-selecting-a-household": "Prieš pasirinkdami namų ūkį, turite pasirinkti grupę"
"you-must-select-a-group-before-selecting-a-household": "Prieš pasirinkdami namų ūkį, turite pasirinkti grupę",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Namų ūkis",
@@ -628,7 +663,7 @@
"create-recipe-description": "Create a new recipe from scratch.",
"create-recipes": "Create Recipes",
"import-with-zip": "Įkelti naudojant .zip failus",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
"create-from-images": "Kurti iš vaizdų",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Rādīt papildu",
"add-field": "Pievienot lauku",
"date-created": "Izveidošanas datums",
"date-updated": "Atjaunināšanas datums"
"date-updated": "Atjaunināšanas datums",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Vai tiešām vēlaties dzēst <b>{groupName} <b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Izmaiņas šajā grupā tiks atspoguļotas nekavējoties.",
"group-id-value": "Grupas ID: {0}",
"total-households": "Kopējais mājsaimniecību skaits",
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Mājsaimniecība",
@@ -628,7 +663,7 @@
"create-recipe-description": "Izveidojiet jaunu recepti no nulles.",
"create-recipes": "Izveidojiet receptes",
"import-with-zip": "Importēt ar .zip",
"create-recipe-from-an-image": "Izveidojiet recepti no attēla",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Izveidojiet recepti, augšupielādējot tās attēlu. Mealie mēģinās iegūt tekstu no attēla, izmantojot AI, un no tā izveidot recepti.",
"crop-and-rotate-the-image": "Apgrieziet un pagrieziet attēlu tā, lai būtu redzams tikai teksts un tas būtu pareizajā orientācijā.",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Es jau esmu iestatīts, vienkārši nogādājiet mani mājaslapā",
"common-settings-for-new-sites": "Šeit ir daži kopīgi iestatījumi jaunām vietnēm",
"setup-complete": "Iestatīšana pabeigta!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Šeit ir dažas lietas, kas palīdzēs jums sākt darbu ar Mealie",
"restore-from-v1-backup": "Vai jums ir dublējums no iepriekšējā Mealie v1 gadījuma? Jūs varat to atjaunot šeit.",
"manage-profile-or-get-invite-link": "Pārvaldiet savu profilu vai paņemiet uzaicinājuma saiti, lai kopīgotu ar citiem."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Laat geavanceerde keuzes zien",
"add-field": "Veld toevoegen",
"date-created": "Datum aangemaakt",
"date-updated": "Datum bijgewerkt"
"date-updated": "Datum bijgewerkt",
"key": "Sleutel",
"value": "Waarde"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Weet je zeker dat je <b>{groupName}<b/> wil verwijderen?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Wijzigingen in deze groep zijn meteen zichtbaar.",
"group-id-value": "Groeps-id: {0}",
"total-households": "Totaal aantal huishoudens",
"you-must-select-a-group-before-selecting-a-household": "Kies een groep voordat je een huishouden kiest"
"you-must-select-a-group-before-selecting-a-household": "Kies een groep voordat je een huishouden kiest",
"ai-provider-settings": {
"ai-provider-settings": "AI-aanbieder instellingen",
"ai-provider": "AI-aanbieder",
"ai-providers": "AI-aanbieders",
"ai-provider-settings-description": "Configureer AI-aanbieders om krachtige AI-aangedreven functies, zoals verbeterde ingrediënt parsing, aanmaken van recepten op basis van video's en nog meer!",
"providers": "Aanbieders",
"create-provider": "Aanbieder aanmaken",
"edit-provider": "Aanbieder bewerken",
"default-provider": "Standaard aanbieder",
"default-provider-description": "Vereist om AI-functies in te schakelen",
"audio-provider": "Audio aanbieder",
"audio-provider-description": "Maakt audiotransscriptie functionaliteiten mogelijk, waarmee recepten op basis van video's gemaakt kunnen worden",
"image-provider": "Afbeelding aanbieder",
"image-provider-description": "Maakt beeldherkenning functionaliteiten mogelijk, waarmee recepten op basis van afbeeldingen gemaakt kunnen worden",
"provider-name": "Naam aanbieder",
"api-key": "API-sleutel",
"api-key-description-create": "Je aanbieder's API-sleutel voor authenticatie. Als je service (bijv. Ollama) geen API-sleutel gebruikt, moet je hier alsnog iets invoeren.",
"api-key-description-edit": "Laat dit leeg tenzij je het wilt wijzigen.",
"base-url": "Basis URL",
"base-url-description": "Als je OpenAI gebruikt laat je dit leeg. Moet een OpenAI-compatibel eindpunt zijn (bijv. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Welk model je AI-aanbieder moet gebruiken (bijv. \"gpt-5\").",
"request-timeout-seconds": "Verzoek time-out (seconden)",
"provider-created": "Aanbieder aangemaakt",
"provider-updated": "Aanbieder bijgewerkt",
"provider-deleted": "Aanbieder verwijderd",
"provider-create-failed": "Aanmaken van aanbieder mislukt",
"provider-update-failed": "Bijwerken van aanbieder mislukt",
"provider-delete-failed": "Verwijderen van aanbieder mislukt",
"request-headers": "Aanvraagheaders",
"request-params": "Aanvraag parameters",
"no-default-provider-warning": "Je hebt geen standaard aanbieder ingesteld, AI-functies zijn uitgeschakeld"
}
},
"household": {
"household": "Huishouden",
@@ -628,7 +663,7 @@
"create-recipe-description": "Maak een nieuw recept.",
"create-recipes": "Recepten aanmaken",
"import-with-zip": "Importeer met .zip",
"create-recipe-from-an-image": "Maak recept van de tekst op een afbeelding",
"create-recipe-from-images": "Maak een recept op basis van een afbeelding",
"create-recipe-from-an-image-description": "Maak een recept door een afbeelding ervan te uploaden. Mealie probeert de tekst met behulp van AI uit de afbeelding te halen en er een recept uit te maken.",
"crop-and-rotate-the-image": "Snijd de afbeelding bij zodat alleen tekst zichtbaar is. En draai t plaatje zodat het leesbaar is.",
"create-from-images": "Maak recept van een afbeelding",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Ik ben al ingesteld, breng me naar de startpagina",
"common-settings-for-new-sites": "Hier zijn enkele algemene instellingen voor nieuwe sites",
"setup-complete": "Installatie voltooid!",
"ai-providers-description": "Optioneel kun je AI-aanbieders instellen voor je groep. AI-aanbieders maken functies, zoals het maken van recepten op basis van afbeeldingen, het malen van recepten op basis van video's, en verbeterde ingrediëntenparsing mogelijk. Je kunt dit later altijd instellen vanuit je groepsinstellingen.",
"here-are-a-few-things-to-help-you-get-started": "Hier zijn een aantal dingen om je op weg te helpen met Mealie",
"restore-from-v1-backup": "Heb je een back-up van een vorig exemplaar van Mealie v1? Deze kan je hier terugzetten.",
"manage-profile-or-get-invite-link": "Beheer je eigen profiel, of gebruik een uitnodigingslink om te delen met anderen."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Vis avansert",
"add-field": "Legg til felt",
"date-created": "Opprettet dato",
"date-updated": "Dato oppdatert"
"date-updated": "Dato oppdatert",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Er du sikker på at du vil slette <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Endringer i denne gruppen vil gjenspeiles umiddelbart.",
"group-id-value": "Gruppe-ID: {0}",
"total-households": "Husholdninger totalt",
"you-must-select-a-group-before-selecting-a-household": "Du må velge en gruppe før du kan velge en husholdning"
"you-must-select-a-group-before-selecting-a-household": "Du må velge en gruppe før du kan velge en husholdning",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Husholdning",
@@ -628,7 +663,7 @@
"create-recipe-description": "Opprett en ny oppskrift fra bunnen av.",
"create-recipes": "Opprett oppskrifter",
"import-with-zip": "Importer fra .zip-fil",
"create-recipe-from-an-image": "Opprett oppskrift fra et bilde",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Opprett en oppskrift ved å laste opp et bilde av den. Mealie vil forsøke å hente ut teksten fra bildet ved bruk av AI, og lage en ny oppskrift.",
"crop-and-rotate-the-image": "Beskjær og roter bildet slik at bare teksten er synlig, og at det er i riktig retning.",
"create-from-images": "Opprett fra bilde",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jeg er allerede satt opp, bare ta meg med til hjemmesiden",
"common-settings-for-new-sites": "Her er noen vanlige innstillinger for nye sider",
"setup-complete": "Oppsett fullført!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Her er noen ting som kan hjelpe deg å komme i gang med Mealie",
"restore-from-v1-backup": "Har du en sikkerhetskopi fra en tidligere forekomst av Mealie v1? Du kan gjenopprette den her.",
"manage-profile-or-get-invite-link": "Administrer din egen profil, eller hent en invitasjonslenke for å dele med andre."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Pokaż zaawansowane",
"add-field": "Dodaj pole",
"date-created": "Data utworzenia",
"date-updated": "Data aktualizacji"
"date-updated": "Data aktualizacji",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Czy na pewno chcesz usunąć <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Zmiany w tej grupie zostaną natychmiast odzwierciedlone.",
"group-id-value": "Id grupy: {0}",
"total-households": "Gospodarstwa domowe razem",
"you-must-select-a-group-before-selecting-a-household": "Musisz wybrać grupę przed wybraniem gospodarstwa domowego"
"you-must-select-a-group-before-selecting-a-household": "Musisz wybrać grupę przed wybraniem gospodarstwa domowego",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Gospodarstwo domowe",
@@ -628,7 +663,7 @@
"create-recipe-description": "Utwórz nowy przepis od zera.",
"create-recipes": "Utwórz przepisy",
"import-with-zip": "Importuj z pliku .zip",
"create-recipe-from-an-image": "Utwórz przepis z obrazów",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Utwórz przepis poprzez przesłanie obrazów tekstu przepisu. Mealie spróbuje wyodrębnić tekst z obrazów za pomocą AI i utworzyć z niego przepis.",
"crop-and-rotate-the-image": "Przytnij i obróć obraz, tak aby był w odpowiedniej orientacji i był widoczny tylko tekst.",
"create-from-images": "Utwórz przepis z obrazów",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Już mam skonfigurowane, po prostu przenieś mnie na stronę główną",
"common-settings-for-new-sites": "Oto kilka typowych ustawień dla nowych witryn",
"setup-complete": "Konfiguracja zakończona!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Oto kilka rzeczy, które pomogą Ci zacząć z Mealie",
"restore-from-v1-backup": "Masz kopię zapasową z poprzedniej instancji Mealie v1? Możesz ją tutaj przywrócić.",
"manage-profile-or-get-invite-link": "Zarządzaj własnym profilem lub pobierz link z zaproszeniem, aby udostępnić go innym."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostrar Avançado",
"add-field": "Adicionar Campo",
"date-created": "Data de Criação",
"date-updated": "Data de Atualização"
"date-updated": "Data de Atualização",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Tem certeza que deseja excluir o grupo <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "As alterações a este grupo serão refletidas imediatamente.",
"group-id-value": "ID do grupo: {0}",
"total-households": "Total de domicílios",
"you-must-select-a-group-before-selecting-a-household": "Você deve selecionar um grupo antes de selecionar um domicílio"
"you-must-select-a-group-before-selecting-a-household": "Você deve selecionar um grupo antes de selecionar um domicílio",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Domicílio",
@@ -628,7 +663,7 @@
"create-recipe-description": "Criar uma receita do zero.",
"create-recipes": "Criar Receitas",
"import-with-zip": "Importar a partir de .zip",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Corte e gire a imagem para que apenas o texto esteja visível e esteja na posição correta.",
"create-from-images": "Criar a partir de imagens",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Já estou pronto, apenas me leve à página inicial",
"common-settings-for-new-sites": "Estas são algumas configurações comuns para novos sites",
"setup-complete": "Configuração Concluída!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aqui há algumas coisas para ajudá-lo a começar com o Mealie",
"restore-from-v1-backup": "Tem uma cópia de segurança de uma instância anterior do Mealie v1? Você pode restaurá-la aqui.",
"manage-profile-or-get-invite-link": "Gerencie seu próprio perfil, ou pegue um link de convite para compartilhar."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Mostrar Avançadas",
"add-field": "Adicionar Campo",
"date-created": "Data de Criação",
"date-updated": "Data de Atualização"
"date-updated": "Data de Atualização",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Tem a certeza que quer eliminar <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "As alterações a este grupo serão aplicadas imediatamente.",
"group-id-value": "ID do Grupo: {0}",
"total-households": "Total de Lares",
"you-must-select-a-group-before-selecting-a-household": "Tens de selecionar um grupo antes de selecionar uma casa"
"you-must-select-a-group-before-selecting-a-household": "Tens de selecionar um grupo antes de selecionar uma casa",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Casa",
@@ -628,7 +663,7 @@
"create-recipe-description": "Criar uma receita em branco.",
"create-recipes": "Criar Receitas",
"import-with-zip": "Importar com .zip",
"create-recipe-from-an-image": "Criar receita a partir de uma imagem",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Crie uma receita carregando uma imagem da mesma. O Mealie tentará extrair o texto da imagem utilizando IA e criará uma receita a partir da mesma.",
"crop-and-rotate-the-image": "Recorte e rode a imagem de modo a que apenas o texto seja visível e esteja na orientação correta.",
"create-from-images": "Criar a partir de Imagens",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Já estou pronto, leva-me para a página inicial",
"common-settings-for-new-sites": "Aqui estão algumas configurações comuns para sites novos",
"setup-complete": "Configuração Concluída!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aqui estão algumas coisas para ajudar a começar com o Mealie",
"restore-from-v1-backup": "Tem uma cópia de segurança de uma instância do Mealie v1? Pode restaurá-la aqui.",
"manage-profile-or-get-invite-link": "Gira o seu próprio perfil ou pegue num convite para partilhar com outros."

View File

@@ -98,7 +98,7 @@
"dashboard": "Panou de control",
"delete": "Șterge",
"disabled": "Inactiv",
"done": "Done",
"done": "Gata",
"download": "Descarcă",
"duplicate": "Duplicat",
"edit": "Editează",
@@ -169,7 +169,7 @@
"token": "Token",
"tuesday": "Marţi",
"type": "Tip",
"undo": "Undo",
"undo": "Anulează acțiunea",
"update": "Actualizează",
"updated": "Actualizat",
"upload": "Încarcă",
@@ -223,7 +223,9 @@
"show-advanced": "Arată avansate",
"add-field": "Adaugă câmp",
"date-created": "Data creării",
"date-updated": "Data actualizată"
"date-updated": "Data actualizată",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Sunteți sigur că doriți să ștergeți <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Modificările la acest grup se vor reflecta imediat.",
"group-id-value": "ID grup: {0}",
"total-households": "Total locuințe",
"you-must-select-a-group-before-selecting-a-household": "Trebuie să selectaţi un grup înainte de a selecta o gospodărie"
"you-must-select-a-group-before-selecting-a-household": "Trebuie să selectaţi un grup înainte de a selecta o gospodărie",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Locuință",
@@ -333,8 +368,8 @@
"any-household": "Orice locuință",
"no-meal-plan-defined-yet": "Nici un plan de mese definit încă",
"no-meal-planned-for-today": "Nicio masă planificată pentru astăzi",
"numberOfDaysPast-hint": "Number of days in the past on page load",
"numberOfDaysPast-label": "Default Days in the Past",
"numberOfDaysPast-hint": "Numărul de zile din trecut la încărcarea paginii",
"numberOfDaysPast-label": "Număr implicit de zile din trecut",
"numberOfDays-hint": "Număr de zile pe pagină încărcată",
"numberOfDays-label": "Zile implicite",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Numai rețetele cu aceste categorii vor fi utilizate în Planurile de mese",
@@ -628,7 +663,7 @@
"create-recipe-description": "Creează o rețetă nouă de la zero.",
"create-recipes": "Crează rețetă",
"import-with-zip": "Importă cu .zip",
"create-recipe-from-an-image": "Creează o rețetă dintr-o imagine",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Creează o rețetă prin încărcarea unei imagini a acesteia. Mealie va încerca să extragă textul din imagine folosind AI și să creeze o rețetă din el.",
"crop-and-rotate-the-image": "Decupați și rotiți imaginea astfel încât numai textul să fie vizibil, iar orientarea să fie corectă.",
"create-from-images": "Creează din Imagini",
@@ -640,8 +675,8 @@
"create-a-recipe-by-providing-the-name-all-recipes-must-have-unique-names": "Creează o rețetă furnizând numele. Toate rețetele trebuie să aibă nume unice.",
"new-recipe-names-must-be-unique": "Numele rețetei trebuie să fie unic",
"scrape-recipe": "Importare rețetă",
"scrape-recipe-description": "Scrape a recipe by url. Provide the url for the site you want to scrape, and Mealie will attempt to scrape the recipe from that site and add it to your collection.",
"scrape-recipe-description-transcription": "You can also provide the url to a video and Mealie will attempt to transcribe it into a recipe.",
"scrape-recipe-description": "Extrage o rețetă după url. Introdu url-ul site-ului din care vrei să extragi rețeta, iar Mealie va încerca să o importe și să o adauge în colecția ta.",
"scrape-recipe-description-transcription": "Poți introduce și URL-ul unui videoclip, iar Mealie va încerca să îl transcrie într-o rețetă.",
"scrape-recipe-have-a-lot-of-recipes": "Ai mai multe rețete pe care vrei să le imporți simultan?",
"scrape-recipe-suggest-bulk-importer": "Încearcă importatorul în bulk",
"scrape-recipe-have-raw-html-or-json-data": "Ai date de tip HTML sau JSON?",
@@ -780,7 +815,7 @@
"irreversible-acknowledgment": "Înțeleg că această acțiune este ireversibilă, distructivă și poate provoca pierderea datelor",
"restore-backup": "Restaurează backup"
},
"backup-and-exports": "Backups",
"backup-and-exports": "Copii de rezervă",
"change-password": "Schimbă parola",
"current": "Versiune:",
"custom-pages": "Pagini personalizate",
@@ -893,17 +928,17 @@
"server-side-base-url-error-text": "`BASE_URL` încă este setat la valoarea implicită pe serverul API. Acest lucru va cauza probleme cu link-urile de notificări generate pe server pentru e-mailuri, etc.",
"server-side-base-url-success-text": "Adresa URL a serverului nu se potrivește cu cea implicită",
"ldap-ready": "LDAP pregătit",
"ldap-not-ready": "LDAP Not Ready",
"ldap-not-ready": "LDAP nu este pregătit\"",
"ldap-ready-error-text": "Nu toate valorile LDAP sunt configurate. Acest lucru poate fi ignorat dacă nu utilizați autentificarea cu LDAP.",
"ldap-ready-success-text": "Variabilele LDAP necesare sunt setate.",
"build": "Compilare",
"recipe-scraper-version": "Versiune \"scraper\" de rețete",
"oidc-ready": "OIDC pregătit",
"oidc-not-ready": "OIDC Not Ready",
"oidc-not-ready": "OIDC nu este pregătit",
"oidc-ready-error-text": "Nu toate valorile OIDC sunt configurate. Acest lucru poate fi ignorat dacă nu folosiți autentificarea OIDC.",
"oidc-ready-success-text": "Variabilele OIDC necesare sunt setate.",
"openai-ready": "OpenAI pregătit",
"openai-not-ready": "OpenAI Not Ready",
"openai-not-ready": "OpenAI nu este pregătit",
"openai-ready-error-text": "Nu toate valorile OpenAI sunt configurate. Acest lucru poate fi ignorat dacă nu utilizaţi caracteristicile OpenAI.",
"openai-ready-success-text": "Variabilele necesare OpenAI sunt setate."
},
@@ -911,15 +946,15 @@
"all-lists": "Toate listele",
"create-shopping-list": "Creează listă de cumpărături",
"from-recipe": "Dintr-o rețetă",
"ingredient-of-recipe": "Ingredient of {recipe}",
"ingredient-of-recipe": "Ingredient din {recipe}",
"list-name": "Nume listă",
"new-list": "Listă nouă",
"quantity": "Cantitate: {0}",
"shopping-list": "Listă de cumpărături",
"shopping-lists": "Liste de cumpărături",
"add-item": "Add item",
"add-item": "Adaugă articol",
"food": "Aliment",
"note": "Note",
"note": "Notă",
"label": "Etichetă",
"save-label": "Salvează etichetă",
"linked-item-warning": "Acest element este legat de una sau mai multe rețete. Ajustarea unităților sau a alimentelor va produce rezultate neașteptate la adăugarea sau scoaterea rețetei din listă.",
@@ -943,7 +978,7 @@
"are-you-sure-you-want-to-uncheck-all-items": "Sunteți sigur că doriți să debifați toate elementele?",
"are-you-sure-you-want-to-delete-checked-items": "Sunteți sigur că doriți să ștergeți toate elementele selectate?",
"no-shopping-lists-found": "Nu s-au găsit liste de cumpărături",
"item-checked-off": "Checked off {item}"
"item-checked-off": "{item} a fost bifat"
},
"sidebar": {
"all-recipes": "Toate reţetele",
@@ -1146,18 +1181,18 @@
"example-unit-plural": "ex: Linguri",
"example-unit-abbreviation-singular": "ex: Lg",
"example-unit-abbreviation-plural": "ex: Lg",
"standardization": "Standardization",
"standardization-description": "How this unit can be represented as a standard unit. This enables unit conversion features such as merging compatible units in shopping lists.",
"standard-unit": "Standard Unit",
"standard-quantity": "Standard Quantity",
"unit-conversion": "Unit Conversion",
"standardization": "Standardizare",
"standardization-description": "Modul în care această unitate poate fi reprezentată ca unitate standard. Activează funcții de conversie a unităților, cum ar fi combinarea unităților compatibile în listele de cumpărături.",
"standard-unit": "Unitate standard",
"standard-quantity": "Cantitate standard",
"unit-conversion": "Conversie unități",
"standard-unit-labels": {
"fluid-ounce": "fluid ounce",
"cup": "cup",
"ounce": "ounce",
"pound": "pound",
"milliliter": "milliliter",
"liter": "liter",
"fluid-ounce": "uncie fluidă",
"cup": "cană",
"ounce": "uncie",
"pound": "livră",
"milliliter": "mililitru",
"liter": "litru",
"gram": "gram",
"kilogram": "kilogram"
}
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Sunt deja configurat, du-mă direct la pagina principală",
"common-settings-for-new-sites": "Aici sunt câteva setări comune pentru noile site-uri",
"setup-complete": "Configurare finalizată!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Aici sunt câteva lucruri care te ajută să începi cu Mealie",
"restore-from-v1-backup": "Aveţi o copie de rezervă dintr-o instanţă anterioară a lui Mealie v1? O puteţi restaura aici.",
"manage-profile-or-get-invite-link": "Gestionează-ți propriul profil, sau apasă un link de invitație pentru a distribui cu alții."
@@ -1478,10 +1514,10 @@
"max-length": "Trebuie să aibă cel mult {max} caracter | Trebuie să aibă cel mult {max} caractere"
},
"announcements": {
"announcements": "Announcements",
"all-announcements": "All announcements",
"mark-all-as-read": "Mark All as Read",
"show-announcements-from-mealie": "Show announcements from Mealie",
"show-announcements-setting-description": "Whether or not you want to allow users to see announcements from Mealie. When enabled users can still opt-out from seeing them in their user settings"
"announcements": "Anunțuri",
"all-announcements": "Toate anunțurile",
"mark-all-as-read": "Marchează toate ca citite",
"show-announcements-from-mealie": "Afișează anunțurile de la Mealie",
"show-announcements-setting-description": "Stabilește dacă utilizatorii pot vedea anunțuri de la Mealie. Când opțiunea este activată, utilizatorii pot alege în continuare să nu le vadă în setările personale"
}
}

View File

@@ -223,7 +223,9 @@
"show-advanced": "Показать расширенные",
"add-field": "Добавить поле",
"date-created": "Дата создания",
"date-updated": "Дата обновления"
"date-updated": "Дата обновления",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Вы действительно хотите удалить <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Изменения в этой группе будут отражены немедленно.",
"group-id-value": "Id группы: {0}",
"total-households": "Всего домохозяйств",
"you-must-select-a-group-before-selecting-a-household": "Вы должны выбрать группу, прежде чем выбирать домохозяйство"
"you-must-select-a-group-before-selecting-a-household": "Вы должны выбрать группу, прежде чем выбирать домохозяйство",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Домохозяйство",
@@ -628,7 +663,7 @@
"create-recipe-description": "Создать новый рецепт с нуля.",
"create-recipes": "Создать Рецепт",
"import-with-zip": "Импорт из .zip",
"create-recipe-from-an-image": "Создать рецепт из изображения",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Создайте рецепт, загрузив изображение. Mealie попытается извлечь текст из изображения с помощью ИИ и создать рецепт из него.",
"crop-and-rotate-the-image": "Обрежьте и поверните изображение так, чтобы виден был только текст в нужной ориентации.",
"create-from-images": "Создать из изображений",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Я уже готов, просто открой домашнюю страницу",
"common-settings-for-new-sites": "Ниже приведены общие настройки для новых сайтов",
"setup-complete": "Настройка завершена!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Вот несколько вещей, которые помогут Вам начать работу с Mealie",
"restore-from-v1-backup": "У вас есть резервная копия предыдущего экземпляра Mealie v1? Вы можете восстановить ее здесь.",
"manage-profile-or-get-invite-link": "Управляйте своим профилем или получите ссылку-приглашение, чтобы поделиться ею с другими."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Zobraziť pokročilé",
"add-field": "Pridať pole",
"date-created": "Dátum vytvorenia",
"date-updated": "Dátum aktualizácie"
"date-updated": "Dátum aktualizácie",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Naozaj chcete odstrániť <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Zmeny týkajúce sa tejto skupiny budú vykonané okamžite.",
"group-id-value": "Id skupiny: {0}",
"total-households": "Domácností celkom",
"you-must-select-a-group-before-selecting-a-household": "Pred výberom domácnosti musíte vybrať skupinu"
"you-must-select-a-group-before-selecting-a-household": "Pred výberom domácnosti musíte vybrať skupinu",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Domácnosť",
@@ -628,7 +663,7 @@
"create-recipe-description": "Vytvoriť nový recept od začiatku.",
"create-recipes": "Vytvoriť recept",
"import-with-zip": "Importovať .zip súbor",
"create-recipe-from-an-image": "Vytvoriť recept z obrázka",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Vytvoriť recept nahraním fotografie jedla. Mealie sa pokúsi previesť obrázok na text pomocou AI a vytvorí k nemu recept.",
"crop-and-rotate-the-image": "Orežte a otočte obrázok tak, aby bol viditeľný iba text a aby mal správnu orientáciu.",
"create-from-images": "Vytvoriť z obrázka",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Som pripravený začať, vezmi ma na hlavnú stránku",
"common-settings-for-new-sites": "Toto sú bežné nastavenia nových inštalácií",
"setup-complete": "Nastavenie je dokončené!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Tu je niekoľko bodov, ktoré vám pomôžu na začiatku v Mealie",
"restore-from-v1-backup": "Máte zálohu z predchádzajúcej inštalácie Mealie v1? Tu ju môžete obnoviť.",
"manage-profile-or-get-invite-link": "Spravujte svoj profil ako súkromný alebo ho s pomocou pozývacieho linku zdieľajte s ostatnými."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Prikaži napredno",
"add-field": "Dodaj polje",
"date-created": "Datum nastanka",
"date-updated": "Datum posodobitve"
"date-updated": "Datum posodobitve",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Ste prepričani, da želite izbrisati <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Spremembe v tej skupini se poznajo takoj.",
"group-id-value": "ID skupine: {0}",
"total-households": "Skupaj gospodinjstev",
"you-must-select-a-group-before-selecting-a-household": "Preden izberete gospodinjstvo, morate izbrati skupino"
"you-must-select-a-group-before-selecting-a-household": "Preden izberete gospodinjstvo, morate izbrati skupino",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Gospodinjstvo",
@@ -628,7 +663,7 @@
"create-recipe-description": "Ustvari nov recept.",
"create-recipes": "Ustvari recepte",
"import-with-zip": "Uvozi z .zip",
"create-recipe-from-an-image": "Ustvari recept iz slike",
"create-recipe-from-images": "Ustvari recept iz slik",
"create-recipe-from-an-image-description": "Ustvarite recept tako, da naložite njegovo sliko. Mealie bo s pomočjo umetne inteligence poskušal izluščiti besedilo iz slike in iz njega ustvariti recept.",
"crop-and-rotate-the-image": "Obrežite in zasukajte sliko, tako da bo vidno samo besedilo in da bo v pravilnem položaju.",
"create-from-images": "Ustvari iz slik",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Vse imam že nastavljeno, odpri glavno stran",
"common-settings-for-new-sites": "Tule je par pogostih nastavitev za nove spletne strani",
"setup-complete": "Namestitev je zaključena!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Par stvari, ki to bodo pomagale začeti z Mealie",
"restore-from-v1-backup": "Imaš varnostno kopijo iz predhodnje instance Mealie v1? Obnoviš jo lahko tule.",
"manage-profile-or-get-invite-link": "Upravljaj s svojim profilom ali skopiraj povezavo z vabilom in jo deli z drugimi."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Прикажи напредно",
"add-field": "Додај поље",
"date-created": "Датум креирања",
"date-updated": "Датум измене"
"date-updated": "Датум измене",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Да ли сте сигурни да желите да обришете <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Промене у овој групи биће одмах видљиве.",
"group-id-value": "ИД групе: {0}",
"total-households": "Укупно домаћинстава",
"you-must-select-a-group-before-selecting-a-household": "Морате селектовати групу пре селектовања домаћинства"
"you-must-select-a-group-before-selecting-a-household": "Морате селектовати групу пре селектовања домаћинства",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Домаћинство",
@@ -628,7 +663,7 @@
"create-recipe-description": "Креирајте нови рецепт од нуле.",
"create-recipes": "Направите рецепте",
"import-with-zip": "Увези помоћу .zip архиве",
"create-recipe-from-an-image": "Направи рецепт на основи слике",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Креирајте рецепт отпремањем његове слике. Mealie ће покушати да издвоји текст из слике користећи АИ и од њега направи рецепт.",
"crop-and-rotate-the-image": "Исеците и ротирајте слику тако да је видљив само текст и да је у исправној оријентацији.",
"create-from-images": "Креирај из слика",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Већ сам подешен, само ме одведи на почетну страницу",
"common-settings-for-new-sites": "Ево неколико уобичајених подешавања за нове сајтове",
"setup-complete": "Подешавање је завршено!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Ево неколико ствари које ће вам помоћи да започнете са Mealieјем",
"restore-from-v1-backup": "Имате резервну копију из претходне инстанце Mealie v1? Можете је вратити овде.",
"manage-profile-or-get-invite-link": "Управљајте сопственим профилом или узмите линк за позивницу да бисте га поделили са другима."

View File

@@ -98,7 +98,7 @@
"dashboard": "Startsida",
"delete": "Ta bort",
"disabled": "Inaktiverad",
"done": "Done",
"done": "Färdig",
"download": "Ladda ner",
"duplicate": "Duplicera",
"edit": "Redigera",
@@ -223,7 +223,9 @@
"show-advanced": "Visa avancerat",
"add-field": "Lägg till fält",
"date-created": "Datum skapad",
"date-updated": "Datum uppdaterat"
"date-updated": "Datum uppdaterat",
"key": "Nyckel",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Är du säker på att du vill radera <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Ändringar i denna grupp kommer att återspeglas omedelbart.",
"group-id-value": "Grupp-Id: {0}",
"total-households": "Totalt antal hushåll",
"you-must-select-a-group-before-selecting-a-household": "Du måste välja en grupp innan du kan välja ett hushåll"
"you-must-select-a-group-before-selecting-a-household": "Du måste välja en grupp innan du kan välja ett hushåll",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI-leverantör",
"ai-providers": "AI-leverantörer",
"ai-provider-settings-description": "Konfigurera AI-leverantörer för att aktivera AI-drivna funktioner, såsom förbättrad ingrediensanalysering, skapa recept från videor och mycket mer!",
"providers": "Leverantörer",
"create-provider": "Skapa leverantör",
"edit-provider": "Ändra leverantör",
"default-provider": "Standard leverantör",
"default-provider-description": "Krävs för att aktivera AI-funktioner",
"audio-provider": "Ljudleverantör",
"audio-provider-description": "Möjliggör funktioner för ljudtranskription, till exempel att skapa recept från videor",
"image-provider": "Bildleverantör",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Leverantörsnamn",
"api-key": "API-nyckel",
"api-key-description-create": "Din leverantörs API-nyckel för autentisering. Om din tjänst (t.ex. Ollama) inte använder en API-nyckel, måste du fortfarande sätta något här.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Hushåll",
@@ -628,7 +663,7 @@
"create-recipe-description": "Skapa nytt recept från grunden.",
"create-recipes": "Skapa recept",
"import-with-zip": "Importera från .zip",
"create-recipe-from-an-image": "Skapa recept från en bild",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Skapa ett recept genom att ladda upp en bild på det. Mealie kommer att försöka extrahera texten från bilden med hjälp av AI och skapa ett recept från det.",
"crop-and-rotate-the-image": "Beskär och rotera bilden så att endast texten är synlig och den är åt rätt håll.",
"create-from-images": "Skapa från bild",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Jag har redan gjort inställningarna, ta mig bara till hemsidan",
"common-settings-for-new-sites": "Här är några vanliga inställningar för nya webbplatser",
"setup-complete": "Konfigurationen slutförd!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Här är några saker som hjälper dig att komma igång med Mealie",
"restore-from-v1-backup": "Har du en säkerhetskopia från en tidigare instans av Mealie v1? Du kan återställa den här.",
"manage-profile-or-get-invite-link": "Hantera din egen profil eller hämta en inbjudningslänk för att dela med andra."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Gelişmiş Göster",
"add-field": "Alan Ekle",
"date-created": "Oluşturma Tarihi",
"date-updated": "Güncellenme tarihi"
"date-updated": "Güncellenme tarihi",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "<b>{groupName}<b/>'i silmek istediğine emin misin?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Bu gruptaki değişiklikler hemen yansıtılacaktır.",
"group-id-value": "Grup Kimliği: {0}",
"total-households": "Toplam Hane Halkı",
"you-must-select-a-group-before-selecting-a-household": " Bir hane seçmeden önce bir grup seçmelisiniz"
"you-must-select-a-group-before-selecting-a-household": " Bir hane seçmeden önce bir grup seçmelisiniz",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Ev Halkı",
@@ -628,7 +663,7 @@
"create-recipe-description": "Sıfırdan yeni bir tarif oluşturun.",
"create-recipes": "Tarif Oluştur",
"import-with-zip": ".zip ile içe aktar",
"create-recipe-from-an-image": "Görüntüden yemek tarifi oluştur",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Bir görsel yükleyerek yemek tarifi oluşturun. Mealie, yapay zekâ kullanarak görseldeki bilgileri çekip yemek tarifini oluşturmaya çalışacaktır.",
"crop-and-rotate-the-image": "Resmi sadece yazılar gözükecek şekilde kesin ve döndürün, ayrıca doğru yönde durduğuna emin olun.",
"create-from-images": "Resimden Oluştur",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Kurulumu zaten yaptım, beni yalnızca ana sayfaya götür",
"common-settings-for-new-sites": "Yeni siteler için bazı ortak ayarlar şunlardır",
"setup-complete": "Kurulum tamamlandı!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Mealie'yi kullanmaya başlamanıza yardımcı olacak birkaç şey",
"restore-from-v1-backup": "Mealie v1'in önceki örneğinden bir yedeğiniz mi var? Buradan geri yükleyebilirsiniz.",
"manage-profile-or-get-invite-link": "Kendi profilinizi yönetin veya başkalarıyla paylaşmak için bir davet bağlantısı alın."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Показати розширені",
"add-field": "Додати поле",
"date-created": "Дата Створення",
"date-updated": "Дата Оновлення"
"date-updated": "Дата Оновлення",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Ви дійсно бажаєте видалити <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Зміни до цієї групи будуть відображені негайно.",
"group-id-value": "Id групи: {0}",
"total-households": "Всього сімей",
"you-must-select-a-group-before-selecting-a-household": "Ви маєте вибрати групу перед тим, як вибирати сім'ю"
"you-must-select-a-group-before-selecting-a-household": "Ви маєте вибрати групу перед тим, як вибирати сім'ю",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Сімʼя",
@@ -628,7 +663,7 @@
"create-recipe-description": "Створити новий рецепт з нуля.",
"create-recipes": "Створити рецепти",
"import-with-zip": "Імпорт з .zip",
"create-recipe-from-an-image": "Створити рецепт з зображення",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Створити рецепт, завантаживши його зображення. Mealie спробує витягти текст з зображення за допомогою ШІ та створити рецепт з нього.",
"crop-and-rotate-the-image": "Обріжте і поверніть зображення так, щоб було видно лише текст в правильній орієнтації.",
"create-from-images": "Створити з зображень",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "Вже все налаштовано, просто перенеси мене на домашню сторінку",
"common-settings-for-new-sites": "Ось деякі загальні налаштування для нових сайтів",
"setup-complete": "Налаштування завершене!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Ось кілька речей, які допоможуть вам почати з Mealie",
"restore-from-v1-backup": "Маєте резервну копію з попереднього екземпляра Меаліе v1? Ви можете використати його тут.",
"manage-profile-or-get-invite-link": "Керуйте вашим власним профілем, або отримайте посилання-запрошення щоб поділитися з іншими."

View File

@@ -223,7 +223,9 @@
"show-advanced": "Show Advanced",
"add-field": "Add Field",
"date-created": "Date Created",
"date-updated": "Date Updated"
"date-updated": "Date Updated",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "Changes to this group will be reflected immediately.",
"group-id-value": "Group Id: {0}",
"total-households": "Total Households",
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household"
"you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "Household",
@@ -628,7 +663,7 @@
"create-recipe-description": "Create a new recipe from scratch.",
"create-recipes": "Create Recipes",
"import-with-zip": "Import with .zip",
"create-recipe-from-an-image": "Create Recipe from an Image",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "Create a recipe by uploading an image of it. Mealie will attempt to extract the text from the image using AI and create a recipe from it.",
"crop-and-rotate-the-image": "Crop and rotate the image so that only the text is visible, and it's in the correct orientation.",
"create-from-images": "Create from Images",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage",
"common-settings-for-new-sites": "Here are some common settings for new sites",
"setup-complete": "Setup Complete!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "Here are a few things to help you get started with Mealie",
"restore-from-v1-backup": "Have a backup from a previous instance of Mealie v1? You can restore it here.",
"manage-profile-or-get-invite-link": "Manage your own profile, or grab an invite link to share with others."

View File

@@ -223,7 +223,9 @@
"show-advanced": "显示进阶设置",
"add-field": "添加项目",
"date-created": "创建日期",
"date-updated": "修改日期"
"date-updated": "修改日期",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "您确定要删除<b>{groupName}<b/>吗?",
@@ -283,7 +285,40 @@
"admin-group-management-text": "对本群组的更改将被立即应用。",
"group-id-value": "群组ID{0}",
"total-households": "总共家庭",
"you-must-select-a-group-before-selecting-a-household": "你必须先选择一个组才能选择一个家庭"
"you-must-select-a-group-before-selecting-a-household": "你必须先选择一个组才能选择一个家庭",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "家庭",
@@ -628,7 +663,7 @@
"create-recipe-description": "从头创建一个新食谱。",
"create-recipes": "创建食谱",
"import-with-zip": "使用 .zip 导入",
"create-recipe-from-an-image": "用图片创建食谱",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "通过上传食谱文本的图片来创建一个食谱。Mealie将尝试使用人工智能从图像中提取文本并从中创建一个新的食谱。",
"crop-and-rotate-the-image": "裁剪并旋转图片,使仅文字可见且方向正确。",
"create-from-images": "从图片创建",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "我已经配置好了,直接跳转到主页",
"common-settings-for-new-sites": "这有一些新站点的常见设置",
"setup-complete": "配置完成!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "以下这些可以帮助你开始使用Mealie",
"restore-from-v1-backup": "有之前Mealie v1实例的备份数据你可以在这里恢复它们。",
"manage-profile-or-get-invite-link": "管理你自己的个人资料,或者获取邀请链接分享给其他人。"

View File

@@ -223,7 +223,9 @@
"show-advanced": "顯示進階選項",
"add-field": "新增欄位",
"date-created": "建立日期",
"date-updated": "更新日期"
"date-updated": "更新日期",
"key": "Key",
"value": "Value"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "確定要刪除 <b>{groupName}</b>",
@@ -283,7 +285,40 @@
"admin-group-management-text": "對此群組的變更將立即生效。",
"group-id-value": "群組 ID{0}",
"total-households": "家庭群組總數",
"you-must-select-a-group-before-selecting-a-household": "請先選擇群組,再選擇家庭群組"
"you-must-select-a-group-before-selecting-a-household": "請先選擇群組,再選擇家庭群組",
"ai-provider-settings": {
"ai-provider-settings": "AI Provider Settings",
"ai-provider": "AI Provider",
"ai-providers": "AI Providers",
"ai-provider-settings-description": "Configure AI providers to enable AI-powered features, such as enhanced ingredient parsing, creating recipes from videos, and more!",
"providers": "Providers",
"create-provider": "Create Provider",
"edit-provider": "Edit Provider",
"default-provider": "Default Provider",
"default-provider-description": "Required to enable AI features",
"audio-provider": "Audio Provider",
"audio-provider-description": "Enables audio transcription features, such as creating recipes from videos",
"image-provider": "Image Provider",
"image-provider-description": "Enables image recognition features, such as creating recipes from images",
"provider-name": "Provider Name",
"api-key": "API Key",
"api-key-description-create": "Your provider's API key for authentication. If your service (e.g. Ollama) doesn't use an API key, you still have to put something here.",
"api-key-description-edit": "Leave this blank unless you want to change it.",
"base-url": "Base URL",
"base-url-description": "If you're using OpenAI leave this blank. Must be an OpenAI-compatible endpoint (e.g. \"http://localhost:11434/v1\").",
"model": "Model",
"model-description": "Which model your AI provider should use (e.g. \"gpt-5\").",
"request-timeout-seconds": "Request Timeout (seconds)",
"provider-created": "Provider created",
"provider-updated": "Provider updated",
"provider-deleted": "Provider deleted",
"provider-create-failed": "Failed to create provider",
"provider-update-failed": "Failed to update provider",
"provider-delete-failed": "Failed to delete provider",
"request-headers": "Request Headers",
"request-params": "Request Parameters",
"no-default-provider-warning": "You have not set a default provider, so AI features are disabled"
}
},
"household": {
"household": "家庭群組",
@@ -628,7 +663,7 @@
"create-recipe-description": "從頭開始建立新食譜。",
"create-recipes": "建立食譜",
"import-with-zip": "以 .zip 匯入",
"create-recipe-from-an-image": "從圖片建立食譜",
"create-recipe-from-images": "Create Recipe from Images",
"create-recipe-from-an-image-description": "上傳食譜圖片來建立食譜Mealie 將嘗試使用 AI 從圖片中擷取文字並建立食譜。",
"crop-and-rotate-the-image": "請裁切並旋轉圖片,使其僅顯示文字且方向正確。",
"create-from-images": "從圖片建立",
@@ -1362,6 +1397,7 @@
"already-set-up-bring-to-homepage": "我已完成設定,直接帶我到首頁",
"common-settings-for-new-sites": "以下是新站台的常用設定",
"setup-complete": "設定完成!",
"ai-providers-description": "Optionally configure AI providers for your group. AI providers enable features like creating recipes from images, importing recipes from videos, and enhanced ingredient parsing. You can always configure this later from your group settings.",
"here-are-a-few-things-to-help-you-get-started": "以下幾項可幫助您開始使用 Mealie",
"restore-from-v1-backup": "有舊版 Mealie v1 的備份?您可以在這裡還原。",
"manage-profile-or-get-invite-link": "管理您的個人資料,或取得邀請連結與他人分享。"

View File

@@ -0,0 +1,27 @@
import { BaseAPI } from "../base/base-clients";
import type { AIProviderCreate, AIProviderOut, AIProviderUpdate } from "~/lib/api/types/group";
const prefix = "/api/admin";
const routes = {
providers: (groupId: string) => `${prefix}/groups/${groupId}/ai-providers/providers`,
providersId: (groupId: string, providerId: string) => `${prefix}/groups/${groupId}/ai-providers/providers/${providerId}`,
};
export class AdminAIProvidersApi extends BaseAPI {
async createProvider(groupId: string, payload: AIProviderCreate) {
return await this.requests.post<AIProviderOut>(routes.providers(groupId), payload);
}
async getProvider(groupId: string, providerId: string) {
return await this.requests.get<AIProviderOut>(routes.providersId(groupId, providerId));
}
async updateProvider(groupId: string, providerId: string, payload: AIProviderUpdate) {
return await this.requests.put<AIProviderOut>(routes.providersId(groupId, providerId), payload);
}
async deleteProvider(groupId: string, providerId: string) {
return await this.requests.delete<AIProviderOut>(routes.providersId(groupId, providerId));
}
}

View File

@@ -4,11 +4,11 @@ import type { DebugResponse } from "~/lib/api/types/admin";
const prefix = "/api";
const routes = {
openai: `${prefix}/admin/debug/openai`,
openai: providerId => `${prefix}/admin/debug/openai/${providerId}`,
};
export class AdminDebugAPI extends BaseAPI {
async debugOpenAI(fileObject: Blob | File | undefined = undefined, fileName = "") {
async debugOpenAI(providerId: string, fileObject: Blob | File | undefined = undefined, fileName = "") {
let formData: FormData | null = null;
if (fileObject) {
formData = new FormData();
@@ -16,6 +16,6 @@ export class AdminDebugAPI extends BaseAPI {
formData.append("extension", fileName.split(".").pop() ?? "");
}
return await this.requests.post<DebugResponse>(routes.openai, formData);
return await this.requests.post<DebugResponse>(routes.openai(providerId), formData);
}
}

View File

@@ -6,6 +6,7 @@ import { AdminBackupsApi } from "./admin/admin-backups";
import { AdminMaintenanceApi } from "./admin/admin-maintenance";
import { AdminAnalyticsApi } from "./admin/admin-analytics";
import { AdminDebugAPI } from "./admin/admin-debug";
import { AdminAIProvidersApi } from "./admin/admin-ai-providers";
import type { ApiRequestInstance } from "~/lib/api/types/non-generated";
export class AdminAPI {
@@ -17,6 +18,7 @@ export class AdminAPI {
public maintenance: AdminMaintenanceApi;
public analytics: AdminAnalyticsApi;
public debug: AdminDebugAPI;
public aiProviders: AdminAIProvidersApi;
constructor(requests: ApiRequestInstance) {
this.about = new AdminAboutAPI(requests);
@@ -27,6 +29,7 @@ export class AdminAPI {
this.maintenance = new AdminMaintenanceApi(requests);
this.analytics = new AdminAnalyticsApi(requests);
this.debug = new AdminDebugAPI(requests);
this.aiProviders = new AdminAIProvidersApi(requests);
Object.freeze(this);
}

View File

@@ -24,6 +24,7 @@ import { MultiPurposeLabelsApi } from "./user/group-multiple-purpose-labels";
import { GroupEventNotifierApi } from "./user/group-event-notifier";
import { MealPlanRulesApi } from "./user/group-mealplan-rules";
import { GroupDataSeederApi } from "./user/group-seeder";
import { AIProvidersAPI } from "./user/group-ai-providers";
import type { ApiRequestInstance } from "~/lib/api/types/non-generated";
export class UserApiClient {
@@ -53,6 +54,7 @@ export class UserApiClient {
public groupEventNotifier: GroupEventNotifierApi;
public upload: UploadFile;
public seeders: GroupDataSeederApi;
public aiProviders: AIProvidersAPI;
constructor(requests: ApiRequestInstance) {
// Recipes
@@ -80,6 +82,7 @@ export class UserApiClient {
this.shopping = new ShoppingApi(requests);
this.multiPurposeLabels = new MultiPurposeLabelsApi(requests);
this.seeders = new GroupDataSeederApi(requests);
this.aiProviders = new AIProvidersAPI(requests);
// Admin
this.backups = new BackupAPI(requests);

View File

@@ -16,9 +16,6 @@ export interface AdminAboutInfo {
enableOidc: boolean;
oidcRedirect: boolean;
oidcProviderName: string;
enableOpenai: boolean;
enableOpenaiImageServices: boolean;
enableOpenaiTranscriptionServices: boolean;
tokenTime: number;
versionLatest: string;
apiPort: number;
@@ -50,9 +47,6 @@ export interface AppInfo {
enableOidc: boolean;
oidcRedirect: boolean;
oidcProviderName: string;
enableOpenai: boolean;
enableOpenaiImageServices: boolean;
enableOpenaiTranscriptionServices: boolean;
tokenTime: number;
}
export interface AppStartupInfo {
@@ -95,7 +89,6 @@ export interface CheckAppConfig {
emailReady: boolean;
ldapReady: boolean;
oidcReady: boolean;
enableOpenai: boolean;
baseUrlSet: boolean;
isUpToDate: boolean;
}

View File

@@ -17,6 +17,77 @@ export type SupportedMigrations =
| "recipekeeper"
| "cookn";
export interface AIProviderCreate {
name: string;
baseUrl?: string | null;
model: string;
timeout?: number;
requestHeaders?: {
[k: string]: string;
};
requestParams?: {
[k: string]: string;
};
}
export interface AIProviderOut {
name: string;
baseUrl?: string | null;
model: string;
timeout?: number;
requestHeaders?: {
[k: string]: string;
};
requestParams?: {
[k: string]: string;
};
id: string;
}
export interface AIProviderSave {
name: string;
baseUrl?: string | null;
model: string;
timeout?: number;
requestHeaders?: {
[k: string]: string;
};
requestParams?: {
[k: string]: string;
};
settingsId: string;
}
export interface AIProviderSettingsCreate {
groupId: string;
}
export interface AIProviderSettingsOut {
defaultProviderId: string | null;
audioProviderId: string | null;
imageProviderId: string | null;
providers: AIProviderSummary[];
aiEnabled: boolean;
audioProviderEnabled: boolean;
imageProviderEnabled: boolean;
}
export interface AIProviderSummary {
id: string;
name: string;
}
export interface AIProviderSettingsUpdate {
defaultProviderId: string | null;
audioProviderId: string | null;
imageProviderId: string | null;
}
export interface AIProviderUpdate {
name: string;
baseUrl?: string | null;
model: string;
timeout?: number;
requestHeaders?: {
[k: string]: string;
};
requestParams?: {
[k: string]: string;
};
}
export interface CreateGroupPreferences {
privateGroup?: boolean;
showAnnouncements?: boolean;
@@ -29,6 +100,7 @@ export interface GroupAdminUpdate {
id: string;
name: string;
preferences?: UpdateGroupPreferences | null;
aiProviderSettings?: AIProviderSettingsUpdate | null;
}
export interface UpdateGroupPreferences {
privateGroup?: boolean;

View File

@@ -59,6 +59,7 @@ export interface GroupInDB {
households?: GroupHouseholdSummary[] | null;
users?: UserSummary[] | null;
preferences?: ReadGroupPreferences | null;
aiProviderSettings?: AIProviderSettingsOut | null;
}
export interface CategoryBase {
name: string;
@@ -89,11 +90,25 @@ export interface ReadGroupPreferences {
groupId: string;
id: string;
}
export interface AIProviderSettingsOut {
defaultProviderId: string | null;
audioProviderId: string | null;
imageProviderId: string | null;
providers: AIProviderSummary[];
aiEnabled: boolean;
audioProviderEnabled: boolean;
imageProviderEnabled: boolean;
}
export interface AIProviderSummary {
id: string;
name: string;
}
export interface GroupSummary {
name: string;
id: string;
slug: string;
preferences?: ReadGroupPreferences | null;
aiProviderSettings?: AIProviderSettingsOut | null;
}
export interface LongLiveTokenCreateResponse {
name: string;

View File

@@ -0,0 +1,27 @@
import { BaseAPI } from "../base/base-clients";
import type { AIProviderCreate, AIProviderOut, AIProviderUpdate } from "~/lib/api/types/group";
const prefix = "/api/groups/ai-providers";
const routes = {
providers: `${prefix}/providers`,
providersId: (id: string) => `${prefix}/providers/${id}`,
};
export class AIProvidersAPI extends BaseAPI {
async getOne(id: string) {
return await this.requests.get<AIProviderOut>(routes.providersId(id));
}
async createOne(payload: AIProviderCreate) {
return await this.requests.post<AIProviderOut>(routes.providers, payload);
}
async updateOne(id: string, payload: AIProviderUpdate) {
return await this.requests.put<AIProviderOut, AIProviderUpdate>(routes.providersId(id), payload);
}
async deleteOne(id: string) {
return await this.requests.delete<AIProviderOut>(routes.providersId(id));
}
}

View File

@@ -3,6 +3,8 @@ import type { PaginationData } from "../types/non-generated";
import type { QueryValue } from "../base/route";
import type { GroupBase, GroupInDB, GroupSummary, UserSummary } from "~/lib/api/types/user";
import type {
AIProviderSettingsUpdate,
AIProviderSettingsOut,
GroupAdminUpdate,
GroupStorage,
ReadGroupPreferences,
@@ -15,6 +17,7 @@ const routes = {
groups: `${prefix}/admin/groups`,
groupsSelf: `${prefix}/groups/self`,
preferences: `${prefix}/groups/preferences`,
aiProviderSettings: `${prefix}/groups/ai-providers/settings`,
storage: `${prefix}/groups/storage`,
members: `${prefix}/groups/members`,
groupsId: (id: string | number) => `${prefix}/admin/groups/${id}`,
@@ -29,15 +32,15 @@ export class GroupAPI extends BaseCRUDAPI<GroupBase, GroupInDB, GroupAdminUpdate
return await this.requests.get<GroupSummary>(routes.groupsSelf);
}
async getPreferences() {
return await this.requests.get<ReadGroupPreferences>(routes.preferences);
}
async setPreferences(payload: UpdateGroupPreferences) {
// TODO: This should probably be a patch request, which isn't offered by the API currently
return await this.requests.put<ReadGroupPreferences, UpdateGroupPreferences>(routes.preferences, payload);
}
async setAIProviderSettings(payload: AIProviderSettingsUpdate) {
return await this.requests.put<AIProviderSettingsOut, AIProviderSettingsUpdate>(routes.aiProviderSettings, payload);
}
async fetchMembers(page = 1, perPage = -1, params = {} as Record<string, QueryValue>) {
return await this.requests.get<PaginationData<UserSummary>>(routes.members, { page, perPage, ...params });
}

View File

@@ -43,10 +43,6 @@ export class HouseholdAPI extends BaseCRUDAPIReadOnly<HouseholdSummary> {
return await this.requests.get<HouseholdRecipeSummary>(routes.householdsSelfRecipesSlug(recipeSlug));
}
async getPreferences() {
return await this.requests.get<ReadHouseholdPreferences>(routes.preferences);
}
async setPreferences(payload: UpdateHouseholdPreferences) {
// TODO: This should probably be a patch request, which isn't offered by the API currently
return await this.requests.put<ReadHouseholdPreferences, UpdateHouseholdPreferences>(routes.preferences, payload);

View File

@@ -6,7 +6,7 @@
<br>
<DocLink
class="mt-2"
link="/documentation/getting-started/installation/open-ai"
link="/documentation/getting-started/installation/ai-providers"
/>
</BaseCardSectionTitle>
</v-container>
@@ -17,6 +17,36 @@
<div>
<v-card-text>
<v-container class="pa-0">
<v-row>
<v-col cols="12" md="6">
<v-select
v-if="groups"
v-model="selectedGroupId"
:items="groups"
item-title="name"
item-value="id"
:label="$t('group.group')"
density="compact"
variant="outlined"
clearable
hide-details
/>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="selectedProviderId"
:items="groupProviders"
item-title="name"
item-value="id"
:label="$t('group.ai-provider-settings.ai-provider')"
density="compact"
variant="outlined"
clearable
hide-details
:disabled="!selectedGroupId"
/>
</v-col>
</v-row>
<v-row>
<v-col
cols="auto"
@@ -61,6 +91,7 @@
<v-card-actions>
<BaseButton
type="submit"
:disabled="!selectedProviderId"
:text="$t('admin.run-test')"
:icon="$globals.icons.check"
:loading="loading"
@@ -85,7 +116,9 @@
<script setup lang="ts">
import { useAdminApi } from "~/composables/api";
import { useGroups } from "~/composables/use-groups";
import { alert } from "~/composables/use-toast";
import type { AIProviderSummary } from "~/lib/api/types/group";
definePageMeta({
layout: "admin",
@@ -106,10 +139,24 @@ const uploadedImage = ref<Blob | File>();
const uploadedImageName = ref<string>("");
const uploadedImagePreviewUrl = ref<string>();
function uploadImage(fileObject: File) {
uploadedImage.value = fileObject;
uploadedImageName.value = fileObject.name;
uploadedImagePreviewUrl.value = URL.createObjectURL(fileObject);
// Group + provider selection
const { groups } = useGroups();
const selectedGroupId = ref<string | null>(null);
const groupProviders = ref<AIProviderSummary[]>([]);
const selectedProviderId = ref<string | null>(null);
watch(selectedGroupId, (id) => {
groupProviders.value = [];
selectedProviderId.value = null;
if (!id) return;
const group = groups.value?.find(g => g.id === id);
groupProviders.value = group?.aiProviderSettings?.providers ?? [];
});
function uploadImage(fileObject: unknown) {
uploadedImage.value = fileObject as File;
uploadedImageName.value = (fileObject as File).name;
uploadedImagePreviewUrl.value = URL.createObjectURL(fileObject as File);
}
function clearImage() {
@@ -119,10 +166,15 @@ function clearImage() {
}
async function testOpenAI() {
if (!selectedProviderId.value) {
alert.error("Please select a provider");
return;
}
response.value = "";
loading.value = true;
const { data } = await api.debug.debugOpenAI(uploadedImage.value);
const { data } = await api.debug.debugOpenAI(selectedProviderId.value, uploadedImage.value);
loading.value = false;
if (!data) {

View File

@@ -33,6 +33,13 @@
v-if="group.preferences"
v-model="group.preferences"
/>
<GroupAIProviderSettingsEditor
v-if="group.aiProviderSettings"
v-model="group.aiProviderSettings"
@create="handleCreateProvider"
@update="handleUpdateProvider"
@delete="handleDeleteProvider"
/>
</v-card-text>
</v-card>
<div class="d-flex pa-2">
@@ -50,8 +57,10 @@
<script setup lang="ts">
import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue";
import GroupAIProviderSettingsEditor from "~/components/Domain/Group/GroupAIProviderSettingsEditor.vue";
import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
import type { VForm } from "vuetify/components";
definePageMeta({
@@ -72,7 +81,7 @@ const adminApi = useAdminApi();
const userError = ref(false);
const { data: group } = useLazyAsyncData(`get-household-${groupId.value}`, async () => {
const { data: group, refresh } = useLazyAsyncData(`get-household-${groupId.value}`, async () => {
if (!groupId.value) {
return null;
}
@@ -86,7 +95,7 @@ const { data: group } = useLazyAsyncData(`get-household-${groupId.value}`, async
}, { watch: [groupId] });
async function handleSubmit() {
if (!refGroupEditForm.value?.validate() || group.value === null) {
if (!refGroupEditForm.value?.validate() || !group.value) {
return;
}
@@ -103,4 +112,40 @@ async function handleSubmit() {
alert.error(i18n.t("settings.settings-update-failed"));
}
}
async function handleCreateProvider(data: AIProviderCreate) {
if (!group.value) return;
const result = await adminApi.aiProviders.createProvider(group.value.id, data);
if (result.data) {
await refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-created"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-create-failed"));
}
}
async function handleUpdateProvider(id: string, data: AIProviderUpdate) {
if (!group.value) return;
const result = await adminApi.aiProviders.updateProvider(group.value.id, id, data);
if (result.data) {
await refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-updated"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-update-failed"));
}
}
async function handleDeleteProvider(id: string) {
if (!group.value) return;
const result = await adminApi.aiProviders.deleteProvider(group.value.id, id);
if (result.data) {
await refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-deleted"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-delete-failed"));
}
}
</script>

View File

@@ -45,6 +45,14 @@
:title="$t('settings.site-settings')"
/>
<v-divider />
<v-stepper-item
:value="Pages.AI_PROVIDERS"
:icon="$globals.icons.robot"
:complete="currentPage > Pages.AI_PROVIDERS"
:color="getStepperColor(currentPage, Pages.AI_PROVIDERS)"
:title="$t('group.ai-provider-settings.ai-providers')"
/>
<v-divider />
<v-stepper-item
:value="Pages.CONFIRM"
:icon="$globals.icons.chefHat"
@@ -173,6 +181,43 @@
</v-stepper-actions>
</v-stepper-window-item>
<!-- AI PROVIDERS -->
<v-stepper-window-item :value="Pages.AI_PROVIDERS">
<v-container max-width="880">
<v-card-title class="headline pa-0">
{{ $t('group.ai-provider-settings.ai-providers') }}
</v-card-title>
<v-card-subtitle class="px-0 py-2 text-wrap">
{{ $t('group.ai-provider-settings.ai-providers-description') }}
</v-card-subtitle>
<GroupAIProviderSettingsEditor
v-if="group?.aiProviderSettings"
v-model="group.aiProviderSettings"
hide-header
class="mt-4"
@create="handleCreateProvider"
@update="handleUpdateProvider"
@delete="handleDeleteProvider"
/>
</v-container>
<v-stepper-actions
:disabled="isSubmitting"
prev-text="general.back"
@click:prev="onPrev"
>
<template #next>
<v-btn
variant="flat"
color="success"
:disabled="isSubmitting"
:loading="isSubmitting"
:text="$t('general.next')"
@click="onNext"
/>
</template>
</v-stepper-actions>
</v-stepper-window-item>
<!-- CONFIRMATION -->
<v-stepper-window-item :value="Pages.CONFIRM">
<v-container max-width="880">
@@ -252,7 +297,11 @@ import { useLocales } from "~/composables/use-locales";
import { alert } from "~/composables/use-toast";
import { useUserRegistrationForm } from "~/composables/use-users/user-registration-form";
import { useCommonSettingsForm } from "~/composables/use-setup/common-settings-form";
import { useGroupSelf } from "~/composables/use-groups";
import { useAIProviders } from "~/composables/use-ai-providers";
import UserRegistrationForm from "~/components/Domain/User/UserRegistrationForm.vue";
import GroupAIProviderSettingsEditor from "~/components/Domain/Group/GroupAIProviderSettingsEditor.vue";
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
definePageMeta({
layout: "blank",
@@ -267,6 +316,42 @@ const userApi = useUserApi();
const adminApi = useAdminApi();
const groupSlug = computed(() => auth.user.value?.groupSlug);
const { group, actions: groupActions } = useGroupSelf();
const { createOne, updateOne, deleteOne } = useAIProviders();
async function handleCreateProvider(data: AIProviderCreate) {
const result = await createOne(data);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-created"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-create-failed"));
}
}
async function handleUpdateProvider(id: string, data: AIProviderUpdate) {
const result = await updateOne(id, data);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-updated"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-update-failed"));
}
}
async function handleDeleteProvider(id: string) {
const result = await deleteOne(id);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-deleted"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-delete-failed"));
}
}
const { locale } = useLocales();
const router = useRouter();
const isSubmitting = ref(false);
@@ -281,8 +366,9 @@ enum Pages {
LANDING = 1,
USER_INFO = 2,
PAGE_2 = 3,
CONFIRM = 4,
END = 5,
AI_PROVIDERS = 4,
CONFIRM = 5,
END = 6,
}
function getStepperColor(currentPage: Pages, page: Pages) {
@@ -475,6 +561,7 @@ async function submitAll() {
const tasks = [
submitRegistration(),
submitCommonSettings(),
groupActions.updateAIProviderSettings(),
];
await Promise.all(tasks);

View File

@@ -284,7 +284,6 @@ const appConfig = ref<CheckApp>({
isUpToDate: false,
ldapReady: false,
oidcReady: false,
enableOpenai: false,
});
function isLocalHostOrHttps() {
return window.location.hostname === "localhost" || window.location.protocol === "https:";
@@ -351,15 +350,6 @@ const simpleChecks = computed<SimpleCheck[]>(() => {
color: appConfig.value.oidcReady ? goodColor : warningColor,
icon: appConfig.value.oidcReady ? goodIcon : warningIcon,
},
{
id: "openai-ready",
text: appConfig.value.enableOpenai ? i18n.t("settings.openai-ready") : i18n.t("settings.openai-not-ready"),
status: appConfig.value.enableOpenai,
errorText: i18n.t("settings.openai-ready-error-text"),
successText: i18n.t("settings.openai-ready-success-text"),
color: appConfig.value.enableOpenai ? goodColor : warningColor,
icon: appConfig.value.enableOpenai ? goodIcon : warningIcon,
},
];
return data;
});

View File

@@ -45,6 +45,7 @@
<script setup lang="ts">
import type { MenuItem } from "~/components/global/BaseOverflowButton.vue";
import AdvancedOnly from "~/components/global/AdvancedOnly.vue";
import { useGroupSelf } from "~/composables/use-groups";
definePageMeta({
middleware: ["group-only"],
@@ -52,7 +53,8 @@ definePageMeta({
const i18n = useI18n();
const auth = useMealieAuth();
const { $appInfo, $globals } = useNuxtApp();
const { $globals } = useNuxtApp();
const { group } = useGroupSelf();
useSeoMeta({
title: i18n.t("general.create"),
@@ -78,7 +80,7 @@ const subpages = computed<MenuItem[]>(() => [
icon: $globals.icons.fileImage,
text: i18n.t("recipe.create-from-images"),
value: "image",
hide: !$appInfo.enableOpenaiImageServices,
hide: !group.value?.aiProviderSettings?.imageProviderEnabled,
},
{
icon: $globals.icons.edit,

View File

@@ -25,7 +25,7 @@
persistent-hint
/>
</v-card-text>
<v-card-text v-if="$appInfo.enableOpenai">
<v-card-text v-if="group?.aiProviderSettings?.aiEnabled">
{{ $t('recipe.recipe-debugger-use-openai-description') }}
<v-checkbox
v-model="state.useOpenAI"
@@ -69,6 +69,7 @@
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { useGroupSelf } from "~/composables/use-groups";
import { validators } from "~/composables/use-validators";
import type { Recipe } from "~/lib/api/types/recipe";
@@ -80,6 +81,7 @@ const state = reactive({
const api = useUserApi();
const route = useRoute();
const router = useRouter();
const { group } = useGroupSelf();
const recipeUrl = computed({
set(recipe_import_url: string | null) {

View File

@@ -3,7 +3,7 @@
<v-form ref="domUrlForm" @submit.prevent="createRecipe">
<div>
<v-card-title class="headline">
{{ $t("recipe.create-recipe-from-an-image") }}
{{ $t("recipe.create-recipe-from-images") }}
</v-card-title>
<v-card-text>
<p>{{ $t("recipe.create-recipe-from-an-image-description") }}</p>

View File

@@ -11,7 +11,7 @@
<v-card-text>
<v-card-text class="pa-0">
<p>{{ $t('recipe.scrape-recipe-description') }}</p>
<p v-if="$appInfo.enableOpenaiTranscriptionServices">
<p v-if="group?.aiProviderSettings?.audioProviderEnabled">
{{ $t('recipe.scrape-recipe-description-transcription') }}
</p>
</v-card-text>
@@ -145,6 +145,7 @@
<script setup lang="ts">
import type { AxiosResponse } from "axios";
import { useUserApi } from "~/composables/api";
import { useGroupSelf } from "~/composables/use-groups";
import { useTagStore } from "~/composables/store/use-tag-store";
import { useNewRecipeOptions } from "~/composables/use-new-recipe-options";
import { validators } from "~/composables/use-validators";
@@ -162,6 +163,7 @@ const auth = useMealieAuth();
const api = useUserApi();
const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug as string || auth.user.value?.groupSlug || "");
const { group } = useGroupSelf();
const router = useRouter();
const tags = useTagStore();

View File

@@ -17,25 +17,52 @@
</template>
{{ $t("profile.group-description") }}
</BasePageTitle>
<v-form ref="refGroupEditForm" @submit.prevent="handleSubmit">
<v-card variant="outlined" style="border-color: lightgray;">
<v-card-text>
<GroupPreferencesEditor v-if="group.preferences" v-model="group.preferences" />
</v-card-text>
</v-card>
<div class="d-flex pa-2">
<BaseButton type="submit" edit class="ml-auto">
{{ $t("general.update") }}
</BaseButton>
</div>
</v-form>
<div class="mb-10">
<v-form ref="refGroupPrefsEditForm" @submit.prevent="handlePrefsSubmit">
<v-card variant="outlined" style="border-color: lightgray;">
<v-card-text>
<GroupPreferencesEditor v-if="group.preferences" v-model="group.preferences" />
</v-card-text>
</v-card>
<div class="d-flex pa-2">
<BaseButton type="submit" edit class="ml-auto">
{{ $t("general.update") }}
</BaseButton>
</div>
</v-form>
</div>
<div>
<v-form ref="refGroupAISettingsForm" @submit.prevent="handleAISettingsSubmit">
<v-card variant="outlined" style="border-color: lightgray;">
<v-card-text>
<GroupAIProviderSettingsEditor
v-if="group.aiProviderSettings"
v-model="group.aiProviderSettings"
@create="handleCreateProvider"
@update="handleUpdateProvider"
@delete="handleDeleteProvider"
/>
</v-card-text>
</v-card>
<div class="d-flex pa-2">
<BaseButton type="submit" edit class="ml-auto">
{{ $t("general.update") }}
</BaseButton>
</div>
</v-form>
</div>
</v-container>
</template>
<script setup lang="ts">
import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue";
import GroupAIProviderSettingsEditor from "~/components/Domain/Group/GroupAIProviderSettingsEditor.vue";
import { useGroupSelf } from "~/composables/use-groups";
import { useAIProviders } from "~/composables/use-ai-providers";
import { alert } from "~/composables/use-toast";
import type { AIProviderCreate, AIProviderUpdate } from "~/lib/api/types/group";
import type { VForm } from "~/types/auto-forms";
definePageMeta({
@@ -49,10 +76,11 @@ useSeoMeta({
title: i18n.t("group.group"),
});
const refGroupEditForm = ref<VForm | null>(null);
const refGroupPrefsEditForm = ref<VForm | null>(null);
const refGroupAISettingsForm = ref<VForm | null>(null);
async function handleSubmit() {
if (!refGroupEditForm.value?.validate() || !group.value?.preferences) {
async function handlePrefsSubmit() {
if (!refGroupPrefsEditForm.value?.validate() || !group.value?.preferences) {
return;
}
@@ -64,6 +92,55 @@ async function handleSubmit() {
alert.error(i18n.t("settings.settings-update-failed"));
}
}
async function handleAISettingsSubmit() {
if (!refGroupAISettingsForm.value?.validate() || !group.value?.aiProviderSettings) {
return;
}
const data = await groupActions.updateAIProviderSettings();
if (data) {
alert.success(i18n.t("settings.settings-updated"));
}
else {
alert.error(i18n.t("settings.settings-update-failed"));
}
}
const { createOne, updateOne, deleteOne } = useAIProviders();
async function handleCreateProvider(data: AIProviderCreate) {
const result = await createOne(data);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-created"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-create-failed"));
}
}
async function handleUpdateProvider(id: string, data: AIProviderUpdate) {
const result = await updateOne(id, data);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-updated"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-update-failed"));
}
}
async function handleDeleteProvider(id: string) {
const result = await deleteOne(id);
if (result.data) {
await groupActions.refresh();
alert.success(i18n.t("group.ai-provider-settings.provider-deleted"));
}
else {
alert.error(i18n.t("group.ai-provider-settings.provider-delete-failed"));
}
}
</script>
<style lang="css">

View File

@@ -45,7 +45,7 @@
sm="12"
md="12"
>
<v-card variant="outlined" style="border-color: lightgray;" class="mt-4">
<v-card variant="outlined" style="border-color: lightgray;" class="mt-4 pa-2">
<v-card-title class="text-h6 pb-0">
{{ $t('profile.household-statistics') }}
</v-card-title>

View File

@@ -0,0 +1,65 @@
/**
* v-no-autofill directive
*
* Vuetify 3 places data-* attributes on its wrapper div, not the underlying
* <input> element, so password managers still offer to autofill. This directive
* uses a MutationObserver to find and patch every <input> inside the host
* element, even ones rendered asynchronously (dialogs, conditional blocks).
*
* From: https://github.com/vuetifyjs/vuetify/issues/18202
*
* Usage:
* <v-text-field v-no-autofill ... />
* <v-form v-no-autofill>...</v-form>
* <div v-no-autofill>...</div>
*/
import type { Directive, DirectiveBinding } from "vue";
interface ObservedElement extends HTMLElement {
_noAutofillObserver?: MutationObserver;
}
function patchInput(input: HTMLInputElement) {
input.setAttribute("autocomplete", "off");
input.setAttribute("data-1p-ignore", "true");
input.setAttribute("data-lpignore", "true");
input.setAttribute("data-protonpass-ignore", "true");
input.setAttribute("data-bwignore", "true");
input.setAttribute("data-form-type", "other");
}
function patchAll(el: HTMLElement) {
if (el.tagName === "INPUT") {
patchInput(el as HTMLInputElement);
}
el.querySelectorAll<HTMLInputElement>("input").forEach(patchInput);
}
const noAutofill: Directive<ObservedElement> = {
mounted(el: ObservedElement, _binding: DirectiveBinding) {
patchAll(el);
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
patchAll(node as HTMLElement);
}
}
}
});
observer.observe(el, { childList: true, subtree: true });
el._noAutofillObserver = observer;
},
unmounted(el: ObservedElement) {
el._noAutofillObserver?.disconnect();
delete el._noAutofillObserver;
},
};
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive("no-autofill", noAutofill);
});

View File

@@ -14,6 +14,7 @@ import type BaseCardSectionTitle from "@/components/global/BaseCardSectionTitle.
import type BaseDialog from "@/components/global/BaseDialog.vue";
import type BaseDivider from "@/components/global/BaseDivider.vue";
import type BaseExpansionPanels from "@/components/global/BaseExpansionPanels.vue";
import type BaseKeyValueEditor from "@/components/global/BaseKeyValueEditor.vue";
import type BaseOverflowButton from "@/components/global/BaseOverflowButton.vue";
import type BasePageTitle from "@/components/global/BasePageTitle.vue";
import type ButtonLink from "@/components/global/ButtonLink.vue";
@@ -54,6 +55,7 @@ declare module "vue" {
BaseDialog: typeof BaseDialog;
BaseDivider: typeof BaseDivider;
BaseExpansionPanels: typeof BaseExpansionPanels;
BaseKeyValueEditor: typeof BaseKeyValueEditor;
BaseOverflowButton: typeof BaseOverflowButton;
BasePageTitle: typeof BasePageTitle;
ButtonLink: typeof ButtonLink;

View File

@@ -11,6 +11,7 @@ export default withNuxt({
"@stylistic/no-tabs": ["error"],
"@stylistic/no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"@typescript-eslint/no-explicit-any": "off",
"import/no-extraneous-dependencies": ["error"],
"vue/first-attribute-linebreak": "error",
"vue/html-closing-bracket-newline": "error",
"vue/max-attributes-per-line": [

View File

@@ -1,6 +1,6 @@
{
"name": "mealie",
"version": "3.18.0",
"version": "3.19.2",
"private": true,
"scripts": {
"dev": "nuxt dev",
@@ -21,18 +21,24 @@
"@mdi/js": "^7.4.47",
"@nuxt/fonts": "^0.11.4",
"@nuxtjs/i18n": "^9.2.1",
"@sphinxxxx/color-conversion": "^2.2.2",
"@vite-pwa/nuxt": "^0.10.6",
"@vueuse/core": "^12.7.0",
"@vueuse/shared": "^14.3.0",
"axios": "^1.8.1",
"date-fns": "^4.1.0",
"dompurify": "^3.4.7",
"fuse.js": "^7.1.0",
"isomorphic-dompurify": "^3.4.0",
"json-editor-vue": "^0.18.1",
"marked": "^15.0.12",
"nuxt": "^4.4.2",
"sse.js": "^2.8.0",
"ufo": "^1.6.4",
"vue": "^3.5.35",
"vue-advanced-cropper": "^2.8.9",
"vue-draggable-plus": "^0.6.0",
"vue-i18n": "^11.4.4",
"vuetify": "^4.0.5",
"vuetify-nuxt-module": "^0.19.5"
},
@@ -41,6 +47,7 @@
"@stylistic/eslint-plugin": "^5.4.0",
"@types/node": "^25.5.2",
"@types/sortablejs": "^1.15.8",
"@vitejs/plugin-vue": "^6.0.7",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-format": "^1.0.1",

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@ from sqlalchemy.orm import Session, load_only
from alembic import op
from mealie.db.models._model_utils.guid import GUID
from mealie.db.models.labels import MultiPurposeLabel
from mealie.db.models.recipe.labels import MultiPurposeLabel
from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel, RecipeIngredientModel
# revision identifiers, used by Alembic.

View File

@@ -0,0 +1,298 @@
"""add table for ai providers
Revision ID: 2187537c52b8
Revises: c7427796f7b6
Create Date: 2026-05-18 16:27:05.770218
"""
import sqlalchemy as sa
from alembic import op
from pydantic_settings import BaseSettings, SettingsConfigDict
import mealie.db.migration_types
from mealie.core.config import ENV
from mealie.core.root_logger import get_logger
from mealie.core.settings.settings import get_secrets_dir
from mealie.db.models._model_utils.guid import GUID
# revision identifiers, used by Alembic.
revision = "2187537c52b8"
down_revision: str | None = "c7427796f7b6"
branch_labels: str | tuple[str, ...] | None = None
depends_on: str | tuple[str, ...] | None = None
logger = get_logger()
class LegacyOpenAISettings(BaseSettings):
OPENAI_BASE_URL: str | None = None
OPENAI_API_KEY: str | None = None
OPENAI_MODEL: str = "gpt-4o"
OPENAI_AUDIO_MODEL: str = "whisper-1"
OPENAI_CUSTOM_HEADERS: dict[str, str] = {}
OPENAI_CUSTOM_PARAMS: dict[str, str] = {}
OPENAI_ENABLE_IMAGE_SERVICES: bool = True
OPENAI_ENABLE_TRANSCRIPTION_SERVICES: bool = True
OPENAI_REQUEST_TIMEOUT: int = 300
model_config = SettingsConfigDict(extra="ignore")
def get_openai_settings() -> LegacyOpenAISettings:
return LegacyOpenAISettings(
_env_file=ENV,
_env_file_encoding="utf-8",
_secrets_dir=get_secrets_dir(),
)
def is_postgres() -> bool:
return op.get_context().dialect.name == "postgresql"
def generate_id() -> str:
val = GUID.generate()
dialect = op.get_bind().dialect
return GUID.convert_value_to_guid(val, dialect) # type: ignore
def create_provider(settings_id: str, provider_id: str, model: str, openai_settings: LegacyOpenAISettings) -> None:
logger.info(f"Creating provider '{model}'")
conn = op.get_bind()
conn.execute(
sa.text(
"INSERT INTO ai_providers (id, settings_id, name, base_url, api_key, model, timeout) "
"VALUES (:id, :settings_id, :name, :base_url, :api_key, :model, :timeout)"
),
{
"id": provider_id,
"settings_id": settings_id,
# we only create one provider per model in this mirgration script,
# so there's no chance for collisions
"name": model,
"base_url": openai_settings.OPENAI_BASE_URL,
"api_key": openai_settings.OPENAI_API_KEY,
"model": model,
"timeout": openai_settings.OPENAI_REQUEST_TIMEOUT,
},
)
for key, value in openai_settings.OPENAI_CUSTOM_HEADERS.items():
conn.execute(
sa.text(
"INSERT INTO ai_provider_headers (provider_id, key_name, value) "
"VALUES (:provider_id, :key_name, :value)"
),
{"provider_id": provider_id, "key_name": key, "value": value},
)
for key, value in openai_settings.OPENAI_CUSTOM_PARAMS.items():
conn.execute(
sa.text(
"INSERT INTO ai_provider_params (provider_id, key_name, value) VALUES (:provider_id, :key_name, :value)"
),
{"provider_id": provider_id, "key_name": key, "value": value},
)
def create_providers() -> None:
"""Create provider settings and migrate legacy OPEN_AI_... environment variables to a provider"""
openai_settings = get_openai_settings()
create_providers = bool(openai_settings.OPENAI_API_KEY and openai_settings.OPENAI_MODEL)
if create_providers:
logger.info("Found legacy OpenAI configuration, creating new AI providers")
conn = op.get_bind()
groups = conn.execute(sa.text("SELECT id FROM groups")).fetchall()
for (group_id,) in groups:
logger.info(f"Creating provider settings for {group_id=}")
# Create AI provider settings
settings_id = generate_id()
conn.execute(
sa.text("INSERT INTO ai_provider_settings (id, group_id) VALUES (:id, :group_id)"),
{"id": settings_id, "group_id": group_id},
)
if not create_providers:
continue
# Create provider
default_provider_id = generate_id()
model = openai_settings.OPENAI_MODEL
create_provider(settings_id, default_provider_id, model, openai_settings)
# Set the image provider if image services are enabled
if openai_settings.OPENAI_ENABLE_IMAGE_SERVICES:
image_provider_id = default_provider_id
else:
image_provider_id = None
# Set the audio provider if transcription services are enabled
if openai_settings.OPENAI_ENABLE_TRANSCRIPTION_SERVICES:
transcription_model = openai_settings.OPENAI_AUDIO_MODEL or model
if transcription_model == openai_settings.OPENAI_MODEL:
audio_provider_id = default_provider_id
else:
# The transcription model is different than the base model, so create a new provider
audio_provider_id = generate_id()
create_provider(settings_id, audio_provider_id, transcription_model, openai_settings)
else:
audio_provider_id = None
# Update the provider settings to reference new provider(s)
conn.execute(
sa.text(
"""
UPDATE ai_provider_settings
SET
default_provider_id = :default_provider_id,
audio_provider_id = :audio_provider_id,
image_provider_id = :image_provider_id
WHERE id = :id
"""
),
{
"default_provider_id": default_provider_id,
"audio_provider_id": audio_provider_id,
"image_provider_id": image_provider_id,
"id": settings_id,
},
)
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"ai_provider_settings",
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("default_provider_id", mealie.db.migration_types.GUID(), nullable=True),
sa.Column("audio_provider_id", mealie.db.migration_types.GUID(), nullable=True),
sa.Column("image_provider_id", mealie.db.migration_types.GUID(), nullable=True),
sa.Column("created_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.Column("update_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.ForeignKeyConstraint(["default_provider_id"], ["ai_providers.id"], use_alter=True),
sa.ForeignKeyConstraint(["audio_provider_id"], ["ai_providers.id"], use_alter=True),
sa.ForeignKeyConstraint(
["group_id"],
["groups.id"],
),
sa.ForeignKeyConstraint(["image_provider_id"], ["ai_providers.id"], use_alter=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("group_id", name="ai_provider_settings_group_id_key"),
)
with op.batch_alter_table("ai_provider_settings", schema=None) as batch_op:
batch_op.create_index(
batch_op.f("ix_ai_provider_settings_default_provider_id"), ["default_provider_id"], unique=False
)
batch_op.create_index(
batch_op.f("ix_ai_provider_settings_audio_provider_id"), ["audio_provider_id"], unique=False
)
batch_op.create_index(batch_op.f("ix_ai_provider_settings_created_at"), ["created_at"], unique=False)
batch_op.create_index(batch_op.f("ix_ai_provider_settings_group_id"), ["group_id"], unique=False)
batch_op.create_index(
batch_op.f("ix_ai_provider_settings_image_provider_id"), ["image_provider_id"], unique=False
)
op.create_table(
"ai_providers",
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("settings_id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("base_url", sa.String(), nullable=True),
sa.Column("api_key", sa.String(), nullable=False),
sa.Column("model", sa.String(), nullable=False),
sa.Column("timeout", sa.Integer(), nullable=False),
sa.Column("created_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.Column("update_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.ForeignKeyConstraint(
["settings_id"],
["ai_provider_settings.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name", "settings_id", name="ai_providers_name_settings_id_key"),
)
with op.batch_alter_table("ai_providers", schema=None) as batch_op:
batch_op.create_index(batch_op.f("ix_ai_providers_created_at"), ["created_at"], unique=False)
batch_op.create_index(batch_op.f("ix_ai_providers_name"), ["name"], unique=False)
batch_op.create_index(batch_op.f("ix_ai_providers_settings_id"), ["settings_id"], unique=False)
op.create_table(
"ai_provider_headers",
sa.Column("provider_id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("key_name", sa.String(), nullable=True),
sa.Column("value", sa.String(), nullable=True),
sa.Column("created_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.Column("update_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.ForeignKeyConstraint(
["provider_id"],
["ai_providers.id"],
),
sa.PrimaryKeyConstraint("id"),
)
with op.batch_alter_table("ai_provider_headers", schema=None) as batch_op:
batch_op.create_index(batch_op.f("ix_ai_provider_headers_created_at"), ["created_at"], unique=False)
batch_op.create_index(batch_op.f("ix_ai_provider_headers_provider_id"), ["provider_id"], unique=False)
op.create_table(
"ai_provider_params",
sa.Column("provider_id", mealie.db.migration_types.GUID(), nullable=False),
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("key_name", sa.String(), nullable=True),
sa.Column("value", sa.String(), nullable=True),
sa.Column("created_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.Column("update_at", mealie.db.migration_types.NaiveDateTime(), nullable=True),
sa.ForeignKeyConstraint(
["provider_id"],
["ai_providers.id"],
),
sa.PrimaryKeyConstraint("id"),
)
with op.batch_alter_table("ai_provider_params", schema=None) as batch_op:
batch_op.create_index(batch_op.f("ix_ai_provider_params_created_at"), ["created_at"], unique=False)
batch_op.create_index(batch_op.f("ix_ai_provider_params_provider_id"), ["provider_id"], unique=False)
# ### end Alembic commands ###
try:
with op.get_bind().begin_nested():
create_providers()
except Exception:
logger.exception("Failed to migrate legacy OpenAI config")
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("ai_provider_params", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_ai_provider_params_provider_id"))
batch_op.drop_index(batch_op.f("ix_ai_provider_params_created_at"))
op.drop_table("ai_provider_params")
with op.batch_alter_table("ai_provider_headers", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_ai_provider_headers_provider_id"))
batch_op.drop_index(batch_op.f("ix_ai_provider_headers_created_at"))
op.drop_table("ai_provider_headers")
with op.batch_alter_table("ai_providers", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_ai_providers_settings_id"))
batch_op.drop_index(batch_op.f("ix_ai_providers_name"))
batch_op.drop_index(batch_op.f("ix_ai_providers_created_at"))
op.drop_table("ai_providers")
with op.batch_alter_table("ai_provider_settings", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_ai_provider_settings_image_provider_id"))
batch_op.drop_index(batch_op.f("ix_ai_provider_settings_group_id"))
batch_op.drop_index(batch_op.f("ix_ai_provider_settings_created_at"))
batch_op.drop_index(batch_op.f("ix_ai_provider_settings_audio_provider_id"))
batch_op.drop_index(batch_op.f("ix_ai_provider_settings_default_provider_id"))
op.drop_table("ai_provider_settings")
# ### end Alembic commands ###

Some files were not shown because too many files have changed in this diff Show More