Compare commits

...

24 Commits

Author SHA1 Message Date
Hayden
4b9dcf95f9 Fix/version number (#960)
* npm install

* set versions

* bump beta label

* bump app version

* v0.5.5 changelog

* allow higher version of python

* add discord release notification
2022-02-03 12:29:48 -09:00
Felix Breidenstein
e82020b7e0 Fix version number for 0.5.4 (#957)
* Add changelog for v0.5.4 to the docs

* Fix APP_VERSION in config file

This fixed #926
2022-02-03 11:33:56 -09:00
Steven Massaro
cfa5c9606d add a line to the docs that clarifies that the run.sh file must have LF line endings (#922) 2022-02-03 11:32:27 -09:00
Steven Massaro
951f92e1ba remove leading and trailing whitespaces from bulk add entries (#921) 2022-02-03 11:32:09 -09:00
Hayden
8a8ee40f4f New Crowdin updates (#930)
* New translations en-US.json (Ukrainian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Russian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Russian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Ukrainian)

* New translations en-US.json (Russian)

* New translations en-US.json (Turkish)
2022-02-03 10:21:16 -09:00
MidnightRising
9d9de3aa77 Trims URL when importing a recipe (#909)
Co-authored-by: Midnight <midnight1@protonmail.com>
2022-01-07 12:12:59 -09:00
MidnightRising
bee7a910b7 Adjusts the image view from height to min-height (#908)
Co-authored-by: Midnight <midnight1@protonmail.com>
2022-01-07 12:10:02 -09:00
Hayden
7f03b1bea8 New Crowdin updates (#886)
* New translations en-US.json (Swedish)

* New translations en-US.json (Swedish)

* New translations en-US.json (French, Canada)

* New translations en-US.json (Danish)
2022-01-01 11:07:54 -09:00
sephrat
d6cd5df449 Add support for fr-CA language (#865)
Fixes #816
2021-12-15 15:32:52 -09:00
cadamswaite
cc2b53a211 White background favicons-2 (#860)
* New favicons

* Add references to new image paths
2021-12-15 15:32:38 -09:00
Hayden
5936c919c4 New translations en-US.json (French, Canada) (#854) 2021-12-04 16:02:46 -09:00
cadamswaite
00bc9a15ec Allow schema to give images as dict (#859) 2021-12-04 16:02:35 -09:00
Hayden
8154ee548a Chore/bump deps (#853)
* add LDAP dep

* bump extruct and scraper

* allow for disabling auto backup

* v0.5.4 changelog
2021-12-01 21:07:17 -09:00
Hayden
591bf9d98f Update v1-task.yaml 2021-11-24 11:46:43 -09:00
Hayden
f202b1f922 Update v1-task.yaml 2021-11-24 11:45:59 -09:00
Hayden
17b2e37e4e Update v1-task.yaml 2021-11-24 11:40:53 -09:00
Hayden
0ec8087ac6 Rename v1-task to v1-task.yaml 2021-11-24 11:33:59 -09:00
Hayden
e580d6f904 Create v1-tasks template 2021-11-24 11:33:26 -09:00
dvdkon
56d9cafb68 Add LDAP authentication support (v2, onto dev) (#803)
* Add LDAP authentication support

* Add test for LDAP authentication
2021-11-24 08:59:03 -09:00
Hayden
32c864c703 New Crowdin updates (#818)
* New translations en-US.json (French, Canada)

* New translations en-US.json (French, Canada)

* New translations en-US.json (French, Canada)

* New translations en-US.json (French)

* New translations en-US.json (French, Canada)

* New translations en-US.json (French, Canada)

* New translations en-US.json (French)
2021-11-23 20:38:25 -09:00
Bryce Willey
37280a3da0 Improve the SWAG Community Guide (#793)
* Freshen up the SWAG documentation

Added some extra pointers for setting up HTTPS with Mealie and SWAG, and indented the `docker-compose.yml` as it should be.

* Replaced <code> html blocks with backticks

* Better formatting and comments in example config files

* Made DuckDNS consistent with other places on the page
2021-11-23 20:34:23 -09:00
cadamswaite
7f850fba98 Use firefox UA when making requests (#780) 2021-11-23 20:34:10 -09:00
J.P. Krauss
b40f201430 Allow arrow keys to function when SearchDialog is not open (#777) 2021-11-07 10:11:07 -09:00
sephrat
a0d796551c Add support for new languages (#781)
* Add support for Slovak language

* Add support for new languages

Catalan, Danish, Norwegian and Russian
2021-11-07 10:03:37 -09:00
54 changed files with 2146 additions and 1173 deletions

38
.github/ISSUE_TEMPLATE/v1-task.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: v1.0.0b Task
description: "CONTRIBUTORS ONLY: Submit a Task that needs to be completed"
title: "[v1.0.0b] [Task] - TASK DESCRIPTION"
labels:
- task
- v1
body:
- type: markdown
attributes:
value: |
Thanks for your interest in Mealie! 🚀
This is a place for Mealie contributors to find tasks that need to get done around the repository. Tasks are different than issues as they are generally related to providing a new feature or improve an existing feature. They are _generally_ not related to an issue.
**DO NOT** create a task unless
- You are a contributors who has prior approval via discord/discussions
- You have otherwise been given approval to post the tasks
Otherwise, your post will be closed/deleted.
**Interested in Taking This?**
If you're interested in completing this tasks and it hasn't already been taken, comment below and to let others know you're working on it. As you work through the task, I ask that you submit a draft pull request as soon as possible, and tag this issue so we can all collaborate as best as possible.
- type: textarea
id: problem
attributes:
label: What is the problem this task addresses?
placeholder: A clear and concise description of what the problem this task will address.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed/Possible Solution(s)?
placeholder: Provide as much context around the idea as possible with potential files and roadblocks that may come up
validations:
required: true

View File

@@ -54,3 +54,12 @@ jobs:
docker build --push \
--tag hkotel/mealie:${{ steps.mealie_version.outputs.tag }} \
--platform linux/amd64,linux/arm64 .
#
# Release Discord Notification
#
- name: Discord notification
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
uses: Ilshidur/action-discord@0.3.2
with:
args: '🚀 Version {{ EVENT_PAYLOAD.release.tag_name }} of Mealie has been released. See the release notes https://github.com/hay-kot/mealie/releases/tag/{{ EVENT_PAYLOAD.release.tag_name }}'

View File

@@ -57,6 +57,7 @@ jobs:
#----------------------------------------------
- name: Install dependencies
run: |
sudo apt-get install libsasl2-dev libldap2-dev libssl-dev
poetry install
poetry add "psycopg2-binary==2.8.6"
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'

View File

@@ -44,6 +44,8 @@ RUN apt-get update \
build-essential \
libpq-dev \
libwebp-dev \
# LDAP Dependencies
libsasl2-dev libldap2-dev libssl-dev \
gnupg gnupg2 gnupg1 \
debian-keyring \
debian-archive-keyring \

View File

@@ -0,0 +1,28 @@
# v0.5.4 - Bug Fixes
**App Version: v0.5.4**
**Database Version: v0.5.0**
## Breaking Changes
!!! error "Breaking Changes"
None
## What's Changed
* Add support for new languages by @sephrat in https://github.com/hay-kot/mealie/pull/781
* Allow arrow keys to function when SearchDialog is not open by @asymworks in https://github.com/hay-kot/mealie/pull/777
* Use firefox user agent when making requests by @cadamswaite in https://github.com/hay-kot/mealie/pull/780
* Improve the SWAG Community Guide by @BryceStevenWilley in https://github.com/hay-kot/mealie/pull/793
* New Crowdin updates by @hay-kot in https://github.com/hay-kot/mealie/pull/818
* Add LDAP authentication support (v2, onto dev) by @dvdkon in https://github.com/hay-kot/mealie/pull/803
* Auto backup is now disabled by default. Enable it by setting the AUTO_BACKUP_ENABLED env variable to true.
## New Contributors
* @asymworks made their first contribution in https://github.com/hay-kot/mealie/pull/777
* @dvdkon made their first contribution in https://github.com/hay-kot/mealie/pull/803
**Full Changelog**: https://github.com/hay-kot/mealie/compare/v0.5.3...v0.5.4

View File

@@ -0,0 +1,31 @@
# v0.5.5 - Bug Fixes
**App Version: v0.5.5**
**Database Version: v0.5.0**
## Breaking Changes
!!! error "Breaking Changes"
None
## What's Changed
* Allow schema to give images as dict by @cadamswaite in https://github.com/hay-kot/mealie/pull/859
* New Crowdin updates by @hay-kot in https://github.com/hay-kot/mealie/pull/854
* White background favicons-2 by @cadamswaite in https://github.com/hay-kot/mealie/pull/860
* Add support for fr-CA language by @sephrat in https://github.com/hay-kot/mealie/pull/865
* New Crowdin updates by @hay-kot in https://github.com/hay-kot/mealie/pull/886
* Adjusts the image view from height to min-height by @MidnightRising in https://github.com/hay-kot/mealie/pull/908
* Trims URL when importing a recipe by @MidnightRising in https://github.com/hay-kot/mealie/pull/909
* New Crowdin updates by @hay-kot in https://github.com/hay-kot/mealie/pull/930
* remove leading and trailing whitespaces from bulk add entries by @StevenMassaro in https://github.com/hay-kot/mealie/pull/921
* add a line to the docs that clarifies that the run.sh file must have LF line endings by @StevenMassaro in https://github.com/hay-kot/mealie/pull/922
* Fix version number for 0.5.4 by @fleaz in https://github.com/hay-kot/mealie/pull/957
* Bump versions (properly) @hay-kot
## New Contributors
* @StevenMassaro made their first contribution in https://github.com/hay-kot/mealie/pull/921
* @fleaz made their first contribution in https://github.com/hay-kot/mealie/pull/957
**Full Changelog**: https://github.com/hay-kot/mealie/compare/v0.5.4...v0.5.5

View File

@@ -10,6 +10,8 @@ Prerequisites
You can easily start the development stack by running `make docker-dev` in the root of the project directory. This will run and build the docker-compose.dev.yml file.
On Windows, the `mealie/run.sh` file must have LF line endings, or the mealie-api container will fail to start with the error: `/app/mealie/run.sh: not found`.
## Without Docker
Prerequisites

View File

@@ -4,89 +4,96 @@
This guide was submitted by a community member. Find something wrong? Submit a PR to get it fixed!
To make the setup of a Reverse Proxy much easier, Linuxserver.io developed [SWAG](https://github.com/linuxserver/docker-swag)
SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx web server and reverse proxy with PHP support and a built-in certbot client that automates free SSL server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention.
SWAG - Secure Web Application Gateway (formerly known as letsencrypt, no relation to Let's Encrypt™) sets up an Nginx web server and reverse proxy with PHP support and a built-in certbot client that automates free TLS server certificate generation and renewal processes (Let's Encrypt and ZeroSSL). It also contains fail2ban for intrusion prevention.
## Step 1: Get a domain
The first step is to grab a dynamic DNS if you don't have your own subdomain already. You can get this from for example [DuckDNS](https://www.duckdns.org).
If you already own a domain, you'll need to create an `A` record that points to the machine that SWAG is running on. See
the [SWAG documentation](https://docs.linuxserver.io/general/swag#create-container-via-http-validation) for more details.
## Step 2: Set-up SWAG
Then you will need to set up SWAG, the variables of the docker-compose are explained on the Github page of [SWAG](https://github.com/linuxserver/docker-swag).
This is an example of how to set it up using duckdns and docker-compose.
This is an example of how to set it up using DuckDNS and docker-compose.
!!! example "docker-compose.yml"
```yaml
version: "2.1"
services:
swag:
image: ghcr.io/linuxserver/swag
container_name: swag
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Brussels
- URL=<mydomain.duckdns>
- SUBDOMAINS=wildcard
- VALIDATION=duckdns
- CERTPROVIDER= #optional
- DNSPLUGIN= #optional
- DUCKDNSTOKEN=<duckdnstoken>
- EMAIL=<e-mail> #optional
- ONLY_SUBDOMAINS=false #optional
- EXTRA_DOMAINS=<extradomains> #optional
- STAGING=false #optional
volumes:
- /etc/config/swag:/config
ports:
- 443:443
restart: unless-stopped
swag:
image: ghcr.io/linuxserver/swag
container_name: swag
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
# valid TZs at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
- TZ=Europe/Brussels
- URL=<mydomain.duckdns>
- SUBDOMAINS=wildcard
- VALIDATION=duckdns
- CERTPROVIDER= #optional
- DNSPLUGIN= #optional
- DUCKDNSTOKEN=<duckdnstoken>
- EMAIL=<e-mail> #optional
- ONLY_SUBDOMAINS=false #optional
- EXTRA_DOMAINS=<extradomains> #optional
- STAGING=false #optional
volumes:
- /etc/config/swag:/config
ports:
- 443:443
# required if VALIDATION=http above, if you aren't using DuckDNS
- 80:80
restart: unless-stopped
```
Don't forget to change the <code>mydomain.duckns</code> into your personal domain and the <code>duckdnstoken</code> into your token and remove the brackets.
Don't forget to change the `mydomain.duckns` into your personal domain and the `duckdnstoken` into your token and remove the brackets.
You can also include the contents of the [mealie docker-compose](mealie/documentation/getting-started/install/#docker-compose-with-sqlite) in the SWAG
docker-compose, without the `ports` section under mealie. This allows SWAG and mealie to communicate on the same docker network, without
making mealie visible to other applications on your machine.
## Step 3: Change the config files
Navigate to the config folder of SWAG and head to <code>proxy-confs</code>. If you used the example above, you should navigate to: <code>/etc/config/swag/nginx/proxy-confs/</code>.
Navigate to the config folder of SWAG and head to `proxy-confs`. If you used the example above, you should navigate to: `/etc/config/swag/nginx/proxy-confs/`.
There are a lot of preconfigured files to use for different apps such as radarr, sonarr, overseerr, ...
To use the bundled configuration file, simply rename <code>mealie.subdomain.conf.sample</code> in the proxy-confs folder to <code>mealie.subdomain.conf</code>.
Alternatively, you can create a new file <code>mealie.subdomain.conf</code> in proxy-confs with the following configuration:
To use the bundled configuration file, simply rename `mealie.subdomain.conf.sample` in the proxy-confs folder to `mealie.subdomain.conf`.
Alternatively, you can create a new file `mealie.subdomain.conf` in proxy-confs with the following configuration:
!!! example "mealie.subdomain.conf"
```yaml
server {
```nginx
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mealie.*;
server_name mealie.*;
include /config/nginx/ssl.conf;
include /config/nginx/ssl.conf;
client_max_body_size 0;
client_max_body_size 0;
location / {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app mealie;
set $upstream_port 80;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}
location / {
include /config/nginx/proxy.conf;
include /config/nginx/resolver.conf;
set $upstream_app mealie;
set $upstream_port 80;
set $upstream_proto http;
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
}
}
```
## Step 4: Port-forward port 443
Since SWAG allows you to set up a secure connection, you will need to open port 443 on your router for encrypted traffic. This is way more secure than port 80 for http.
Since SWAG allows you to set up a secure connection, you will need to open port 443 on your router for encrypted traffic. This is way more secure than port 80 for http. For more information about using TLS on port 443, see [SWAG's documentation](https://docs.linuxserver.io/general/swag#cert-provider-lets-encrypt-vs-zerossl) on cert providers and port forwarding.
## Step 5: Restart SWAG
When you change anything in the config of Nginx, you will need to restart the container using <code>docker restart swag</code>.
If everything went well, you can now access mealie on the subdomain you configured: mealie.mydomain.duckdns.org
When you change anything in the config of Nginx, you will need to restart the container using `docker restart swag`.
If everything went well, you can now access mealie on the subdomain you configured: `mealie.mydomain.duckdns.org`

View File

@@ -128,12 +128,17 @@ services:
| POSTGRES_PORT | 5432 | Postgres database port |
| POSTGRES_DB | mealie | Postgres database name |
| TOKEN_TIME | 2 | The time in hours that a login/auth token is valid |
| LDAP_AUTH_ENABLED | False | Authenticate via an external LDAP server in addidion to built-in Mealie auth |
| LDAP_SERVER_URL | None | LDAP server URL (e.g. ldap://ldap.example.com) |
| LDAP_BIND_TEMPLATE | None | Templated DN for users, `{}` will be replaced with the username (e.g. `cn={},dc=example,dc=com`) |
| LDAP_ADMIN_FILTER | None | Optional LDAP filter, which tells Mealie the LDAP user is an admin (e.g. `(memberOf=cn=admins,dc=example,dc=com)`) |
| RECIPE_PUBLIC | True | Default Recipe Settings - Make Recipe Public |
| RECIPE_SHOW_NUTRITION | True | Default Recipe Settings - Show Recipe Nutrition |
| RECIPE_SHOW_ASSETS | True | Default Recipe Settings - Show Recipe Assets |
| RECIPE_LANDSCAPE_VIEW | True | Default Recipe Settings - Set Landscape View |
| RECIPE_DISABLE_COMMENTS | False | Default Recipe Settings - Disable Comments |
| RECIPE_DISABLE_AMOUNT | False | Default Recipe Settings - Disable Amount |
| AUTO_BACKUP_ENABLED | False | Disable/Enable Mealie's Auto Backup Function |
| API_PORT | 9000 | The port exposed by backend API. **Do not change this if you're running in Docker** |
| API_DOCS | True | Turns on/off access to the API documentation locally. |
| TZ | UTC | Must be set to get correct date/time on the server |

View File

@@ -94,7 +94,9 @@ nav:
- Style Guide: "contributors/developers-guide/style-guide.md"
- Development Road Map: "roadmap.md"
- Change Log:
- v0.5.3 - Bug Fixes: "changelog/v0.5.3.md"
- v0.5.5 Bug Fixes: "changelog/v0.5.5.md"
- v0.5.4 Bug Fixes: "changelog/v0.5.4.md"
- v0.5.3 Bug Fixes: "changelog/v0.5.3.md"
- v0.5.2 Misc Updates: "changelog/v0.5.2.md"
- v0.5.1 Bug Fixes: "changelog/v0.5.1.md"
- v0.5.0 General Upgrades: "changelog/v0.5.0.md"

View File

@@ -5,7 +5,6 @@
"requires": true,
"packages": {
"": {
"name": "frontend",
"version": "0.1.0",
"dependencies": {
"@adapttive/vue-markdown": "^4.0.1",
@@ -20542,7 +20541,6 @@
"integrity": "sha512-pM7CR3yXB6L8Gfn6EmX7FLNE3+V/15I3o33GkSNsWvgsMp6HVGXKkXgojrcfUUauyL1LZOdvTmu4enU2RePGHw==",
"dev": true,
"requires": {
"@babel/core": "^7.11.0",
"@babel/helper-compilation-targets": "^7.9.6",
"@babel/helper-module-imports": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
@@ -20555,7 +20553,6 @@
"@vue/babel-plugin-jsx": "^1.0.3",
"@vue/babel-preset-jsx": "^1.2.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
"core-js": "^3.6.5",
"core-js-compat": "^3.6.5",
"semver": "^6.1.0"
}

View File

@@ -24,7 +24,6 @@
"vuex-persistedstate": "^4.0.0-beta.3"
},
"devDependencies": {
"typeface-roboto": "^1.1.13",
"@intlify/vue-i18n-loader": "^1.1.0",
"@mdi/font": "^5.9.55",
"@mdi/js": "^5.9.55",
@@ -40,6 +39,7 @@
"preload-webpack-plugin": "^2.3.0",
"sass": "^1.34.1",
"sass-loader": "^8.0.2",
"typeface-roboto": "^1.1.13",
"vue-cli-plugin-i18n": "~1.0.1",
"vue-cli-plugin-vuetify": "^2.4.1",
"vue-cli-plugin-webpack-bundle-analyzer": "^4.0.0",
@@ -72,4 +72,4 @@
"last 2 versions",
"not dead"
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,3 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256" version="1.1">
<path d="M 162.083 54.642 C 148.745 68.272, 137.170 80.703, 136.362 82.266 C 133.689 87.435, 133.522 94.130, 135.929 99.573 C 137.122 102.269, 139.070 105.510, 140.258 106.775 L 142.418 109.074 90.974 160.526 L 39.529 211.979 46.999 219.499 L 54.470 227.020 91.235 190.265 L 128 153.510 164.765 190.265 L 201.530 227.020 209 219.500 L 216.470 211.980 179.725 175.225 L 142.980 138.470 150.320 131.178 C 156.858 124.685, 157.808 124.063, 159.001 125.501 C 162.066 129.195, 168.873 132.163, 174.392 132.213 C 183.508 132.295, 186.374 130.174, 212.477 104.038 L 236.454 80.030 231.501 75.001 L 226.548 69.973 209.288 87.212 L 192.027 104.452 187 99.500 L 181.973 94.548 199.212 77.288 L 216.452 60.027 211.500 55 L 206.548 49.973 189.288 67.212 L 172.027 84.452 167 79.500 L 161.973 74.548 179.225 57.275 L 196.477 40.001 191.406 34.930 L 186.335 29.859 162.083 54.642 M 38.429 41.250 C 31.557 49.376, 28.011 62.815, 29.835 73.824 C 31.955 86.615, 34.508 90.093, 61.720 117.253 L 86.520 142.005 101.501 126.999 L 116.482 111.993 79.496 74.996 C 59.154 54.648, 42.210 38, 41.844 38 C 41.478 38, 39.941 39.462, 38.429 41.250" stroke="none" fill="black" fill-rule="evenodd"/>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M4948 6348 c-662 -677 -956 -982 -1123 -1168 -32 -36 -62 -67 -65
-70 -3 -3 -31 -35 -62 -71 -127 -151 -157 -391 -77 -600 26 -68 117 -233 137
-249 4 -3 25 -25 47 -48 l40 -42 -1679 -1679 -1678 -1678 244 -246 243 -247
1200 1200 1199 1199 1192 -1192 c656 -655 1197 -1193 1202 -1195 10 -3 473
459 480 478 2 5 -534 547 -1191 1204 l-1194 1195 185 183 c250 248 262 258
296 258 11 0 41 -19 66 -43 139 -131 331 -199 538 -190 160 6 273 63 475 236
132 114 199 179 845 822 l642 640 -161 163 c-88 90 -162 162 -164 160 -3 -1
-256 -254 -564 -561 l-560 -559 -160 158 c-89 87 -161 162 -161 165 0 4 251
259 559 567 l558 560 -159 161 c-87 89 -161 161 -164 161 -3 0 -258 -252 -566
-559 l-560 -560 -164 162 -164 162 560 560 c308 308 560 563 560 566 0 5 -194
202 -292 297 l-34 32 -326 -332z"/>
<path d="M489 6349 c-108 -115 -190 -257 -254 -440 -20 -57 -35 -104 -34 -104
1 0 -3 -22 -9 -50 -42 -181 -46 -400 -11 -568 72 -343 178 -493 781 -1102 199
-202 1018 -1020 1054 -1055 6 -5 974 962 974 973 0 9 -1704 1713 -2130 2130
-156 152 -291 277 -299 277 -9 0 -41 -27 -72 -61z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -3,77 +3,29 @@
"short_name": "Mealie",
"icons": [
{
"src": "./img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
"src": "./img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "./img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
"src": "./img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "./img/icons/android-chrome-maskable-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
},
{
"src": "./img/icons/android-chrome-maskable-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "./img/icons/apple-touch-icon-60x60.png",
"sizes": "60x60",
"type": "image/png"
},
{
"src": "./img/icons/apple-touch-icon-76x76.png",
"sizes": "76x76",
"type": "image/png"
},
{
"src": "./img/icons/apple-touch-icon-120x120.png",
"sizes": "120x120",
"type": "image/png"
},
{
"src": "./img/icons/apple-touch-icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "./img/icons/apple-touch-icon-180x180.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "./img/icons/apple-touch-icon.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "./img/icons/favicon-16x16.png",
"sizes": "16x16",
"type": "image/png"
},
{
"src": "./img/icons/favicon-32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "./img/icons/msapplication-icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "./img/icons/mstile-150x150.png",
"sizes": "150x150",
"type": "image/png"
}
}
],
"start_url": ".",
"display": "standalone",

View File

@@ -5,7 +5,7 @@
<v-main>
<v-banner v-if="demo" sticky>
<div class="text-center">
<b> This is a Demo of the v0.5.4 (BETA) </b> | Username: changeme@email.com | Password: demo
<b> This is a Demo of the v0.5.6 (BETA) </b> | Username: changeme@email.com | Password: demo
</div>
</v-banner>
<GlobalSnackbar />
@@ -136,4 +136,3 @@ export default {
scrollbar-color: transparent transparent;
}
</style>

View File

@@ -46,7 +46,7 @@ export default {
}
});
return split;
return split.map((element) => element.trim());
},
save() {
this.$emit("bulk-data", this.splitText());

View File

@@ -136,16 +136,18 @@ export default {
this.$emit(SELECTED_EVENT, recipe);
},
onUpDown(e) {
if (e.keyCode === 38) {
e.preventDefault();
this.selectedIndex--;
} else if (e.keyCode === 40) {
e.preventDefault();
this.selectedIndex++;
} else {
return;
if (this.dialog) {
if (e.keyCode === 38) {
e.preventDefault();
this.selectedIndex--;
} else if (e.keyCode === 40) {
e.preventDefault();
this.selectedIndex++;
} else {
return;
}
this.selectRecipe();
}
this.selectRecipe();
},
resetSelected() {
this.searchString = "";
@@ -169,4 +171,4 @@ export default {
</script>
<style >
</style>
</style>

View File

@@ -177,6 +177,7 @@ export default {
computed: {
recipeURL: {
set(recipe_import_url) {
recipe_import_url = recipe_import_url.trim()
this.$router.replace({ query: { ...this.$route.query, recipe_import_url } });
},
get() {
@@ -234,7 +235,7 @@ export default {
this.processing = false;
},
isValidWebUrl(url) {
let regEx = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,256}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$/gm;
let regEx = /^\s*https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,256}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)\s*$/gm;
return regEx.test(url) ? true : this.$t('new-recipe.must-be-a-valid-url');
},
},

View File

@@ -0,0 +1,21 @@
{
"short": {
"month": "short",
"day": "numeric",
"weekday": "long"
},
"medium": {
"month": "long",
"day": "numeric",
"weekday": "long",
"year": "numeric"
},
"long": {
"year": "numeric",
"month": "long",
"day": "numeric",
"weekday": "long",
"hour": "numeric",
"minute": "numeric"
}
}

View File

@@ -123,8 +123,8 @@
"token": "Token",
"tuesday": "Tirsdag",
"type": "Type",
"update": "Opdater",
"updated": "Opdateret",
"update": "Gem",
"updated": "Ændret",
"upload": "Upload",
"url": "URL",
"view": "Se",
@@ -137,7 +137,7 @@
"cannot-delete-group-with-users": "En gruppe med brugere i kan ikke blive slettet",
"confirm-group-deletion": "Bekræft sletning af gruppe",
"create-group": "Opret gruppe",
"error-updating-group": "Fejl ved opdatering af gruppe",
"error-updating-group": "Fejl ved ændring af gruppe",
"group": "Gruppe",
"group-deleted": "Gruppe slettet",
"group-deletion-failed": "Sletning af gruppe fejlede",
@@ -168,8 +168,8 @@
"mealplan-deleted": "Madplan slettet",
"mealplan-deletion-failed": "Sletning af madplan fejlede",
"mealplan-settings": "Madplansindstillinger",
"mealplan-update-failed": "Opdatering af madplanen fejlede",
"mealplan-updated": "Madplanen blev opdateret",
"mealplan-update-failed": "Ændring af madplanen fejlede",
"mealplan-updated": "Madplanen blev ændret",
"no-meal-plan-defined-yet": "Ingen madplan er defineret",
"no-meal-planned-for-today": "Ingen ret er planlagt til i dag",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Kun opskrifter med disse kategorier vil blive brugt i madplaner",
@@ -248,7 +248,7 @@
"milligrams": "milligram",
"new-key-name": "Nyt nøglenavn",
"no-white-space-allowed": "Mellemrum er ikke tilladt",
"note": "Bemærk",
"note": "Bemærkninger",
"nutrition": "Ernæring",
"object-key": "Objektnøgle",
"object-value": "Objektværdi",
@@ -261,7 +261,7 @@
"recipe-creation-failed": "Oprettelse af opskrift fejlede",
"recipe-deleted": "Opskrift slettet",
"recipe-image": "Opskriftsbillede",
"recipe-image-updated": "Opskriftsbillede opdateret",
"recipe-image-updated": "Opskriftsbillede ændret",
"recipe-name": "Opskriftens navn",
"recipe-settings": "Opskriftsindstillinger",
"recipe-update-failed": "Opdatering af opskrift fejlede",

View File

@@ -0,0 +1,489 @@
{
"about": {
"about": "À propos",
"about-mealie": "À propos de Mealie",
"api-docs": "Documentation de l'API",
"api-port": "Port de l'API",
"application-mode": "Mode de l'application",
"database-type": "Type de base de données",
"database-url": "URL de la base de données",
"default-group": "Groupe par défaut",
"demo": "Oui",
"demo-status": "Mode démo",
"development": "Développement",
"docs": "Documentation",
"download-log": "Télécharger les logs",
"download-recipe-json": "Dernier JSON récupéré",
"github": "GitHub",
"log-lines": "Lignes de log",
"not-demo": "Non",
"portfolio": "Portfolio",
"production": "Production",
"support": "Soutenir",
"version": "Version"
},
"asset": {
"assets": "Ressources",
"code": "Code",
"file": "Fichier",
"image": "Image",
"new-asset": "Nouvelle ressource",
"pdf": "PDF",
"recipe": "Recette",
"show-assets": "Afficher les ressources"
},
"category": {
"category-created": "Catégorie créée",
"category-creation-failed": "La création de la catégorie a échoué",
"category-deleted": "Catégorie supprimée",
"category-deletion-failed": "La suppression de la catégorie a échoué",
"category-filter": "Filtre par catégories",
"category-update-failed": "La mise à jour de la catégorie a échoué",
"category-updated": "Catégorie mise à jour",
"uncategorized-count": "{count} non catégorisée|{count} non catégorisées"
},
"events": {
"apprise-url": "URL apprise",
"database": "Base de données",
"delete-event": "Supprimer lévènement",
"new-notification-form-description": "Mealie utilise la bibliothèque apprise pour générer des notifications. Elle propose de nombreux services à utiliser pour les notifications. Consultez leur wiki pour un guide complet sur la façon de créer l'URL de votre service. Si disponible, sélectionner le type de votre notification peut inclure des fonctionnalités supplémentaires.",
"new-version": "Nouvelle version disponible!",
"notification": "Notification",
"refresh": "Rafraîchir",
"scheduled": "Planifié",
"something-went-wrong": "Une erreur s'est produite!",
"subscribed-events": "Évènements suivis",
"test-message-sent": "Message de test envoyé"
},
"general": {
"cancel": "Annuler",
"clear": "Effacer",
"close": "Fermer",
"confirm": "Confirmer",
"confirm-delete-generic": "Voulez-vous vraiment supprimer ceci?",
"copied": "Copié",
"create": "Créer",
"created": "Créé",
"custom": "Personnalisé",
"dashboard": "Tableau de bord",
"delete": "Supprimer",
"disabled": "Désactivé",
"download": "Télécharger",
"edit": "Modifier",
"enabled": "Activé",
"exception": "Exception",
"failed-count": "Échec : {count}",
"failure-uploading-file": "Échec de l'envoi du fichier",
"favorites": "Favoris",
"field-required": "Champ obligatoire",
"file-folder-not-found": "Fichier/dossier introuvable",
"file-uploaded": "Fichier envoyé",
"filter": "Filtrer",
"friday": "Vendredi",
"general": "Général",
"get": "Envoyer",
"home": "Page d'accueil",
"image": "Image",
"image-upload-failed": "Le téléchargement de l'image a échoué",
"import": "Importer",
"json": "JSON",
"keyword": "Mot-clé",
"link-copied": "Lien copié",
"loading-recipes": "Chargement des recettes",
"monday": "Lundi",
"name": "Nom",
"new": "Nouveau",
"no": "Non",
"no-recipe-found": "Aucune recette trouvée",
"ok": "OK",
"options": "Options :",
"print": "Imprimer",
"random": "Aléatoire",
"rating": "Note",
"recent": "Récent",
"recipe": "Recette",
"recipes": "Recettes",
"rename-object": "Renommer {0}",
"reset": "Réinitialiser",
"saturday": "Samedi",
"save": "Sauvegarder",
"settings": "Paramètres",
"share": "Partager",
"shuffle": "Aléatoire",
"sort": "Trier",
"sort-alphabetically": "Alphabétique",
"status": "Statut",
"submit": "Importer",
"success-count": "Succès : {count}",
"sunday": "Dimanche",
"templates": "Modèles :",
"test": "Tester",
"themes": "Thèmes",
"thursday": "Jeudi",
"token": "Jeton",
"tuesday": "Mardi",
"type": "Type",
"update": "Mettre à jour",
"updated": "Mis à jour",
"upload": "Importer",
"url": "URL",
"view": "Afficher",
"wednesday": "Mercredi",
"yes": "Oui"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Êtes-vous certain de vouloir supprimer <b>{groupName}<b/>?",
"cannot-delete-default-group": "Vous ne pouvez pas supprimer le groupe par défaut",
"cannot-delete-group-with-users": "Impossible de supprimer un groupe avec des utilisateurs",
"confirm-group-deletion": "Confirmer la suppression du groupe",
"create-group": "Créer un groupe",
"error-updating-group": "Erreur lors de la mise à jour du groupe",
"group": "Groupe",
"group-deleted": "Groupe supprimé",
"group-deletion-failed": "Échec de la suppression du groupe",
"group-id-with-value": "ID groupe : {groupID}",
"group-name": "Nom du groupe",
"group-not-found": "Groupe non trouvé",
"group-with-value": "Groupe : {groupID}",
"groups": "Groupes",
"manage-groups": "Gérer les groupes",
"user-group": "Groupe d'utilisateurs",
"user-group-created": "Groupe d'utilisateurs créé",
"user-group-creation-failed": "La création du groupe d'utilisateur a échoué"
},
"meal-plan": {
"create-a-new-meal-plan": "Créer un nouveau menu",
"dinner-this-week": "Menu de la semaine",
"dinner-today": "Menu du jour",
"dinner-tonight": "AU MENU CE SOIR",
"edit-meal-plan": "Modifier le menu",
"end-date": "Date de fin",
"group": "Regrouper (Bêta)",
"main": "Plat principal",
"meal-planner": "Menus",
"meal-plans": "Menus",
"mealplan-categories": "CATÉGORIES DES MENUS",
"mealplan-created": "Menu créé",
"mealplan-creation-failed": "La création du menu a échoué",
"mealplan-deleted": "Menu supprimé",
"mealplan-deletion-failed": "La suppression du menu a échoué",
"mealplan-settings": "Paramètres des menus",
"mealplan-update-failed": "La mise à jour du menu a échoué",
"mealplan-updated": "Menu mis à jour",
"no-meal-plan-defined-yet": "Aucun menu planifié",
"no-meal-planned-for-today": "Aucun repas prévu pour aujourd'hui",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Seules les recettes appartenant à ces catégories seront utilisées dans les menus",
"planner": "Planificateur",
"quick-week": "Semaine rapide",
"side": "Accompagnement",
"sides": "Accompagnements",
"start-date": "Date de début"
},
"migration": {
"chowdown": {
"description": "Importer des recettes depuis Chowdown",
"title": "Chowdown"
},
"migration-data-removed": "Données de migration supprimées",
"nextcloud": {
"description": "Importer des recettes depuis un livre de recettes Nextcloud existant",
"title": "Nextcloud Cookbook"
},
"no-migration-data-available": "Aucune donnée d'importation n'est disponible",
"recipe-migration": "Migrer les recettes"
},
"new-recipe": {
"bulk-add": "Ajouter en masse",
"error-details": "Seuls les sites Web contenant ld+json ou des microdonnées peuvent être importés par Mealie. La plupart des grands sites web de recettes sont compatibles avec cette structure de données. Si votre site ne peut pas être importé mais qu'il y a des données JSON dans le journal, veuillez soumettre un problème GitHub avec l'URL et les données.",
"error-title": "On dirait qu'on n'a pas pu trouver quoi que ce soit",
"from-url": "Depuis une adresse Web",
"github-issues": "Anomalies GitHub",
"google-ld-json-info": "Infos Json-Ld Google",
"must-be-a-valid-url": "Doit être une URL valide",
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Copiez votre recette ici. Chaque ligne sera traitée comme un objet de la liste",
"recipe-markup-specification": "Spécification du marquage des recettes",
"recipe-url": "Adresse de la recette",
"upload-a-recipe": "Télécharger une recette",
"upload-individual-zip-file": "Chargez un fichier .zip exporté depuis une autre instance Mealie.",
"url-form-hint": "Copiez et collez un lien depuis votre site de recettes favori",
"view-scraped-data": "Voir les données récupérées"
},
"page": {
"404-page-not-found": "404 Page introuvable",
"all-recipes": "Toutes les recettes",
"new-page-created": "Nouvelle page créée",
"page": "Page",
"page-creation-failed": "La création de la page a échoué",
"page-deleted": "Page supprimée",
"page-deletion-failed": "La suppression de la page a échoué",
"page-update-failed": "La mise à jour de la page a échoué",
"page-updated": "Page mise à jour",
"pages-update-failed": "La mise à jour des pages a échoué",
"pages-updated": "Pages mises à jour"
},
"recipe": {
"add-key": "Ajouter une clé",
"add-to-favorites": "Ajouter aux favoris",
"api-extras": "Extras API",
"calories": "Calories",
"calories-suffix": "calories",
"carbohydrate-content": "Glucides",
"categories": "Catégories",
"comment-action": "Commenter",
"comments": "Commentaires",
"delete-confirmation": "Êtes-vous sûr(e) de vouloir supprimer cette recette?",
"delete-recipe": "Supprimer la recette",
"description": "Description",
"disable-amount": "Désactiver les quantités d'ingrédients",
"disable-comments": "Désactiver les commentaires",
"fat-content": "Matières grasses",
"fiber-content": "Fibres",
"grams": "grammes",
"ingredient": "Ingrédient",
"ingredients": "Ingrédients",
"insert-section": "Insérer une section",
"instructions": "Instructions",
"key-name-required": "Un nom de clé est requis",
"landscape-view-coming-soon": "Vue paysage (bientôt disponible)",
"milligrams": "milligrammes",
"new-key-name": "Nouveau nom de clé",
"no-white-space-allowed": "Aucun espace blanc autorisé",
"note": "Note",
"nutrition": "Valeurs nutritionnelles",
"object-key": "Clé d'objet",
"object-value": "Valeur d'objet",
"original-url": "Recette originale",
"perform-time": "Temps de cuisson",
"prep-time": "Temps de préparation",
"protein-content": "Protéines",
"public-recipe": "Recette publique",
"recipe-created": "Recette créée",
"recipe-creation-failed": "La création de la recette a échoué",
"recipe-deleted": "Recette supprimée",
"recipe-image": "Image de la recette",
"recipe-image-updated": "L'image de la recette a été mise à jour",
"recipe-name": "Nom de la recette",
"recipe-settings": "Paramètres de la recette",
"recipe-update-failed": "La mise à jour de la recette a échoué",
"recipe-updated": "Recette mise à jour",
"remove-from-favorites": "Supprimer des favoris",
"remove-section": "Supprimer une section",
"save-recipe-before-use": "Enregistrez la recette avant utilisation",
"section-title": "Titre de la section",
"servings": "Portions",
"share-recipe-message": "Je voulais partager ma recette de {0} avec vous.",
"show-nutrition-values": "Afficher les valeurs nutritionnelles",
"sodium-content": "Sodium",
"step-index": "Étape {step}",
"sugar-content": "Sucres",
"title": "Titre",
"total-time": "Temps total",
"unable-to-delete-recipe": "Impossible de supprimer la recette"
},
"reicpe": {
"no-recipe": "Pas de recette"
},
"search": {
"advanced-search": "Recherche avancée",
"and": "et",
"exclude": "Exclure",
"include": "Inclure",
"max-results": "Nombre de résultats maximum",
"or": "Ou",
"results": "Résultats",
"search": "Rechercher",
"search-mealie": "Rechercher dans Mealie (appuyez sur /)",
"search-placeholder": "Rechercher...",
"tag-filter": "Filtre par mots-clés"
},
"settings": {
"add-a-new-theme": "Ajouter un nouveau thème",
"admin-settings": "Paramètres d'administration",
"backup": {
"backup-created-at-response-export_path": "Sauvegarde créée dans {path}",
"backup-deleted": "Sauvegarde supprimée",
"backup-tag": "Tag de la sauvegarde",
"create-heading": "Créer une sauvegarde",
"delete-backup": "Supprimer la sauvegarde",
"error-creating-backup-see-log-file": "Erreur de création de la sauvegarde. Voir les logs",
"full-backup": "Sauvegarde complète",
"import-summary": "Résumé de l'importation",
"partial-backup": "Sauvegarde partielle",
"unable-to-delete-backup": "Impossible de supprimer la sauvegarde."
},
"backup-and-exports": "Sauvegardes",
"change-password": "Modifier le mot de passe",
"current": "Version :",
"custom-pages": "Pages personnalisées",
"edit-page": "Modifier la page",
"events": "Évènements",
"first-day-of-week": "Premier jour de la semaine",
"group-settings-updated": "Paramètres du groupe mis à jour",
"homepage": {
"all-categories": "Toutes les catégories",
"card-per-section": "Tuiles par section",
"home-page": "Page d'accueil",
"home-page-sections": "Sections de la page d'accueil",
"show-recent": "Afficher les récentes"
},
"language": "Langue",
"latest": "Dernière",
"local-api": "API locale",
"locale-settings": "Paramètres régionaux",
"migrations": "Migrations",
"new-page": "Nouvelle page",
"notify": "Notifier",
"organize": "Organiser",
"page-name": "Nom de la page",
"pages": "Pages",
"profile": "Profil",
"remove-existing-entries-matching-imported-entries": "Supprimer les entrées existantes correspondant aux entrées importées",
"set-new-time": "Indiquer une nouvelle heure",
"settings-update-failed": "La mise à jour des paramètres a échoué",
"settings-updated": "Paramètres mis à jour",
"site-settings": "Paramètres du site",
"theme": {
"accent": "Accentué",
"dark": "Sombre",
"default-to-system": "Identique au système",
"error": "Erreur",
"error-creating-theme-see-log-file": "Erreur lors de la création du thème. Consultez les logs.",
"error-deleting-theme": "Erreur lors de la suppression du thème",
"error-updating-theme": "Erreur lors de la mise à jour du thème",
"info": "Information",
"light": "Clair",
"primary": "Primaire",
"secondary": "Secondaire",
"success": "Succès",
"switch-to-dark-mode": "Basculer en mode sombre",
"switch-to-light-mode": "Basculer en mode clair",
"theme-deleted": "Thème supprimé",
"theme-name": "Nom du thème",
"theme-name-is-required": "Un nom de thème est requis.",
"theme-saved": "Thème enregistré",
"theme-updated": "Thème mis à jour",
"warning": "Avertissement"
},
"token": {
"active-tokens": "JETONS ACTIFS",
"api-token": "Jeton de l'API",
"api-tokens": "Jetons de l'API",
"copy-this-token-for-use-with-an-external-application-this-token-will-not-be-viewable-again": "Copiez ce jeton pour l'utiliser avec une application externe. Ce jeton ne sera plus consultable.",
"create-an-api-token": "Créer un jeton API",
"token-name": "Nom du jeton"
},
"toolbox": {
"assign-all": "Assigner tout",
"bulk-assign": "Assigner en masse",
"new-name": "Nouveau nom",
"no-unused-items": "Aucun élément inutilisé",
"recipes-affected": "Aucune recette affectée|Une recette affectée|{count} recettes affectées",
"remove-unused": "Supprimer orphelins",
"title-case-all": "Majuscules partout",
"toolbox": "Boîte à outils",
"unorganized": "Non organisé(s)"
},
"webhooks": {
"test-webhooks": "Tester les webhooks",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "Les liens dans cette liste recevront les webhooks contenant les recettes pour le menu du jour. Actuellement, les webhooks se lancent à",
"webhook-url": "Lien du webhook",
"webhooks-caps": "WEBHOOKS"
}
},
"shopping-list": {
"all-lists": "Toutes les listes",
"create-shopping-list": "Créer une liste d'épicerie",
"from-recipe": "À partir d'une recette",
"list-name": "Nom de la liste",
"new-list": "Nouvelle liste",
"quantity": "Quantité : {0}",
"shopping-list": "Liste d'épicerie",
"shopping-lists": "Listes d'épicerie"
},
"sidebar": {
"all-recipes": "Les recettes",
"categories": "Catégories",
"dashboard": "Console",
"home-page": "Accueil",
"manage-users": "Utilisateurs",
"migrations": "Migrations",
"profile": "Profil",
"search": "Rechercher",
"site-settings": "Paramètres",
"tags": "Mots-clés",
"toolbox": "Boîte à outils"
},
"signup": {
"error-signing-up": "Erreur lors de l'inscription",
"sign-up": "S'inscrire",
"sign-up-link-created": "Lien d'inscription créé",
"sign-up-link-creation-failed": "La création du lien d'inscription a échoué",
"sign-up-links": "Liens d'inscription",
"sign-up-token-deleted": "Jeton d'inscription supprimé",
"sign-up-token-deletion-failed": "La suppression du jeton d'inscription a échoué",
"welcome-to-mealie": "Bienvenue sur Mealie! Pour devenir un utilisateur de cette instance, vous devez avoir un lien d'invitation valide. Si vous n'avez pas reçu d'invitation, vous ne pouvez pas vous inscrire. Pour recevoir un lien, contactez l'administrateur du site."
},
"tag": {
"tag-created": "Mot-clé créé",
"tag-creation-failed": "La création du mot-clé a échoué",
"tag-deleted": "Mot-clé supprimé",
"tag-deletion-failed": "La suppression du mot-clé a échoué",
"tag-update-failed": "La mise à jour du mot-clé a échoué",
"tag-updated": "Mot-clé mis à jour",
"tags": "Mots-clés",
"untagged-count": "{count} sans mot-clés"
},
"user": {
"admin": "Administrateur",
"are-you-sure-you-want-to-delete-the-link": "Voulez-vous réellement supprimer le lien <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "Voulez-vous réellement supprimer l'utilisateur <b>{activeName} ID : {activeId}<b/>?",
"confirm-link-deletion": "Confirmer la suppression du lien",
"confirm-password": "Confirmer mot de passe",
"confirm-user-deletion": "Confirmer la suppression",
"could-not-validate-credentials": "La vérification de vos identifiants a échoué",
"create-link": "Créer un lien",
"create-user": "Créer utilisateur",
"current-password": "Mot de passe actuel",
"e-mail-must-be-valid": "Le courriel doit être valide",
"edit-user": "Modifier l'utilisateur",
"email": "Courriel",
"error-cannot-delete-super-user": "Erreur! Impossible de supprimer le super utilisateur",
"existing-password-does-not-match": "Le mot de passe actuel ne correspond pas",
"full-name": "Nom",
"link-id": "ID du lien",
"link-name": "Nom du lien",
"login": "Connexion",
"logout": "Déconnexion",
"manage-users": "Gérer les utilisateurs",
"new-password": "Nouveau mot de passe",
"new-user": "Nouvel utilisateur",
"password": "Mot de passe",
"password-has-been-reset-to-the-default-password": "Le mot de passe a été réinitialisé à la valeur par défaut",
"password-must-match": "Les mots de passe doivent correspondre",
"password-reset-failed": "Échec de la réinitialisation du mot de passe",
"password-updated": "Mot de passe mis à jour",
"reset-password": "Réinitialiser le mot de passe",
"sign-in": "Se connecter",
"total-mealplans": "Nombre de menus",
"total-users": "Nombre d'utilisateurs",
"upload-photo": "Importer une photo",
"use-8-characters-or-more-for-your-password": "Utilisez au moins 8 caractères pour votre mot de passe",
"user": "Utilisateur",
"user-created": "Utilisateur créé",
"user-creation-failed": "La création de l'utilisateur a échoué",
"user-deleted": "Utilisateur supprimé",
"user-id": "ID utilisateur",
"user-id-with-value": "ID utilisateur : {id}",
"user-password": "Mot de passe de l'utilisateur",
"user-successfully-logged-in": "Connexion réussie",
"user-update-failed": "La mise à jour de l'utilisateur a échoué",
"user-updated": "Utilisateur mis à jour",
"username": "Nom d'utilisateur",
"users": "Utilisateurs",
"users-header": "UTILISATEURS",
"webhook-time": "Heure du Webhook",
"webhooks-enabled": "Webhooks activés",
"you-are-not-allowed-to-create-a-user": "Vous n'avez pas le droit de créer un utilisateur",
"you-are-not-allowed-to-delete-this-user": "Vous n'avez pas le droit de supprimer cet utilisateur"
}
}

View File

@@ -47,11 +47,11 @@
"database": "Base de données",
"delete-event": "Supprimer lévènement",
"new-notification-form-description": "Mealie utilise la bibliothèque Apprise pour générer des notifications. Elle propose de nombreux services à utiliser pour les notifications. Consultez leur wiki pour un guide complet sur la façon de créer l'URL de votre service. Si disponible, sélectionner le type de votre notification peut inclure des fonctionnalités supplémentaires.",
"new-version": "Nouvelle version disponible!",
"new-version": "Nouvelle version disponible !",
"notification": "Notification",
"refresh": "Rafraîchir",
"scheduled": "Planifié",
"something-went-wrong": "Une erreur s'est produite!",
"something-went-wrong": "Une erreur s'est produite !",
"subscribed-events": "Évènements suivis",
"test-message-sent": "Message de test envoyé"
},
@@ -60,7 +60,7 @@
"clear": "Effacer",
"close": "Fermer",
"confirm": "Confirmer",
"confirm-delete-generic": "Voulez-vous vraiment supprimer ceci?",
"confirm-delete-generic": "Voulez-vous vraiment supprimer ceci ?",
"copied": "Copié",
"create": "Créer",
"created": "Créé",
@@ -316,7 +316,7 @@
"current": "Version :",
"custom-pages": "Pages personnalisées",
"edit-page": "Modifier la page",
"events": "Evènements",
"events": "Évènements",
"first-day-of-week": "Premier jour de la semaine",
"group-settings-updated": "Paramètres du groupe mis à jour",
"homepage": {

View File

@@ -5,7 +5,7 @@
"api-docs": "Документация API",
"api-port": "Порт API",
"application-mode": "Статус приложения",
"database-type": "Тип БД",
"database-type": "Тип базы данных",
"database-url": "URL базы данных",
"default-group": "Группа по умолчанию",
"demo": "Демо",
@@ -18,7 +18,7 @@
"log-lines": "Строки журнала",
"not-demo": "Не демо",
"portfolio": "Портфолио",
"production": "Создание",
"production": "Пользовательский",
"support": "Поддержка",
"version": "Версия"
},
@@ -204,7 +204,7 @@
"recipe-markup-specification": "Спецификация разметки рецепта",
"recipe-url": "URL-адрес рецепта",
"upload-a-recipe": "Загрузить рецепт",
"upload-individual-zip-file": "Загрузить отдельный .zip файл, экспортированный из другой инстанции Mealie.",
"upload-individual-zip-file": "Загрузить отдельный .zip файл, экспортированный из другой Mealie.",
"url-form-hint": "Скопируйте и вставьте ссылку из вашего любимого сайта рецептов",
"view-scraped-data": "Просмотр собранных данных"
},
@@ -415,7 +415,7 @@
},
"signup": {
"error-signing-up": "Ошибка регистрации",
"sign-up": "Зарегистироваться",
"sign-up": "Зарегистрироваться",
"sign-up-link-created": "Ссылка для регистрации создана",
"sign-up-link-creation-failed": "Ошибка создания ссылки для регистрации",
"sign-up-links": "Ссылки для регистрации",

View File

@@ -201,7 +201,7 @@
"google-ld-json-info": "Google ld+json Info",
"must-be-a-valid-url": "Måste vara en korrekt URL",
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Klistra in din receptdata, varje rad kommer att hanteras som ett listelement",
"recipe-markup-specification": "Recipe Markup Specification",
"recipe-markup-specification": "Specifikation för receptmärkning",
"recipe-url": "Recept URL",
"upload-a-recipe": "Ladda upp ett recept",
"upload-individual-zip-file": "Ladda upp en individuell .zip-fil som exporteras från en annan Mealie-instans.",
@@ -385,7 +385,7 @@
},
"webhooks": {
"test-webhooks": "Testa Webhooks",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "Följande URLer kommer att mottaga webhooks med receptdata för dagens planerade måltid. Datan kommer att skickas klockan <strong>{ time }</strong>",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "Följande webbadresser kommer att mottaga webhooks med receptdata för dagens planerade måltid. För närvarande körs webhooks klockan",
"webhook-url": "Webhook URL",
"webhooks-caps": "WEBHOOKS"
}
@@ -405,11 +405,11 @@
"categories": "Kategorier",
"dashboard": "Startsida",
"home-page": "Startsida",
"manage-users": "Manage Users",
"manage-users": "Användare",
"migrations": "Importer",
"profile": "Profil",
"search": "Sök",
"site-settings": "Site Settings",
"site-settings": "Inställningar",
"tags": "Taggar",
"toolbox": "Verktygslåda"
},

View File

@@ -1,63 +1,63 @@
{
"about": {
"about": "About",
"about-mealie": "About Mealie",
"api-docs": "API Docs",
"api-port": "API Port",
"application-mode": "Application Mode",
"database-type": "Database Type",
"database-url": "Database URL",
"default-group": "Default Group",
"about": "Hakkında",
"about-mealie": "Mealie hakkında",
"api-docs": "API Dökümentasyonu",
"api-port": "API port",
"application-mode": "Uygulama Modu",
"database-type": "Veritabanı Türü",
"database-url": "Veritabanı Sunucu URL'si",
"default-group": "Varsayılan Grup",
"demo": "Demo",
"demo-status": "Demo Status",
"development": "Development",
"docs": "Docs",
"download-log": "Download Log",
"download-recipe-json": "Last Scraped JSON",
"github": "Github",
"log-lines": "Log Lines",
"not-demo": "Not Demo",
"portfolio": "Portfolio",
"production": "Production",
"support": "Support",
"version": "Version"
"demo-status": "Demo durumu",
"development": "Geliştirme",
"docs": "Dökümanlar",
"download-log": "Logu indir",
"download-recipe-json": "Son Kazınmış JSON",
"github": "GitHub",
"log-lines": "Log satırlar",
"not-demo": "Demo Değil",
"portfolio": "Portföy",
"production": "Üretim",
"support": "Destek",
"version": "Versiyon"
},
"asset": {
"assets": "Assets",
"code": "Code",
"file": "File",
"image": "Image",
"new-asset": "New Asset",
"assets": "Varlıklar",
"code": "Kod",
"file": "Dosya",
"image": "Resim",
"new-asset": "Yeni Varlık",
"pdf": "PDF",
"recipe": "Recipe",
"recipe": "Tarif",
"show-assets": "Show Assets"
},
"category": {
"category-created": "Category created",
"category-creation-failed": "Category creation failed",
"category-deleted": "Category Deleted",
"category-deletion-failed": "Category deletion failed",
"category-filter": "Category Filter",
"category-update-failed": "Category update failed",
"category-updated": "Category updated",
"uncategorized-count": "Uncategorized {count}"
"category-created": "Kategori oluşturuldu",
"category-creation-failed": "Kategori oluşturma başarısız",
"category-deleted": "Kategori silindi",
"category-deletion-failed": "Kategori silinme başarısız",
"category-filter": "Kategori Filteri",
"category-update-failed": "Kategori güncellemesi başarısız oldu",
"category-updated": "Kategori güncellendi",
"uncategorized-count": "{count} Kategorize edilmemiş"
},
"events": {
"apprise-url": "Apprise URL",
"database": "Database",
"delete-event": "Delete Event",
"apprise-url": "Url'yi bildir",
"database": "Veritabanı",
"delete-event": "Etkinlik Sil",
"new-notification-form-description": "Mealie uses the Apprise library to generate notifications. They offer many options for services to use for notifications. Refer to their wiki for a comprehensive guide on how to create the URL for your service. If available, selecting the type of your notification may include extra features.",
"new-version": "New version available!",
"notification": "Notification",
"refresh": "Refresh",
"scheduled": "Scheduled",
"something-went-wrong": "Something Went Wrong!",
"subscribed-events": "Subscribed Events",
"test-message-sent": "Test Message Sent"
"new-version": "Yeni bir sürüm var!",
"notification": "Bildirimler",
"refresh": "Yenile",
"scheduled": "Planlandı",
"something-went-wrong": "Bir sorun oluştu!",
"subscribed-events": "Abone Olunan Etkinlikler",
"test-message-sent": "Test Mesajı Gönderildi"
},
"general": {
"cancel": "Cancel",
"clear": "Clear",
"cancel": "İptal",
"clear": "Temizle",
"close": "Close",
"confirm": "Confirm",
"confirm-delete-generic": "Are you sure you want to delete this?",

View File

@@ -1,489 +1,489 @@
{
"about": {
"about": "About",
"about-mealie": "About Mealie",
"api-docs": "API Docs",
"api-port": "API Port",
"application-mode": "Application Mode",
"database-type": "Database Type",
"database-url": "Database URL",
"default-group": "Default Group",
"demo": "Demo",
"demo-status": "Demo Status",
"development": "Development",
"docs": "Docs",
"download-log": "Download Log",
"download-recipe-json": "Last Scraped JSON",
"about": "Про програму",
"about-mealie": "Про Mealie",
"api-docs": "Документація API",
"api-port": "Порт API",
"application-mode": "Режим додатку",
"database-type": "Тип бази данних",
"database-url": "URL-адреса бази даних",
"default-group": "Групи за замовчуванням",
"demo": "Демо",
"demo-status": "Статус демо",
"development": "Розробка",
"docs": "Документація",
"download-log": "Завантажити лог",
"download-recipe-json": "Останній зібраний JSON",
"github": "Github",
"log-lines": "Log Lines",
"not-demo": "Not Demo",
"portfolio": "Portfolio",
"production": "Production",
"support": "Support",
"version": "Version"
"log-lines": "Журнал рядків",
"not-demo": "Не демо",
"portfolio": "Портфоліо",
"production": "Користувацький",
"support": "Підтримка",
"version": "Версія"
},
"asset": {
"assets": "Assets",
"code": "Code",
"file": "File",
"image": "Image",
"new-asset": "New Asset",
"assets": "Медіа-ресурси",
"code": "Код",
"file": "Файл",
"image": "Зображення",
"new-asset": "Новий медіа-ресурс",
"pdf": "PDF",
"recipe": "Recipe",
"show-assets": "Show Assets"
"recipe": "Рецепт",
"show-assets": "Показати медіа-ресурси"
},
"category": {
"category-created": "Category created",
"category-creation-failed": "Category creation failed",
"category-deleted": "Category Deleted",
"category-deletion-failed": "Category deletion failed",
"category-filter": "Category Filter",
"category-update-failed": "Category update failed",
"category-updated": "Category updated",
"uncategorized-count": "Uncategorized {count}"
"category-created": "Категорія створена",
"category-creation-failed": "Не вдалося створити категорію",
"category-deleted": "Категорію видалено",
"category-deletion-failed": "Не вдалося видалити категорію",
"category-filter": "Фільтр категорій",
"category-update-failed": "Не вдалося оновити категорію",
"category-updated": "Категорію оновлено",
"uncategorized-count": "Без категорії {count}"
},
"events": {
"apprise-url": "Apprise URL",
"database": "Database",
"delete-event": "Delete Event",
"new-notification-form-description": "Mealie uses the Apprise library to generate notifications. They offer many options for services to use for notifications. Refer to their wiki for a comprehensive guide on how to create the URL for your service. If available, selecting the type of your notification may include extra features.",
"new-version": "New version available!",
"notification": "Notification",
"refresh": "Refresh",
"scheduled": "Scheduled",
"something-went-wrong": "Something Went Wrong!",
"subscribed-events": "Subscribed Events",
"test-message-sent": "Test Message Sent"
"apprise-url": "URL-адреса Apprise",
"database": "База даних",
"delete-event": "Видалити подію",
"new-notification-form-description": "Mealie використовує бібліотеку Apprise для створення сповіщень. Вони пропонують багато варіантів використання служб для сповіщень. Зверніться до wiki бібліотеки Apprise, щоб отримати повну інструкцію про те, як створити URL-адресу для вашого сервісу. При наявності вибраний тип вашого сповіщення може включати додаткові функції.",
"new-version": "Доступна нова версія!",
"notification": "Сповіщення",
"refresh": "Оновлення",
"scheduled": "Заплановано",
"something-went-wrong": "Щось пішло не так!",
"subscribed-events": "Події, на які підписано",
"test-message-sent": "Тестове повідомлення надіслано"
},
"general": {
"cancel": "Cancel",
"clear": "Clear",
"close": "Close",
"confirm": "Confirm",
"confirm-delete-generic": "Are you sure you want to delete this?",
"copied": "Copied",
"create": "Create",
"created": "Created",
"custom": "Custom",
"dashboard": "Dashboard",
"delete": "Delete",
"disabled": "Disabled",
"download": "Download",
"edit": "Edit",
"enabled": "Enabled",
"exception": "Exception",
"failed-count": "Failed: {count}",
"failure-uploading-file": "Failure uploading file",
"favorites": "Favorites",
"field-required": "Field Required",
"file-folder-not-found": "File/folder not found",
"file-uploaded": "File uploaded",
"filter": "Filter",
"friday": "Friday",
"general": "General",
"get": "Get",
"home": "Home",
"image": "Image",
"image-upload-failed": "Image upload failed",
"import": "Import",
"cancel": "Скасувати",
"clear": "Очистити",
"close": "Закрити",
"confirm": "Підтвердити",
"confirm-delete-generic": "Ви дійсно бажаєте видалити це?",
"copied": "Скопійовано",
"create": "Створити",
"created": "Створено",
"custom": "Власний",
"dashboard": "Панель керування",
"delete": "Видалити",
"disabled": "Вимкнено",
"download": "Завантажити",
"edit": "Редагувати",
"enabled": "Увімкнено",
"exception": "Виняток",
"failed-count": "Не вдалося: {count}",
"failure-uploading-file": "Помилка відвантаження файлу",
"favorites": "Улюблені",
"field-required": "Обов'язкове поле",
"file-folder-not-found": "Файл/теку не знайдено",
"file-uploaded": "Файл відвантажено",
"filter": "Фільтр",
"friday": "П'ятниця",
"general": "Загальне",
"get": "Отримати",
"home": "Головна",
"image": "Зображення",
"image-upload-failed": "Не вдалося відвантажити зображення",
"import": "Імпорт",
"json": "JSON",
"keyword": "Keyword",
"link-copied": "Link Copied",
"loading-recipes": "Loading Recipes",
"monday": "Monday",
"name": "Name",
"new": "New",
"no": "No",
"no-recipe-found": "No Recipe Found",
"keyword": "Ключове слово",
"link-copied": "Посилання скопійовано",
"loading-recipes": "Завантаження рецептів",
"monday": "Понеділок",
"name": "Назва",
"new": "Створити",
"no": "Ні",
"no-recipe-found": "Рецепти не знайдені",
"ok": "OK",
"options": "Options:",
"print": "Print",
"random": "Random",
"rating": "Rating",
"recent": "Recent",
"recipe": "Recipe",
"recipes": "Recipes",
"rename-object": "Rename {0}",
"reset": "Reset",
"saturday": "Saturday",
"save": "Save",
"settings": "Settings",
"share": "Share",
"shuffle": "Shuffle",
"sort": "Sort",
"sort-alphabetically": "Alphabetical",
"status": "Status",
"submit": "Submit",
"success-count": "Success: {count}",
"sunday": "Sunday",
"templates": "Templates:",
"test": "Test",
"themes": "Themes",
"thursday": "Thursday",
"token": "Token",
"tuesday": "Tuesday",
"type": "Type",
"update": "Update",
"updated": "Updated",
"upload": "Upload",
"url": "URL",
"view": "View",
"wednesday": "Wednesday",
"yes": "Yes"
"options": "Опції:",
"print": "Друк",
"random": "Випадково",
"rating": "Рейтинг",
"recent": "Нещодавні",
"recipe": "Рецепт",
"recipes": "Рецепти",
"rename-object": "Перейменувати {0}",
"reset": "Скинути",
"saturday": "Субота",
"save": "Зберегти",
"settings": "Налаштування",
"share": "Поділитись",
"shuffle": "Перемішати",
"sort": "Сортувати",
"sort-alphabetically": "За алфавітом",
"status": "Статус",
"submit": "Надіслати",
"success-count": "Успіх: {count}",
"sunday": "Неділя",
"templates": "Шаблони:",
"test": "Тест",
"themes": "Теми",
"thursday": "Четвер",
"token": "Токен",
"tuesday": "Вівторок",
"type": "Тип",
"update": "Оновити",
"updated": "Оновлено",
"upload": "Відвантажити",
"url": "URL-адреса",
"view": "Перегляд",
"wednesday": "Середа",
"yes": "Так"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
"cannot-delete-default-group": "Cannot delete default group",
"cannot-delete-group-with-users": "Cannot delete group with users",
"confirm-group-deletion": "Confirm Group Deletion",
"create-group": "Create Group",
"error-updating-group": "Error updating group",
"group": "Group",
"group-deleted": "Group deleted",
"group-deletion-failed": "Group deletion failed",
"group-id-with-value": "Group ID: {groupID}",
"group-name": "Group Name",
"group-not-found": "Group not found",
"group-with-value": "Group: {groupID}",
"groups": "Groups",
"manage-groups": "Manage Groups",
"user-group": "User Group",
"user-group-created": "User Group Created",
"user-group-creation-failed": "User Group Creation Failed"
"are-you-sure-you-want-to-delete-the-group": "Ви дійсно бажаєте видалити <b>{groupName}<b/>?",
"cannot-delete-default-group": "Неможливо видалити групу за замовчуванням",
"cannot-delete-group-with-users": "Неможливо видалити групу з користувачами",
"confirm-group-deletion": "Підтвердіть видалення групи",
"create-group": "Створити групу",
"error-updating-group": "Помилка оновлення групи",
"group": "Група",
"group-deleted": "Групу видалено",
"group-deletion-failed": "Не вдалося видалити групу",
"group-id-with-value": "ID групи: {groupID}",
"group-name": "Назва групи",
"group-not-found": "Групу не знайдено",
"group-with-value": "Група: {groupID}",
"groups": "Групи",
"manage-groups": "Керування групами",
"user-group": "Група користувача",
"user-group-created": "Групу користувача створено",
"user-group-creation-failed": "Не вдалося створити групу користувача"
},
"meal-plan": {
"create-a-new-meal-plan": "Create a New Meal Plan",
"dinner-this-week": "Dinner This Week",
"dinner-today": "Dinner Today",
"dinner-tonight": "DINNER TONIGHT",
"edit-meal-plan": "Edit Meal Plan",
"end-date": "End Date",
"group": "Group (Beta)",
"main": "Main",
"meal-planner": "Meal Planner",
"meal-plans": "Meal Plans",
"mealplan-categories": "MEALPLAN CATEGORIES",
"mealplan-created": "Mealplan created",
"mealplan-creation-failed": "Mealplan creation failed",
"mealplan-deleted": "Mealplan Deleted",
"mealplan-deletion-failed": "Mealplan deletion failed",
"mealplan-settings": "Mealplan Settings",
"mealplan-update-failed": "Mealplan update failed",
"mealplan-updated": "Mealplan Updated",
"no-meal-plan-defined-yet": "No meal plan defined yet",
"no-meal-planned-for-today": "No meal planned for today",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans",
"planner": "Planner",
"quick-week": "Quick Week",
"side": "Side",
"sides": "Sides",
"start-date": "Start Date"
"create-a-new-meal-plan": "Створити новий план харчування",
"dinner-this-week": "Обід цього тижня",
"dinner-today": "Обід сьогодні",
"dinner-tonight": "Вечеря сьогодні",
"edit-meal-plan": "Редагувати план харчування",
"end-date": "Дата завершення",
"group": "Група (бета)",
"main": "Основне",
"meal-planner": "Планувальник харчування",
"meal-plans": "Плани харчування",
"mealplan-categories": "КАТЕГОРІЇ",
"mealplan-created": "План харчування створено",
"mealplan-creation-failed": "Не вдалося створити план харчування",
"mealplan-deleted": "План харчування видалено",
"mealplan-deletion-failed": "Не вдалося видалити план харчування",
"mealplan-settings": "Налаштування плану харчування",
"mealplan-update-failed": "Не вдалося оновити план харчування",
"mealplan-updated": "План харчування оновлено",
"no-meal-plan-defined-yet": "Не створено жодного плану харчування",
"no-meal-planned-for-today": "Не заплановано харчування на сьогодні",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Лише рецепти з цими категоріями будуть використані в планах харчування",
"planner": "Планувальник",
"quick-week": "Швидкий тиждень",
"side": "Закуска",
"sides": "Закуска",
"start-date": "Дата початку"
},
"migration": {
"chowdown": {
"description": "Migrate data from Chowdown",
"description": "Міграція даних з Chowdown",
"title": "Chowdown"
},
"migration-data-removed": "Migration data removed",
"migration-data-removed": "Дані міграції видалені",
"nextcloud": {
"description": "Migrate data from a Nextcloud Cookbook instance",
"description": "Міграція даних з Nextcloud Cookbook",
"title": "Nextcloud Cookbook"
},
"no-migration-data-available": "No Migration Data Available",
"recipe-migration": "Recipe Migration"
"no-migration-data-available": "Дані для міграції відсутні",
"recipe-migration": "Міграція рецептів"
},
"new-recipe": {
"bulk-add": "Bulk Add",
"error-details": "Only websites containing ld+json or microdata can be imported by Mealie. Most major recipe websites support this data structure. If your site cannot be imported but there is json data in the log, please submit a github issue with the URL and data.",
"error-title": "Looks Like We Couldn't Find Anything",
"from-url": "Import a Recipe",
"bulk-add": "Масове додавання",
"error-details": "Лише веб-сайти, що містять ld+json або мікродані, можуть бути імпортовані Mealie. Більшість кулінарних веб-сайтів підтримують цю структуру даних. Якщо ваш сайт не може бути імпортовано, але в журналі є json, будь ласка, створіть GitHub задачу з URL-адресою та даними.",
"error-title": "Схоже, ми не змогли нічого знайти",
"from-url": "Імпорт рецепту",
"github-issues": "GitHub Issues",
"google-ld-json-info": "Google ld+json Info",
"must-be-a-valid-url": "Must be a Valid URL",
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Paste in your recipe data. Each line will be treated as an item in a list",
"recipe-markup-specification": "Recipe Markup Specification",
"recipe-url": "Recipe URL",
"upload-a-recipe": "Upload a Recipe",
"upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.",
"url-form-hint": "Copy and paste a link from your favorite recipe website",
"view-scraped-data": "View Scraped Data"
"google-ld-json-info": "Google ld+json дані",
"must-be-a-valid-url": "Має бути дійсною URL-адресою",
"paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Вставте дані рецепту. Кожен рядок буде використаний як елемент у списку",
"recipe-markup-specification": "Налаштування розмітки рецептів",
"recipe-url": "URL-адреса рецепту",
"upload-a-recipe": "Відвантажити рецепт",
"upload-individual-zip-file": "Відвантажити окремий .zip файл, експортований з іншого Mealie.",
"url-form-hint": "Скопіюйте та вставте посилання з вашого улюбленого кулінарного веб-сайту",
"view-scraped-data": "Переглянути зібрані дані"
},
"page": {
"404-page-not-found": "404 Page not found",
"all-recipes": "All Recipes",
"new-page-created": "New page created",
"page": "Page",
"page-creation-failed": "Page creation failed",
"page-deleted": "Page deleted",
"page-deletion-failed": "Page deletion failed",
"page-update-failed": "Page update failed",
"page-updated": "Page updated",
"pages-update-failed": "Pages update failed",
"pages-updated": "Pages updated"
"404-page-not-found": "404 - Сторінка не знайдена",
"all-recipes": "Всі рецепти",
"new-page-created": "Нова сторінка створена",
"page": "Сторінка",
"page-creation-failed": "Не вдалося створити сторінку",
"page-deleted": "Сторінка видалена",
"page-deletion-failed": "Не вдалося видалити сторінку",
"page-update-failed": "Не вдалося оновити сторінку",
"page-updated": "Сторінку оновлено",
"pages-update-failed": "Не вдалося оновити сторінки",
"pages-updated": "Сторінки оновлено"
},
"recipe": {
"add-key": "Add Key",
"add-to-favorites": "Add to Favorites",
"api-extras": "API Extras",
"calories": "Calories",
"calories-suffix": "calories",
"carbohydrate-content": "Carbohydrate",
"categories": "Categories",
"comment-action": "Comment",
"comments": "Comments",
"delete-confirmation": "Are you sure you want to delete this recipe?",
"delete-recipe": "Delete Recipe",
"description": "Description",
"disable-amount": "Disable Ingredient Amounts",
"disable-comments": "Disable Comments",
"fat-content": "Fat",
"fiber-content": "Fiber",
"grams": "grams",
"ingredient": "Ingredient",
"ingredients": "Ingredients",
"insert-section": "Insert Section",
"instructions": "Instructions",
"key-name-required": "Key Name Required",
"landscape-view-coming-soon": "Landscape View (Coming Soon)",
"milligrams": "milligrams",
"new-key-name": "New Key Name",
"no-white-space-allowed": "No White Space Allowed",
"note": "Note",
"nutrition": "Nutrition",
"object-key": "Object Key",
"object-value": "Object Value",
"original-url": "Original URL",
"perform-time": "Cook Time",
"prep-time": "Prep Time",
"protein-content": "Protein",
"public-recipe": "Public Recipe",
"recipe-created": "Recipe created",
"recipe-creation-failed": "Recipe creation failed",
"recipe-deleted": "Recipe deleted",
"recipe-image": "Recipe Image",
"recipe-image-updated": "Recipe image updated",
"recipe-name": "Recipe Name",
"recipe-settings": "Recipe Settings",
"recipe-update-failed": "Recipe update failed",
"recipe-updated": "Recipe updated",
"remove-from-favorites": "Remove from Favorites",
"remove-section": "Remove Section",
"save-recipe-before-use": "Save recipe before use",
"section-title": "Section Title",
"servings": "Servings",
"share-recipe-message": "I wanted to share my {0} recipe with you.",
"show-nutrition-values": "Show Nutrition Values",
"sodium-content": "Sodium",
"step-index": "Step: {step}",
"sugar-content": "Sugar",
"title": "Title",
"total-time": "Total Time",
"unable-to-delete-recipe": "Unable to Delete Recipe"
"add-key": "Додати ключ",
"add-to-favorites": "Додати в улюблені",
"api-extras": "Додаткове API",
"calories": "Калорії",
"calories-suffix": "калорії",
"carbohydrate-content": "Вуглеводи",
"categories": "Категорії",
"comment-action": "Коментар",
"comments": "Коментарі",
"delete-confirmation": "Ви впевнені, що хочете видалити цей рецепт?",
"delete-recipe": "Видалити рецепт",
"description": "Опис",
"disable-amount": "Сховати кількість інгредієнтів",
"disable-comments": "Вимкнути коментарі",
"fat-content": "Жири",
"fiber-content": "Волокна",
"grams": "грами",
"ingredient": "Інгредієнт",
"ingredients": "Інгредієнти",
"insert-section": "Вставити розділ",
"instructions": "Інструкції",
"key-name-required": "Необхідно вказати назву ключа",
"landscape-view-coming-soon": "Вид в ландшафтному режимі (незабаром буде)",
"milligrams": "міліграми",
"new-key-name": "Назва нового ключа",
"no-white-space-allowed": "Проміжки не дозволені",
"note": "Нотатка",
"nutrition": "Харчова цінність",
"object-key": "Ключ об'єкту",
"object-value": "Значення об'єкту",
"original-url": "Оригінальна URL-адреса",
"perform-time": "Час приготування",
"prep-time": "Час підготовки",
"protein-content": "Білки",
"public-recipe": "Публічний рецепт",
"recipe-created": "Рецепт створено",
"recipe-creation-failed": "Не вдалося створити рецепт",
"recipe-deleted": "Рецепт видалено",
"recipe-image": "Зображення рецепту",
"recipe-image-updated": "Зображення рецепту оновлено",
"recipe-name": "Назва рецепта",
"recipe-settings": "Налаштування рецепта",
"recipe-update-failed": "Не вдалося оновити рецепт",
"recipe-updated": "Рецепт оновлено",
"remove-from-favorites": "Видалити з улюбленого",
"remove-section": "Видалити розділ",
"save-recipe-before-use": "Зберегти рецепт перед використанням",
"section-title": "Назва розділу",
"servings": "Порції",
"share-recipe-message": "Я хотів би поділитися з тобою своїм рецептом {0}.",
"show-nutrition-values": "Показати харчову цінність",
"sodium-content": "Натрій",
"step-index": "Крок: {step}",
"sugar-content": "Цукор",
"title": "Назва",
"total-time": "Загальний час",
"unable-to-delete-recipe": "Не вдалося видалити рецепт"
},
"reicpe": {
"no-recipe": "No Recipe"
"no-recipe": "Немає рецепту"
},
"search": {
"advanced-search": "Advanced Search",
"and": "and",
"exclude": "Exclude",
"include": "Include",
"max-results": "Max Results",
"or": "Or",
"results": "Results",
"search": "Search",
"search-mealie": "Search Mealie (press /)",
"search-placeholder": "Search...",
"tag-filter": "Tag Filter"
"advanced-search": "Розширений пошук",
"and": "та",
"exclude": "Виключаючи",
"include": "Включаючи",
"max-results": "Максимальна кількість результатів",
"or": "Або",
"results": "Результати",
"search": "Пошук",
"search-mealie": "Пошук по Mealie (натисніть /)",
"search-placeholder": "Пошук...",
"tag-filter": "Фільтр міток"
},
"settings": {
"add-a-new-theme": "Add a New Theme",
"admin-settings": "Admin Settings",
"add-a-new-theme": "Додати нову тему",
"admin-settings": "Адміністративні налаштування",
"backup": {
"backup-created-at-response-export_path": "Backup Created at {path}",
"backup-deleted": "Backup deleted",
"backup-tag": "Backup Tag",
"create-heading": "Create a Backup",
"delete-backup": "Delete Backup",
"error-creating-backup-see-log-file": "Error Creating Backup. See Log File",
"full-backup": "Full Backup",
"import-summary": "Import Summary",
"partial-backup": "Partial Backup",
"unable-to-delete-backup": "Unable to Delete Backup."
"backup-created-at-response-export_path": "Резервна копія створена {path}",
"backup-deleted": "Резервна копія видалена",
"backup-tag": "Мітка резервної копії",
"create-heading": "Створити резервну копію",
"delete-backup": "Видалити резервну копію",
"error-creating-backup-see-log-file": "Помилка створення резервної копії. Перегляньте файл журналу",
"full-backup": "Повна резервна копія",
"import-summary": "Резюме імпорту",
"partial-backup": "Часткова резервна копія",
"unable-to-delete-backup": "Не вдалося видалити резервну копію."
},
"backup-and-exports": "Backups",
"change-password": "Change Password",
"current": "Version:",
"custom-pages": "Custom Pages",
"edit-page": "Edit Page",
"events": "Events",
"first-day-of-week": "First day of the week",
"group-settings-updated": "Group Settings Updated",
"backup-and-exports": "Резервні копії",
"change-password": "Змінити пароль",
"current": "Версія:",
"custom-pages": "Власні сторінки",
"edit-page": "Редагувати сторінку",
"events": "Події",
"first-day-of-week": "Перший день тижня",
"group-settings-updated": "Налаштування групи оновлено",
"homepage": {
"all-categories": "All Categories",
"card-per-section": "Card Per Section",
"home-page": "Home Page",
"home-page-sections": "Home Page Sections",
"show-recent": "Show Recent"
"all-categories": "Всі категорії",
"card-per-section": "Карток в розділі",
"home-page": "Домашня сторінка",
"home-page-sections": "Розділи на головній сторінці",
"show-recent": "Показати недавні"
},
"language": "Language",
"latest": "Latest",
"local-api": "Local API",
"locale-settings": "Locale settings",
"migrations": "Migrations",
"new-page": "New Page",
"notify": "Notify",
"organize": "Organize",
"page-name": "Page Name",
"pages": "Pages",
"profile": "Profile",
"remove-existing-entries-matching-imported-entries": "Remove existing entries matching imported entries",
"set-new-time": "Set New Time",
"settings-update-failed": "Settings update failed",
"settings-updated": "Settings updated",
"site-settings": "Site Settings",
"language": "Мова",
"latest": "Недавні",
"local-api": "Локальний API",
"locale-settings": "Налаштування локалі",
"migrations": "Міграції",
"new-page": "Нова сторінка",
"notify": "Сповіщення",
"organize": "Впорядкувати",
"page-name": "Назва сторінки",
"pages": "Сторінки",
"profile": "Профіль",
"remove-existing-entries-matching-imported-entries": "Видалити існуючі записи, відповідні до імпортованих даних",
"set-new-time": "Встановити новий час",
"settings-update-failed": "Не вдалося оновити налаштування",
"settings-updated": "Налаштування оновлено",
"site-settings": "Налаштування сайту",
"theme": {
"accent": "Accent",
"dark": "Dark",
"default-to-system": "Default to system",
"error": "Error",
"error-creating-theme-see-log-file": "Error creating theme. See log file.",
"error-deleting-theme": "Error deleting theme",
"error-updating-theme": "Error updating theme",
"info": "Info",
"light": "Light",
"primary": "Primary",
"secondary": "Secondary",
"success": "Success",
"switch-to-dark-mode": "Switch to dark mode",
"switch-to-light-mode": "Switch to light mode",
"theme-deleted": "Theme deleted",
"theme-name": "Theme Name",
"theme-name-is-required": "Theme Name is required.",
"theme-saved": "Theme Saved",
"theme-updated": "Theme updated",
"warning": "Warning"
"accent": "Акцент",
"dark": "Темна",
"default-to-system": "За замовчуванням системи",
"error": "Помилка",
"error-creating-theme-see-log-file": "Помилка створення теми. Перегляньте файл журналу.",
"error-deleting-theme": "Помилка видалення теми",
"error-updating-theme": "Помилка оновлення теми",
"info": "Інформація",
"light": "Світла",
"primary": "Основний",
"secondary": "Додатковий",
"success": "Успіх",
"switch-to-dark-mode": "Перейти в темний режим",
"switch-to-light-mode": "Перейти в світлий режим",
"theme-deleted": "Тему видалено",
"theme-name": "Назва теми",
"theme-name-is-required": "Назва обов'язкова.",
"theme-saved": "Тему збережено",
"theme-updated": "Тему оновлено",
"warning": "Попередження"
},
"token": {
"active-tokens": "ACTIVE TOKENS",
"api-token": "API Token",
"api-tokens": "API Tokens",
"copy-this-token-for-use-with-an-external-application-this-token-will-not-be-viewable-again": "Copy this token for use with an external application. This token will not be viewable again.",
"create-an-api-token": "Create an API Token",
"token-name": "Token Name"
"active-tokens": "АКТИВНІ КЛЮЧІ",
"api-token": "Ключ API",
"api-tokens": "Ключі API",
"copy-this-token-for-use-with-an-external-application-this-token-will-not-be-viewable-again": "Скопіюйте цей ключ для використання з зовнішнім додатком. Цей ключ не буде доступним для перегляду знову.",
"create-an-api-token": "Створити новий API ключ",
"token-name": "Назва ключа"
},
"toolbox": {
"assign-all": "Assign All",
"bulk-assign": "Bulk Assign",
"new-name": "New Name",
"no-unused-items": "No Unused Items",
"recipes-affected": "No Recipes Affected|One Recipe Affected|{count} Recipes Affected",
"remove-unused": "Remove Unused",
"title-case-all": "Title Case All",
"toolbox": "Toolbox",
"unorganized": "Unorganized"
"assign-all": "Призначити все",
"bulk-assign": "Масове призначення",
"new-name": "Нова назва",
"no-unused-items": "Немає невикористаних елементів",
"recipes-affected": "Жоден рецепт не змінено|Один рецепт змінено|{count} рецептів змінено",
"remove-unused": "Видалити невикористані",
"title-case-all": "Все З Великих Літер",
"toolbox": "Інструменти",
"unorganized": "Неорганізовані"
},
"webhooks": {
"test-webhooks": "Test Webhooks",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "The URLs listed below will receive webhooks containing the recipe data for the meal plan on it's scheduled day. Currently Webhooks will execute at",
"webhook-url": "Webhook URL",
"webhooks-caps": "WEBHOOKS"
"test-webhooks": "Тестування вебхуків",
"the-urls-listed-below-will-recieve-webhooks-containing-the-recipe-data-for-the-meal-plan-on-its-scheduled-day-currently-webhooks-will-execute-at": "URL-адреси, перераховані нижче, будуть отримувати вебхуки, що містять дані рецепта для плану харчування на запланований день. В даний час Вебхуки будуть виконуватися о",
"webhook-url": "URL-адреса вебхука",
"webhooks-caps": "ВЕБХУКИ"
}
},
"shopping-list": {
"all-lists": "All Lists",
"create-shopping-list": "Create Shopping List",
"from-recipe": "From Recipe",
"list-name": "List Name",
"new-list": "New List",
"quantity": "Quantity: {0}",
"shopping-list": "Shopping List",
"shopping-lists": "Shopping Lists"
"all-lists": "Всі списки",
"create-shopping-list": "Сторити список покупок",
"from-recipe": "З рецепту",
"list-name": "Назва списку",
"new-list": "Новий список",
"quantity": "Кількість: {0}",
"shopping-list": "Список покупок",
"shopping-lists": "Списки покупок"
},
"sidebar": {
"all-recipes": "All Recipes",
"categories": "Categories",
"dashboard": "Dashboard",
"home-page": "Home Page",
"manage-users": "Manage Users",
"migrations": "Migrations",
"profile": "Profile",
"search": "Search",
"site-settings": "Site Settings",
"tags": "Tags",
"toolbox": "Toolbox"
"all-recipes": "Всі рецепти",
"categories": "Категорії",
"dashboard": "Панель",
"home-page": "Головна",
"manage-users": "Користувачі",
"migrations": "Міграції",
"profile": "Профіль",
"search": "Пошук",
"site-settings": "Налаштування",
"tags": "Мітки",
"toolbox": "Інструменти"
},
"signup": {
"error-signing-up": "Error Signing Up",
"sign-up": "Sign Up",
"sign-up-link-created": "Sign up link created",
"sign-up-link-creation-failed": "Sign up link creation failed",
"sign-up-links": "Sign Up Links",
"sign-up-token-deleted": "Sign Up Token Deleted",
"sign-up-token-deletion-failed": "Sign up token deletion failed",
"welcome-to-mealie": "Welcome to Mealie! To become a user of this instance you are required to have a valid invitation link. If you haven't recieved an invitation you are unable to sign-up. To recieve a link, contact the sites administrator."
"error-signing-up": "Помилка реєстрації",
"sign-up": "Зареєструватися",
"sign-up-link-created": "Посилання для реєстрації створено",
"sign-up-link-creation-failed": "Не вдалося створити посилання для реєстрації",
"sign-up-links": "Посилання для реєстрації",
"sign-up-token-deleted": "Ключ реєстрації видалено",
"sign-up-token-deletion-failed": "Не вдалося видалити ключ реєстрації",
"welcome-to-mealie": "Ласкаво просимо до Mealie! Щоб стати користувачем цього серверу, вам необхідно мати дійсне посилання-запрошення. Якщо ви не отримали запрошення, вам не вдасться зареєструватися. Щоб отримати посилання, зв'яжіться з адміністратором сайту."
},
"tag": {
"tag-created": "Tag created",
"tag-creation-failed": "Tag creation failed",
"tag-deleted": "Tag deleted",
"tag-deletion-failed": "Tag deletion failed",
"tag-update-failed": "Tag update failed",
"tag-updated": "Tag updated",
"tags": "Tags",
"untagged-count": "Untagged {count}"
"tag-created": "Мітка створена",
"tag-creation-failed": "Не вдалося створити мітку",
"tag-deleted": "Мітка видалена",
"tag-deletion-failed": "Не вдалося видалити мітку",
"tag-update-failed": "Не вдалося оновити мітку",
"tag-updated": "Мітку оновлено",
"tags": "Мітки",
"untagged-count": "Без мітки {count}"
},
"user": {
"admin": "Admin",
"are-you-sure-you-want-to-delete-the-link": "Are you sure you want to delete the link <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "Are you sure you want to delete the user <b>{activeName} ID: {activeId}<b/>?",
"confirm-link-deletion": "Confirm Link Deletion",
"confirm-password": "Confirm Password",
"confirm-user-deletion": "Confirm User Deletion",
"could-not-validate-credentials": "Could Not Validate Credentials",
"create-link": "Create Link",
"create-user": "Create User",
"current-password": "Current Password",
"e-mail-must-be-valid": "E-mail must be valid",
"edit-user": "Edit User",
"email": "Email",
"error-cannot-delete-super-user": "Error! Cannot Delete Super User",
"existing-password-does-not-match": "Existing password does not match",
"full-name": "Full Name",
"link-id": "Link ID",
"link-name": "Link Name",
"login": "Login",
"logout": "Logout",
"manage-users": "Manage Users",
"new-password": "New Password",
"new-user": "New User",
"password": "Password",
"password-has-been-reset-to-the-default-password": "Password has been reset to the default password",
"password-must-match": "Password must match",
"password-reset-failed": "Password reset failed",
"password-updated": "Password updated",
"reset-password": "Reset Password",
"sign-in": "Sign in",
"total-mealplans": "Total MealPlans",
"total-users": "Total Users",
"upload-photo": "Upload Photo",
"use-8-characters-or-more-for-your-password": "Use 8 characters or more for your password",
"user": "User",
"user-created": "User created",
"user-creation-failed": "User creation failed",
"user-deleted": "User deleted",
"user-id": "User ID",
"user-id-with-value": "User ID: {id}",
"user-password": "User Password",
"user-successfully-logged-in": "User Successfully Logged In",
"user-update-failed": "User update failed",
"user-updated": "User updated",
"username": "Username",
"users": "Users",
"users-header": "USERS",
"webhook-time": "Webhook Time",
"webhooks-enabled": "Webhooks Enabled",
"you-are-not-allowed-to-create-a-user": "You are not allowed to create a user",
"you-are-not-allowed-to-delete-this-user": "You are not allowed to delete this user"
"admin": "Адміністратор",
"are-you-sure-you-want-to-delete-the-link": "Ви впевнені, що хочете видалити посилання <b>{link}<b/>?",
"are-you-sure-you-want-to-delete-the-user": "Ви впевнені, що хочете видалити користувача <b>{activeName} ID: {activeId}<b/>?",
"confirm-link-deletion": "Підтвердіть видалення посилання",
"confirm-password": "Підтвердьте пароль",
"confirm-user-deletion": "Підтвердіть видалення користувача",
"could-not-validate-credentials": "Не вдалося підтвердити облікові дані",
"create-link": "Створити посилання",
"create-user": "Створити користувача",
"current-password": "Поточний пароль",
"e-mail-must-be-valid": "Електронна пошта має бути дійсною",
"edit-user": "Редагувати користувача",
"email": "Електронна пошта",
"error-cannot-delete-super-user": "Помилка! Неможливо видалити суперкористувача",
"existing-password-does-not-match": "Існуючий пароль не збігається",
"full-name": "Повне Ім'я",
"link-id": "ID посилання",
"link-name": "Назва посилання",
"login": "Увійти",
"logout": "Вийти",
"manage-users": "Керування користувачами",
"new-password": "Новий пароль",
"new-user": "Новий користувач",
"password": "Пароль",
"password-has-been-reset-to-the-default-password": "Пароль було скинуто до стандартного",
"password-must-match": "Паролі повинні збігатися",
"password-reset-failed": "Не вдалося скинути пароль",
"password-updated": "Пароль оновлено",
"reset-password": "Скинути пароль",
"sign-in": "Увійти",
"total-mealplans": "Всього планів харчування",
"total-users": "Всього користувачів",
"upload-photo": "Відвантажити світлину",
"use-8-characters-or-more-for-your-password": "Пароль повинен містити 8 або більше символів",
"user": "Користувач",
"user-created": "Користувача створено",
"user-creation-failed": "Не вдалося створити користувача",
"user-deleted": "Користувача видалено",
"user-id": "ID Користувача",
"user-id-with-value": "ID користувача: {id}",
"user-password": "Пароль користувача",
"user-successfully-logged-in": "Користувач успішно увійшов",
"user-update-failed": "Не вдалося оновити користувача",
"user-updated": "Користувача оновлено",
"username": "Ім'я користувача",
"users": "Користувачі",
"users-header": "КОРИСТУВАЧІ",
"webhook-time": "Час вебхука",
"webhooks-enabled": "Веб-хуки увімкнено",
"you-are-not-allowed-to-create-a-user": "Вам не дозволено створювати користувача",
"you-are-not-allowed-to-delete-this-user": "Вам не дозволено видаляти користувача"
}
}

View File

@@ -7,7 +7,7 @@
<v-card v-else-if="!loadFailed" id="myRecipe" class="d-print-none">
<a :href="getImage(recipeDetails.slug)">
<v-img
:height="hideImage ? '50' : imageHeight"
:min-height="hideImage ? '50' : imageHeight"
@error="hideImage = true"
:src="getImage(recipeDetails.slug)"
class="d-print-none"

View File

@@ -3,6 +3,7 @@ import Vuetify from "vuetify/lib";
Vue.use(Vuetify);
import ca from "vuetify/es5/locale/ca";
import de from "vuetify/es5/locale/de";
import en from "vuetify/es5/locale/en";
import es from "vuetify/es5/locale/es";
@@ -10,7 +11,10 @@ import fr from "vuetify/es5/locale/fr";
import hu from "vuetify/es5/locale/hu";
import it from "vuetify/es5/locale/it";
import nl from "vuetify/es5/locale/nl";
import no from "vuetify/es5/locale/no";
import pl from "vuetify/es5/locale/pl";
import ru from "vuetify/es5/locale/ru";
import sk from "vuetify/es5/locale/sk";
import sv from "vuetify/es5/locale/sv";
import zhHans from "vuetify/es5/locale/zh-Hans";
import zhHant from "vuetify/es5/locale/zh-Hant";
@@ -43,15 +47,21 @@ const vuetify = new Vuetify({
},
lang: {
locales: {
"ca-ES": ca,
"da-DK": en, // language not supported by Vuetify
"de-DE": de,
"en-US": en,
"en-GB": en,
"es-ES": es,
"fr-FR": fr,
"fr-CA": fr,
"hu-HU": hu,
"it-IT": it,
"nl-NL": nl,
"no-NO": no,
"pl-PL": pl,
"ru-RU": ru,
"sk-SK": sk,
"sv-SE": sv,
"zh-CN": zhHans,
"zh-TW": zhHant,

View File

@@ -9,6 +9,14 @@ const state = {
name: "British English",
value: "en-GB",
},
{
name: "Català (Catalan)",
value: "ca-ES",
},
{
name: "Dansk (Danish)",
value: "da-DK",
},
{
name: "Deutsch (German)",
value: "de-DE",
@@ -21,6 +29,10 @@ const state = {
name: "Français (French)",
value: "fr-FR",
},
{
name: "Français Canadien (Canadian French)",
value: "fr-CA",
},
{
name: "Magyar (Hungarian)",
value: "hu-HU",
@@ -29,6 +41,10 @@ const state = {
name: "Italiano (Italian)",
value: "it-IT",
},
{
name: "Norsk (Norwegian)",
value: "no-NO",
},
{
name: "Nederlands (Dutch)",
value: "nl-NL",
@@ -37,6 +53,14 @@ const state = {
name: "Polski (Polish)",
value: "pl-PL",
},
{
name: "Pусский (Russian)",
value: "ru-RU",
},
{
name: "Slovenčina (Slovak)",
value: "sk-SK",
},
{
name: "Svenska (Swedish)",
value: "sv-SE",

View File

@@ -36,11 +36,19 @@ module.exports = {
pwa: {
name: manifestJSON.short_name,
themeColor: manifestJSON.theme_color,
msTileColor: manifestJSON.background_color,
msTileColor: manifestJSON.theme_color,
appleMobileWebAppCapable: "yes",
appleMobileWebAppStatusBarStyle: "black",
manifestCrossorigin: "use-credentials",
iconPaths: {
maskicon: "img/icons/safari-pinned-tab.svg",
favicon32: "img/icons/favicon-32x32.png",
favicon16: "img/icons/favicon-16x16.png",
appleTouchIcon: "img/icons/apple-touch-icon.png",
msTileImage: "img/icons/mstile-150x150.png",
},
workboxPluginMode: "InjectManifest",
workboxOptions: {
swSrc: "./src/sw.js",

View File

@@ -6,7 +6,7 @@ from typing import Any, Optional, Union
import dotenv
from pydantic import BaseSettings, Field, PostgresDsn, validator
APP_VERSION = "v0.5.3"
APP_VERSION = "v0.5.5"
DB_VERSION = "v0.5.0"
CWD = Path(__file__).parent
@@ -151,6 +151,11 @@ class AppSettings(BaseSettings):
DEFAULT_EMAIL: str = "changeme@email.com"
DEFAULT_PASSWORD: str = "MyPassword"
LDAP_AUTH_ENABLED: bool = False
LDAP_SERVER_URL: str = None
LDAP_BIND_TEMPLATE: str = None
LDAP_ADMIN_FILTER: str = None
SCHEDULER_DATABASE = f"sqlite:///{app_dirs.DATA_DIR.joinpath('scheduler.db')}"
TOKEN_TIME: int = 2 # Time in Hours
@@ -167,6 +172,8 @@ class AppSettings(BaseSettings):
RECIPE_DISABLE_COMMENTS: bool = False
RECIPE_DISABLE_AMOUNT: bool = False
AUTO_BACKUP_ENABLED: bool = False
class Config:
env_file = BASE_DIR.joinpath(".env")
env_file_encoding = "utf-8"

View File

@@ -11,6 +11,44 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
ALGORITHM = "HS256"
def user_from_ldap(session, username: str, password: str) -> UserInDB:
"""Given a username and password, tries to authenticate by BINDing to an
LDAP server
If the BIND succeeds, it will either create a new user of that username on
the server or return an existing one.
Returns False on failure.
"""
import ldap
conn = ldap.initialize(settings.LDAP_SERVER_URL)
user_dn = settings.LDAP_BIND_TEMPLATE.format(username)
try:
conn.simple_bind_s(user_dn, password)
except (ldap.INVALID_CREDENTIALS, ldap.NO_SUCH_OBJECT):
return False
user = db.users.get(session, username, "username", any_case=True)
if not user:
user = db.users.create(
session,
{
"username": username,
"password": "LDAP",
# Fill the next two values with something unique and vaguely
# relevant
"full_name": username,
"email": username,
},
)
if settings.LDAP_ADMIN_FILTER:
user.admin = len(conn.search_s(user_dn, ldap.SCOPE_BASE, settings.LDAP_ADMIN_FILTER, [])) > 0
db.users.update(session, user.id, user)
return user
def create_access_token(data: dict(), expires_delta: timedelta = None) -> str:
to_encode = data.copy()
expires_delta = expires_delta or timedelta(hours=settings.TOKEN_TIME)
@@ -31,6 +69,8 @@ def authenticate_user(session, email: str, password: str) -> UserInDB:
if not user:
user = db.users.get(session, email, "username", any_case=True)
if settings.LDAP_AUTH_ENABLED and (not user or user.password == "LDAP"):
return user_from_ldap(session, email, password)
if not user:
return False

View File

@@ -29,6 +29,7 @@ langs = {
"ca-ES",
"sr-SP",
"cs-CZ",
"fr-CA",
"fr-FR",
"zh-TW",
"af-ZA",

View File

@@ -6,7 +6,7 @@ from typing import Union
from jinja2 import Template
from mealie.core import root_logger
from mealie.core.config import app_dirs
from mealie.core.config import app_dirs, settings
from mealie.db.database import db
from mealie.db.db_setup import create_session
from mealie.services.events import create_backup_event
@@ -153,6 +153,9 @@ def backup_all(
def auto_backup_job():
if not settings.AUTO_BACKUP_ENABLED:
return
for backup in app_dirs.BACKUP_DIR.glob("Auto*.zip"):
backup.unlink()

View File

@@ -43,6 +43,7 @@ def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path:
def scrape_image(image_url: str, slug: str) -> Path:
logger.info(f"Image URL: {image_url}")
_FIREFOX_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0"
if isinstance(image_url, str): # Handles String Types
pass
@@ -53,8 +54,10 @@ def scrape_image(image_url: str, slug: str) -> Path:
all_image_requests = []
for url in image_url:
if isinstance(url, dict):
url = url.get('url', "")
try:
r = requests.get(url, stream=True, headers={"User-Agent": ""})
r = requests.get(url, stream=True, headers={"User-Agent": _FIREFOX_UA})
except Exception:
logger.exception("Image {url} could not be requested")
continue
@@ -72,7 +75,7 @@ def scrape_image(image_url: str, slug: str) -> Path:
filename = Recipe(slug=slug).image_dir.joinpath(filename)
try:
r = requests.get(image_url, stream=True)
r = requests.get(image_url, stream=True, headers={"User-Agent": _FIREFOX_UA})
except Exception:
logger.exception("Fatal Image Request Exception")
return None

1302
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "mealie"
version = "0.5.2"
version = "0.5.5"
description = "A Recipe Manager"
authors = ["Hayden <hay-kot@pm.me>"]
license = "MIT"
@@ -9,7 +9,7 @@ license = "MIT"
start = "mealie.app:main"
[tool.poetry.dependencies]
python = "^3.9"
python = "^3.9.9"
aiofiles = "0.5.0"
aniso8601 = "7.0.0"
appdirs = "1.4.4"
@@ -22,7 +22,7 @@ python-dotenv = "^0.15.0"
python-slugify = "^4.0.1"
requests = "^2.25.1"
PyYAML = "^5.3.1"
extruct = "^0.12.0"
extruct = "^0.13.0"
python-multipart = "^0.0.5"
fastapi-camelcase = "^1.0.2"
bcrypt = "^3.2.0"
@@ -32,8 +32,9 @@ lxml = "4.6.2"
Pillow = "^8.2.0"
pathvalidate = "^2.4.1"
apprise = "0.9.3"
recipe-scrapers = "^13.2.7"
recipe-scrapers = "^13.7.0"
psycopg2-binary = {version = "^2.9.1", optional = true}
python-ldap = "^3.3.0"
gunicorn = "^20.1.0"
[tool.poetry.dev-dependencies]
@@ -67,3 +68,4 @@ skip_empty = true
[tool.poetry.extras]
pgsql = ["psycopg2-binary"]
ldap = ["python-ldap"]

View File

@@ -33,4 +33,10 @@ RECIPE_SHOW_NUTRITION=False
RECIPE_SHOW_ASSETS=False
RECIPE_LANDSCAPE_VIEW=False
RECIPE_DISABLE_COMMENTS=False
RECIPE_DISABLE_AMOUNT=False
RECIPE_DISABLE_AMOUNT=False
# Configuration for authentication via an external LDAP server
LDAP_AUTH_ENABLED=False
LDAP_SERVER_URL=None
LDAP_BIND_TEMPLATE=None
LDAP_ADMIN_FILTER=None

View File

@@ -2,6 +2,8 @@ from pathlib import Path
from mealie.core import security
from mealie.routes.deps import validate_file_token
from mealie.core.config import settings
from mealie.db.db_setup import create_session
def test_create_file_token():
@@ -9,3 +11,37 @@ def test_create_file_token():
file_token = security.create_file_token(file_path)
assert file_path == validate_file_token(file_token)
def test_ldap_authentication_mocked(monkeypatch):
import ldap
user = "testinguser"
password = "testingpass"
bind_template = "cn={},dc=example,dc=com"
admin_filter = "(memberOf=cn=admins,dc=example,dc=com)"
monkeypatch.setattr(settings, "LDAP_AUTH_ENABLED", True)
monkeypatch.setattr(settings, "LDAP_SERVER_URL", "") # Not needed due to mocking
monkeypatch.setattr(settings, "LDAP_BIND_TEMPLATE", bind_template)
monkeypatch.setattr(settings, "LDAP_ADMIN_FILTER", admin_filter)
class LdapConnMock:
def simple_bind_s(self, dn, bind_pw):
assert dn == bind_template.format(user)
return bind_pw == password
def search_s(self, dn, scope, filter, attrlist):
assert attrlist == []
assert filter == admin_filter
assert dn == bind_template.format(user)
assert scope == ldap.SCOPE_BASE
return [()]
def ldap_initialize_mock(url):
assert url == ""
return LdapConnMock()
monkeypatch.setattr(ldap, "initialize", ldap_initialize_mock)
result = security.authenticate_user(create_session(), user, password)
assert result is not False
assert result.username == user