mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-09 16:18:00 -05:00
Merge branch 'TandoorRecipes:develop' into Auto-Planner
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
DEBUG=0
|
DEBUG=0
|
||||||
SQL_DEBUG=0
|
SQL_DEBUG=0
|
||||||
DEBUG_TOOLBAR=0
|
DEBUG_TOOLBAR=0
|
||||||
|
# Gunicorn log level for debugging (default value is "info" when unset)
|
||||||
|
# (see https://docs.gunicorn.org/en/stable/settings.html#loglevel for available settings)
|
||||||
|
# GUNICORN_LOG_LEVEL="debug"
|
||||||
|
|
||||||
# HTTP port to bind to
|
# HTTP port to bind to
|
||||||
# TANDOOR_PORT=8080
|
# TANDOOR_PORT=8080
|
||||||
|
|||||||
120
.github/workflows/build-docker-open-data.yml
vendored
Normal file
120
.github/workflows/build-docker-open-data.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
name: Build Docker Container with open data plugin installed
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-container:
|
||||||
|
name: Build ${{ matrix.name }} Container
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository_owner == 'TandoorRecipes'
|
||||||
|
continue-on-error: ${{ matrix.continue-on-error }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# Standard build config
|
||||||
|
- name: Standard
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
suffix: ""
|
||||||
|
continue-on-error: false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Get version number
|
||||||
|
id: get_version
|
||||||
|
run: |
|
||||||
|
if [[ "$GITHUB_REF" = refs/tags/* ]]; then
|
||||||
|
echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "$GITHUB_REF" = refs/heads/beta ]]; then
|
||||||
|
echo VERSION=beta >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo VERSION=develop >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update Version number
|
||||||
|
- name: Update version file
|
||||||
|
uses: DamianReeves/write-file-action@v1.2
|
||||||
|
with:
|
||||||
|
path: recipes/version.py
|
||||||
|
contents: |
|
||||||
|
VERSION_NUMBER = '${{ steps.get_version.outputs.VERSION }}-open-data'
|
||||||
|
BUILD_REF = '${{ github.sha }}'
|
||||||
|
write-mode: overwrite
|
||||||
|
|
||||||
|
# clone open data plugin
|
||||||
|
- name: clone open data plugin repo
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
repository: TandoorRecipes/open_data_plugin
|
||||||
|
ref: master
|
||||||
|
path: ./recipes/plugins/open_data_plugin
|
||||||
|
|
||||||
|
# Build Vue frontend
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
cache: yarn
|
||||||
|
cache-dependency-path: vue/yarn.lock
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: ./vue
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
- name: Build dependencies
|
||||||
|
working-directory: ./vue
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: Setup Open Data Plugin Links
|
||||||
|
working-directory: ./recipes/plugins/open_data_plugin
|
||||||
|
run: python setup_repo.py
|
||||||
|
|
||||||
|
- name: Build Open Data Frontend
|
||||||
|
working-directory: ./recipes/plugins/open_data_plugin/vue
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
- name: Set up Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
if: github.secret_source == 'Actions'
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
if: github.secret_source == 'Actions'
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
vabene1111/recipes
|
||||||
|
ghcr.io/TandoorRecipes/recipes
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
|
suffix=${{ matrix.suffix }}
|
||||||
|
tags: |
|
||||||
|
type=raw,value=latest,suffix=-open-data-plugin,enable=${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
|
type=semver,suffix=-open-data-plugin,pattern={{version}}
|
||||||
|
type=semver,suffix=-open-data-plugin,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,suffix=-open-data-plugin,pattern={{major}}
|
||||||
|
type=ref,suffix=-open-data-plugin,event=branch
|
||||||
|
- name: Build and Push
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ${{ matrix.dockerfile }}
|
||||||
|
pull: true
|
||||||
|
push: ${{ github.secret_source == 'Actions' }}
|
||||||
|
platforms: ${{ matrix.platforms }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
3
boot.sh
3
boot.sh
@@ -4,6 +4,7 @@ source venv/bin/activate
|
|||||||
TANDOOR_PORT="${TANDOOR_PORT:-8080}"
|
TANDOOR_PORT="${TANDOOR_PORT:-8080}"
|
||||||
GUNICORN_WORKERS="${GUNICORN_WORKERS:-3}"
|
GUNICORN_WORKERS="${GUNICORN_WORKERS:-3}"
|
||||||
GUNICORN_THREADS="${GUNICORN_THREADS:-2}"
|
GUNICORN_THREADS="${GUNICORN_THREADS:-2}"
|
||||||
|
GUNICORN_LOG_LEVEL="${GUNICORN_LOG_LEVEL:-'info'}"
|
||||||
NGINX_CONF_FILE=/opt/recipes/nginx/conf.d/Recipes.conf
|
NGINX_CONF_FILE=/opt/recipes/nginx/conf.d/Recipes.conf
|
||||||
|
|
||||||
display_warning() {
|
display_warning() {
|
||||||
@@ -65,4 +66,4 @@ echo "Done"
|
|||||||
|
|
||||||
chmod -R 755 /opt/recipes/mediafiles
|
chmod -R 755 /opt/recipes/mediafiles
|
||||||
|
|
||||||
exec gunicorn -b :$TANDOOR_PORT --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level INFO recipes.wsgi
|
exec gunicorn -b :$TANDOOR_PORT --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level $GUNICORN_LOG_LEVEL recipes.wsgi
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ from treebeard.forms import movenodeform_factory
|
|||||||
|
|
||||||
from cookbook.managers import DICTIONARY
|
from cookbook.managers import DICTIONARY
|
||||||
|
|
||||||
from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField, ImportLog,
|
from .models import (Automation, BookmarkletImport, Comment, CookLog, Food, FoodInheritField,
|
||||||
Ingredient, InviteLink, Keyword, MealPlan, MealType, NutritionInformation,
|
ImportLog, Ingredient, InviteLink, Keyword, MealPlan, MealType,
|
||||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
NutritionInformation, Property, PropertyType, Recipe, RecipeBook,
|
||||||
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
RecipeBookEntry, RecipeImport, SearchPreference, ShareLink, ShoppingList,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, Supermarket,
|
||||||
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace)
|
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, TelegramBot,
|
||||||
|
Unit, UnitConversion, UserFile, UserPreference, UserSpace, ViewLog)
|
||||||
|
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
@@ -150,9 +151,16 @@ class KeywordAdmin(TreeAdmin):
|
|||||||
admin.site.register(Keyword, KeywordAdmin)
|
admin.site.register(Keyword, KeywordAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description='Delete Steps not part of a Recipe.')
|
||||||
|
def delete_unattached_steps(modeladmin, request, queryset):
|
||||||
|
with scopes_disabled():
|
||||||
|
Step.objects.filter(recipe=None).delete()
|
||||||
|
|
||||||
|
|
||||||
class StepAdmin(admin.ModelAdmin):
|
class StepAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'order',)
|
list_display = ('name', 'order',)
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
actions = [delete_unattached_steps]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Step, StepAdmin)
|
admin.site.register(Step, StepAdmin)
|
||||||
@@ -201,9 +209,24 @@ class FoodAdmin(TreeAdmin):
|
|||||||
admin.site.register(Food, FoodAdmin)
|
admin.site.register(Food, FoodAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversionAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('base_amount', 'base_unit', 'food', 'converted_amount', 'converted_unit')
|
||||||
|
search_fields = ('food__name', 'unit__name')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(UnitConversion, UnitConversionAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description='Delete Ingredients not part of a Recipe.')
|
||||||
|
def delete_unattached_ingredients(modeladmin, request, queryset):
|
||||||
|
with scopes_disabled():
|
||||||
|
Ingredient.objects.filter(step__recipe=None).delete()
|
||||||
|
|
||||||
|
|
||||||
class IngredientAdmin(admin.ModelAdmin):
|
class IngredientAdmin(admin.ModelAdmin):
|
||||||
list_display = ('food', 'amount', 'unit')
|
list_display = ('food', 'amount', 'unit')
|
||||||
search_fields = ('food__name', 'unit__name')
|
search_fields = ('food__name', 'unit__name')
|
||||||
|
actions = [delete_unattached_ingredients]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Ingredient, IngredientAdmin)
|
admin.site.register(Ingredient, IngredientAdmin)
|
||||||
@@ -319,6 +342,20 @@ class ShareLinkAdmin(admin.ModelAdmin):
|
|||||||
admin.site.register(ShareLink, ShareLinkAdmin)
|
admin.site.register(ShareLink, ShareLinkAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTypeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id', 'name')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(PropertyType, PropertyTypeAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('property_amount', 'property_type')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Property, PropertyAdmin)
|
||||||
|
|
||||||
|
|
||||||
class NutritionInformationAdmin(admin.ModelAdmin):
|
class NutritionInformationAdmin(admin.ModelAdmin):
|
||||||
list_display = ('id',)
|
list_display = ('id',)
|
||||||
|
|
||||||
|
|||||||
@@ -167,8 +167,25 @@ class ImportExportBase(forms.Form):
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleFileInput(forms.ClearableFileInput):
|
||||||
|
allow_multiple_selected = True
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleFileField(forms.FileField):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs.setdefault("widget", MultipleFileInput())
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, data, initial=None):
|
||||||
|
single_file_clean = super().clean
|
||||||
|
if isinstance(data, (list, tuple)):
|
||||||
|
result = [single_file_clean(d, initial) for d in data]
|
||||||
|
else:
|
||||||
|
result = single_file_clean(data, initial)
|
||||||
|
return result
|
||||||
|
|
||||||
class ImportForm(ImportExportBase):
|
class ImportForm(ImportExportBase):
|
||||||
files = forms.FileField(required=True, widget=forms.ClearableFileInput(attrs={'multiple': True}))
|
files = MultipleFileField(required=True)
|
||||||
duplicates = forms.BooleanField(help_text=_(
|
duplicates = forms.BooleanField(help_text=_(
|
||||||
'To prevent duplicates recipes with the same name as existing ones are ignored. Check this box to import everything.'),
|
'To prevent duplicates recipes with the same name as existing ones are ignored. Check this box to import everything.'),
|
||||||
required=False)
|
required=False)
|
||||||
|
|||||||
11
cookbook/helper/cache_helper.py
Normal file
11
cookbook/helper/cache_helper.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
class CacheHelper:
|
||||||
|
space = None
|
||||||
|
|
||||||
|
BASE_UNITS_CACHE_KEY = None
|
||||||
|
PROPERTY_TYPE_CACHE_KEY = None
|
||||||
|
|
||||||
|
def __init__(self, space):
|
||||||
|
self.space = space
|
||||||
|
|
||||||
|
self.BASE_UNITS_CACHE_KEY = f'SPACE_{space.id}_BASE_UNITS'
|
||||||
|
self.PROPERTY_TYPE_CACHE_KEY = f'SPACE_{space.id}_PROPERTY_TYPES'
|
||||||
@@ -41,6 +41,11 @@ def get_filetype(name):
|
|||||||
# filetype argument can not be optional, otherwise this function will treat all images as if they were a jpeg
|
# filetype argument can not be optional, otherwise this function will treat all images as if they were a jpeg
|
||||||
# Because it's no longer optional, no reason to return it
|
# Because it's no longer optional, no reason to return it
|
||||||
def handle_image(request, image_object, filetype):
|
def handle_image(request, image_object, filetype):
|
||||||
|
try:
|
||||||
|
Image.open(image_object).verify()
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
if (image_object.size / 1000) > 500: # if larger than 500 kb compress
|
if (image_object.size / 1000) > 500: # if larger than 500 kb compress
|
||||||
if filetype == '.jpeg' or filetype == '.jpg':
|
if filetype == '.jpeg' or filetype == '.jpg':
|
||||||
return rescale_image_jpeg(image_object)
|
return rescale_image_jpeg(image_object)
|
||||||
|
|||||||
214
cookbook/helper/open_data_importer.py
Normal file
214
cookbook/helper/open_data_importer.py
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from cookbook.models import Unit, SupermarketCategory, Property, PropertyType, Supermarket, SupermarketCategoryRelation, Food, Automation, UnitConversion, FoodProperty
|
||||||
|
|
||||||
|
|
||||||
|
class OpenDataImporter:
|
||||||
|
request = None
|
||||||
|
data = {}
|
||||||
|
slug_id_cache = {}
|
||||||
|
update_existing = False
|
||||||
|
use_metric = True
|
||||||
|
|
||||||
|
def __init__(self, request, data, update_existing=False, use_metric=True):
|
||||||
|
self.request = request
|
||||||
|
self.data = data
|
||||||
|
self.update_existing = update_existing
|
||||||
|
self.use_metric = use_metric
|
||||||
|
|
||||||
|
def _update_slug_cache(self, object_class, datatype):
|
||||||
|
self.slug_id_cache[datatype] = dict(object_class.objects.filter(space=self.request.space, open_data_slug__isnull=False).values_list('open_data_slug', 'id', ))
|
||||||
|
|
||||||
|
def import_units(self):
|
||||||
|
datatype = 'unit'
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
for u in list(self.data[datatype].keys()):
|
||||||
|
insert_list.append(Unit(
|
||||||
|
name=self.data[datatype][u]['name'],
|
||||||
|
plural_name=self.data[datatype][u]['plural_name'],
|
||||||
|
base_unit=self.data[datatype][u]['base_unit'] if self.data[datatype][u]['base_unit'] != '' else None,
|
||||||
|
open_data_slug=u,
|
||||||
|
space=self.request.space
|
||||||
|
))
|
||||||
|
|
||||||
|
if self.update_existing:
|
||||||
|
return Unit.objects.bulk_create(insert_list, update_conflicts=True, update_fields=('name', 'plural_name', 'base_unit', 'open_data_slug'), unique_fields=('space', 'name',))
|
||||||
|
else:
|
||||||
|
return Unit.objects.bulk_create(insert_list, update_conflicts=True, update_fields=('open_data_slug',), unique_fields=('space', 'name',))
|
||||||
|
|
||||||
|
def import_category(self):
|
||||||
|
datatype = 'category'
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
insert_list.append(SupermarketCategory(
|
||||||
|
name=self.data[datatype][k]['name'],
|
||||||
|
open_data_slug=k,
|
||||||
|
space=self.request.space
|
||||||
|
))
|
||||||
|
|
||||||
|
return SupermarketCategory.objects.bulk_create(insert_list, update_conflicts=True, update_fields=('open_data_slug',), unique_fields=('space', 'name',))
|
||||||
|
|
||||||
|
def import_property(self):
|
||||||
|
datatype = 'property'
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
insert_list.append(PropertyType(
|
||||||
|
name=self.data[datatype][k]['name'],
|
||||||
|
unit=self.data[datatype][k]['unit'],
|
||||||
|
open_data_slug=k,
|
||||||
|
space=self.request.space
|
||||||
|
))
|
||||||
|
|
||||||
|
return PropertyType.objects.bulk_create(insert_list, update_conflicts=True, update_fields=('open_data_slug',), unique_fields=('space', 'name',))
|
||||||
|
|
||||||
|
def import_supermarket(self):
|
||||||
|
datatype = 'store'
|
||||||
|
|
||||||
|
self._update_slug_cache(SupermarketCategory, 'category')
|
||||||
|
insert_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
insert_list.append(Supermarket(
|
||||||
|
name=self.data[datatype][k]['name'],
|
||||||
|
open_data_slug=k,
|
||||||
|
space=self.request.space
|
||||||
|
))
|
||||||
|
|
||||||
|
# always add open data slug if matching supermarket is found, otherwise relation might fail
|
||||||
|
supermarkets = Supermarket.objects.bulk_create(insert_list, unique_fields=('space', 'name',), update_conflicts=True, update_fields=('open_data_slug',))
|
||||||
|
self._update_slug_cache(Supermarket, 'store')
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
relations = []
|
||||||
|
order = 0
|
||||||
|
for c in self.data[datatype][k]['categories']:
|
||||||
|
relations.append(
|
||||||
|
SupermarketCategoryRelation(
|
||||||
|
supermarket_id=self.slug_id_cache[datatype][k],
|
||||||
|
category_id=self.slug_id_cache['category'][c],
|
||||||
|
order=order,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
order += 1
|
||||||
|
|
||||||
|
SupermarketCategoryRelation.objects.bulk_create(relations, ignore_conflicts=True, unique_fields=('supermarket', 'category',))
|
||||||
|
|
||||||
|
return supermarkets
|
||||||
|
|
||||||
|
def import_food(self):
|
||||||
|
identifier_list = []
|
||||||
|
datatype = 'food'
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
identifier_list.append(self.data[datatype][k]['name'])
|
||||||
|
identifier_list.append(self.data[datatype][k]['plural_name'])
|
||||||
|
|
||||||
|
existing_objects_flat = []
|
||||||
|
existing_objects = {}
|
||||||
|
for f in Food.objects.filter(space=self.request.space).filter(name__in=identifier_list).values_list('id', 'name', 'plural_name'):
|
||||||
|
existing_objects_flat.append(f[1])
|
||||||
|
existing_objects_flat.append(f[2])
|
||||||
|
existing_objects[f[1]] = f
|
||||||
|
existing_objects[f[2]] = f
|
||||||
|
|
||||||
|
self._update_slug_cache(Unit, 'unit')
|
||||||
|
self._update_slug_cache(PropertyType, 'property')
|
||||||
|
|
||||||
|
# pref_unit_key = 'preferred_unit_metric'
|
||||||
|
# pref_shopping_unit_key = 'preferred_packaging_unit_metric'
|
||||||
|
# if not self.use_metric:
|
||||||
|
# pref_unit_key = 'preferred_unit_imperial'
|
||||||
|
# pref_shopping_unit_key = 'preferred_packaging_unit_imperial'
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
update_list = []
|
||||||
|
update_field_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
if not (self.data[datatype][k]['name'] in existing_objects_flat or self.data[datatype][k]['plural_name'] in existing_objects_flat):
|
||||||
|
insert_list.append({'data': {
|
||||||
|
'name': self.data[datatype][k]['name'],
|
||||||
|
'plural_name': self.data[datatype][k]['plural_name'] if self.data[datatype][k]['plural_name'] != '' else None,
|
||||||
|
# 'preferred_unit_id': self.slug_id_cache['unit'][self.data[datatype][k][pref_unit_key]],
|
||||||
|
# 'preferred_shopping_unit_id': self.slug_id_cache['unit'][self.data[datatype][k][pref_shopping_unit_key]],
|
||||||
|
'supermarket_category_id': self.slug_id_cache['category'][self.data[datatype][k]['store_category']],
|
||||||
|
'fdc_id': self.data[datatype][k]['fdc_id'] if self.data[datatype][k]['fdc_id'] != '' else None,
|
||||||
|
'open_data_slug': k,
|
||||||
|
'space': self.request.space.id,
|
||||||
|
}})
|
||||||
|
else:
|
||||||
|
if self.data[datatype][k]['name'] in existing_objects:
|
||||||
|
existing_food_id = existing_objects[self.data[datatype][k]['name']][0]
|
||||||
|
else:
|
||||||
|
existing_food_id = existing_objects[self.data[datatype][k]['plural_name']][0]
|
||||||
|
|
||||||
|
if self.update_existing:
|
||||||
|
update_field_list = ['name', 'plural_name', 'preferred_unit_id', 'preferred_shopping_unit_id', 'supermarket_category_id', 'fdc_id', 'open_data_slug', ]
|
||||||
|
update_list.append(Food(
|
||||||
|
id=existing_food_id,
|
||||||
|
name=self.data[datatype][k]['name'],
|
||||||
|
plural_name=self.data[datatype][k]['plural_name'] if self.data[datatype][k]['plural_name'] != '' else None,
|
||||||
|
# preferred_unit_id=self.slug_id_cache['unit'][self.data[datatype][k][pref_unit_key]],
|
||||||
|
# preferred_shopping_unit_id=self.slug_id_cache['unit'][self.data[datatype][k][pref_shopping_unit_key]],
|
||||||
|
supermarket_category_id=self.slug_id_cache['category'][self.data[datatype][k]['store_category']],
|
||||||
|
fdc_id=self.data[datatype][k]['fdc_id'] if self.data[datatype][k]['fdc_id'] != '' else None,
|
||||||
|
open_data_slug=k,
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
update_field_list = ['open_data_slug', ]
|
||||||
|
update_list.append(Food(id=existing_food_id, open_data_slug=k, ))
|
||||||
|
|
||||||
|
Food.load_bulk(insert_list, None)
|
||||||
|
if len(update_list) > 0:
|
||||||
|
Food.objects.bulk_update(update_list, update_field_list)
|
||||||
|
|
||||||
|
self._update_slug_cache(Food, 'food')
|
||||||
|
|
||||||
|
food_property_list = []
|
||||||
|
alias_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
for fp in self.data[datatype][k]['properties']['type_values']:
|
||||||
|
food_property_list.append(Property(
|
||||||
|
property_type_id=self.slug_id_cache['property'][fp['property_type']],
|
||||||
|
property_amount=fp['property_value'],
|
||||||
|
import_food_id=self.slug_id_cache['food'][k],
|
||||||
|
space=self.request.space,
|
||||||
|
))
|
||||||
|
|
||||||
|
# for a in self.data[datatype][k]['alias']:
|
||||||
|
# alias_list.append(Automation(
|
||||||
|
# param_1=a,
|
||||||
|
# param_2=self.data[datatype][k]['name'],
|
||||||
|
# space=self.request.space,
|
||||||
|
# created_by=self.request.user,
|
||||||
|
# ))
|
||||||
|
|
||||||
|
Property.objects.bulk_create(food_property_list, ignore_conflicts=True, unique_fields=('space', 'import_food_id', 'property_type',))
|
||||||
|
|
||||||
|
property_food_relation_list = []
|
||||||
|
for p in Property.objects.filter(space=self.request.space, import_food_id__isnull=False).values_list('import_food_id', 'id', ):
|
||||||
|
property_food_relation_list.append(Food.properties.through(food_id=p[0], property_id=p[1]))
|
||||||
|
|
||||||
|
FoodProperty.objects.bulk_create(property_food_relation_list, ignore_conflicts=True, unique_fields=('food_id', 'property_id',))
|
||||||
|
|
||||||
|
# Automation.objects.bulk_create(alias_list, ignore_conflicts=True, unique_fields=('space', 'param_1', 'param_2',))
|
||||||
|
return insert_list + update_list
|
||||||
|
|
||||||
|
def import_conversion(self):
|
||||||
|
datatype = 'conversion'
|
||||||
|
|
||||||
|
insert_list = []
|
||||||
|
for k in list(self.data[datatype].keys()):
|
||||||
|
insert_list.append(UnitConversion(
|
||||||
|
base_amount=self.data[datatype][k]['base_amount'],
|
||||||
|
base_unit_id=self.slug_id_cache['unit'][self.data[datatype][k]['base_unit']],
|
||||||
|
converted_amount=self.data[datatype][k]['converted_amount'],
|
||||||
|
converted_unit_id=self.slug_id_cache['unit'][self.data[datatype][k]['converted_unit']],
|
||||||
|
food_id=self.slug_id_cache['food'][self.data[datatype][k]['food']],
|
||||||
|
open_data_slug=k,
|
||||||
|
space=self.request.space,
|
||||||
|
created_by=self.request.user,
|
||||||
|
))
|
||||||
|
|
||||||
|
return UnitConversion.objects.bulk_create(insert_list, ignore_conflicts=True, unique_fields=('space', 'base_unit', 'converted_unit', 'food', 'open_data_slug'))
|
||||||
71
cookbook/helper/property_helper.py
Normal file
71
cookbook/helper/property_helper.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from django.core.cache import caches
|
||||||
|
|
||||||
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
|
from cookbook.helper.unit_conversion_helper import UnitConversionHelper
|
||||||
|
from cookbook.models import PropertyType, Unit, Food, Property, Recipe, Step
|
||||||
|
|
||||||
|
|
||||||
|
class FoodPropertyHelper:
|
||||||
|
space = None
|
||||||
|
|
||||||
|
def __init__(self, space):
|
||||||
|
"""
|
||||||
|
Helper to perform food property calculations
|
||||||
|
:param space: space to limit scope to
|
||||||
|
"""
|
||||||
|
self.space = space
|
||||||
|
|
||||||
|
def calculate_recipe_properties(self, recipe):
|
||||||
|
"""
|
||||||
|
Calculate all food properties for a given recipe.
|
||||||
|
:param recipe: recipe to calculate properties for
|
||||||
|
:return: dict of with property keys and total/food values for each property available
|
||||||
|
"""
|
||||||
|
ingredients = []
|
||||||
|
computed_properties = {}
|
||||||
|
|
||||||
|
for s in recipe.steps.all():
|
||||||
|
ingredients += s.ingredients.all()
|
||||||
|
|
||||||
|
property_types = caches['default'].get(CacheHelper(self.space).PROPERTY_TYPE_CACHE_KEY, None)
|
||||||
|
|
||||||
|
if not property_types:
|
||||||
|
property_types = PropertyType.objects.filter(space=self.space).all()
|
||||||
|
caches['default'].set(CacheHelper(self.space).PROPERTY_TYPE_CACHE_KEY, property_types, 60 * 60) # cache is cleared on property type save signal so long duration is fine
|
||||||
|
|
||||||
|
for fpt in property_types:
|
||||||
|
computed_properties[fpt.id] = {'id': fpt.id, 'name': fpt.name, 'icon': fpt.icon, 'description': fpt.description, 'unit': fpt.unit, 'food_values': {}, 'total_value': 0, 'missing_value': False}
|
||||||
|
|
||||||
|
uch = UnitConversionHelper(self.space)
|
||||||
|
|
||||||
|
for i in ingredients:
|
||||||
|
if i.food is not None:
|
||||||
|
conversions = uch.get_conversions(i)
|
||||||
|
for pt in property_types:
|
||||||
|
found_property = False
|
||||||
|
if i.food.properties_food_amount == 0 or i.food.properties_food_unit is None:
|
||||||
|
computed_properties[pt.id]['food_values'][i.food.id] = {'id': i.food.id, 'food': i.food.name, 'value': 0}
|
||||||
|
computed_properties[pt.id]['missing_value'] = i.food.properties_food_unit is None
|
||||||
|
else:
|
||||||
|
for p in i.food.properties.all():
|
||||||
|
if p.property_type == pt:
|
||||||
|
for c in conversions:
|
||||||
|
if c.unit == i.food.properties_food_unit:
|
||||||
|
found_property = True
|
||||||
|
computed_properties[pt.id]['total_value'] += (c.amount / i.food.properties_food_amount) * p.property_amount
|
||||||
|
computed_properties[pt.id]['food_values'] = self.add_or_create(computed_properties[p.property_type.id]['food_values'], c.food.id, (c.amount / i.food.properties_food_amount) * p.property_amount, c.food)
|
||||||
|
if not found_property:
|
||||||
|
computed_properties[pt.id]['missing_value'] = True
|
||||||
|
computed_properties[pt.id]['food_values'][i.food.id] = {'id': i.food.id, 'food': i.food.name, 'value': 0}
|
||||||
|
|
||||||
|
return computed_properties
|
||||||
|
|
||||||
|
# small dict helper to add to existing key or create new, probably a better way of doing this
|
||||||
|
# TODO move to central helper ?
|
||||||
|
@staticmethod
|
||||||
|
def add_or_create(d, key, value, food):
|
||||||
|
if key in d:
|
||||||
|
d[key]['value'] += value
|
||||||
|
else:
|
||||||
|
d[key] = {'id': food.id, 'food': food.name, 'value': value}
|
||||||
|
return d
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
# import random
|
# import random
|
||||||
import re
|
import re
|
||||||
|
import traceback
|
||||||
from html import unescape
|
from html import unescape
|
||||||
|
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
@@ -12,7 +13,8 @@ from recipe_scrapers._utils import get_host_name, get_minutes
|
|||||||
|
|
||||||
# from cookbook.helper import recipe_url_import as helper
|
# from cookbook.helper import recipe_url_import as helper
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
from cookbook.models import Automation, Keyword
|
from cookbook.models import Automation, Keyword, PropertyType
|
||||||
|
|
||||||
|
|
||||||
# from unicodedata import decomposition
|
# from unicodedata import decomposition
|
||||||
|
|
||||||
@@ -33,6 +35,9 @@ def get_from_scraper(scrape, request):
|
|||||||
except Exception:
|
except Exception:
|
||||||
recipe_json['name'] = ''
|
recipe_json['name'] = ''
|
||||||
|
|
||||||
|
if isinstance(recipe_json['name'], list) and len(recipe_json['name']) > 0:
|
||||||
|
recipe_json['name'] = recipe_json['name'][0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
description = scrape.description() or None
|
description = scrape.description() or None
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -193,7 +198,14 @@ def get_from_scraper(scrape, request):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if recipe_json['source_url']:
|
try:
|
||||||
|
recipe_json['properties'] = get_recipe_properties(request.space, scrape.schema.nutrients())
|
||||||
|
print(recipe_json['properties'])
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 'source_url' in recipe_json and recipe_json['source_url']:
|
||||||
automations = Automation.objects.filter(type=Automation.INSTRUCTION_REPLACE, space=request.space, disabled=False).only('param_1', 'param_2', 'param_3').order_by('order').all()[:512]
|
automations = Automation.objects.filter(type=Automation.INSTRUCTION_REPLACE, space=request.space, disabled=False).only('param_1', 'param_2', 'param_3').order_by('order').all()[:512]
|
||||||
for a in automations:
|
for a in automations:
|
||||||
if re.match(a.param_1, (recipe_json['source_url'])[:512]):
|
if re.match(a.param_1, (recipe_json['source_url'])[:512]):
|
||||||
@@ -203,6 +215,30 @@ def get_from_scraper(scrape, request):
|
|||||||
return recipe_json
|
return recipe_json
|
||||||
|
|
||||||
|
|
||||||
|
def get_recipe_properties(space, property_data):
|
||||||
|
# {'servingSize': '1', 'calories': '302 kcal', 'proteinContent': '7,66g', 'fatContent': '11,56g', 'carbohydrateContent': '41,33g'}
|
||||||
|
properties = {
|
||||||
|
"property-calories": "calories",
|
||||||
|
"property-carbohydrates": "carbohydrateContent",
|
||||||
|
"property-proteins": "proteinContent",
|
||||||
|
"property-fats": "fatContent",
|
||||||
|
}
|
||||||
|
recipe_properties = []
|
||||||
|
for pt in PropertyType.objects.filter(space=space, open_data_slug__in=list(properties.keys())).all():
|
||||||
|
for p in list(properties.keys()):
|
||||||
|
if pt.open_data_slug == p:
|
||||||
|
if properties[p] in property_data:
|
||||||
|
recipe_properties.append({
|
||||||
|
'property_type': {
|
||||||
|
'id': pt.id,
|
||||||
|
'name': pt.name,
|
||||||
|
},
|
||||||
|
'property_amount': parse_servings(property_data[properties[p]]) / float(property_data['servingSize']),
|
||||||
|
})
|
||||||
|
|
||||||
|
return recipe_properties
|
||||||
|
|
||||||
|
|
||||||
def get_from_youtube_scraper(url, request):
|
def get_from_youtube_scraper(url, request):
|
||||||
"""A YouTube Information Scraper."""
|
"""A YouTube Information Scraper."""
|
||||||
kw, created = Keyword.objects.get_or_create(name='YouTube', space=request.space)
|
kw, created = Keyword.objects.get_or_create(name='YouTube', space=request.space)
|
||||||
|
|||||||
141
cookbook/helper/unit_conversion_helper.py
Normal file
141
cookbook/helper/unit_conversion_helper.py
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
from django.core.cache import caches
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
|
from cookbook.models import Ingredient, Unit
|
||||||
|
|
||||||
|
CONVERSION_TABLE = {
|
||||||
|
'weight': {
|
||||||
|
'g': 1000,
|
||||||
|
'kg': 1,
|
||||||
|
'ounce': 35.274,
|
||||||
|
'pound': 2.20462
|
||||||
|
},
|
||||||
|
'volume': {
|
||||||
|
'ml': 1000,
|
||||||
|
'l': 1,
|
||||||
|
'fluid_ounce': 33.814,
|
||||||
|
'pint': 2.11338,
|
||||||
|
'quart': 1.05669,
|
||||||
|
'gallon': 0.264172,
|
||||||
|
'tbsp': 67.628,
|
||||||
|
'tsp': 202.884,
|
||||||
|
'imperial_fluid_ounce': 35.1951,
|
||||||
|
'imperial_pint': 1.75975,
|
||||||
|
'imperial_quart': 0.879877,
|
||||||
|
'imperial_gallon': 0.219969,
|
||||||
|
'imperial_tbsp': 56.3121,
|
||||||
|
'imperial_tsp': 168.936,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_UNITS_WEIGHT = list(CONVERSION_TABLE['weight'].keys())
|
||||||
|
BASE_UNITS_VOLUME = list(CONVERSION_TABLE['volume'].keys())
|
||||||
|
|
||||||
|
|
||||||
|
class ConversionException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversionHelper:
|
||||||
|
space = None
|
||||||
|
|
||||||
|
def __init__(self, space):
|
||||||
|
"""
|
||||||
|
Initializes unit conversion helper
|
||||||
|
:param space: space to perform conversions on
|
||||||
|
"""
|
||||||
|
self.space = space
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert_from_to(from_unit, to_unit, amount):
|
||||||
|
"""
|
||||||
|
Convert from one base unit to another. Throws ConversionException if trying to convert between different systems (weight/volume) or if units are not supported.
|
||||||
|
:param from_unit: str unit to convert from
|
||||||
|
:param to_unit: str unit to convert to
|
||||||
|
:param amount: amount to convert
|
||||||
|
:return: Decimal converted amount
|
||||||
|
"""
|
||||||
|
system = None
|
||||||
|
if from_unit in BASE_UNITS_WEIGHT and to_unit in BASE_UNITS_WEIGHT:
|
||||||
|
system = 'weight'
|
||||||
|
if from_unit in BASE_UNITS_VOLUME and to_unit in BASE_UNITS_VOLUME:
|
||||||
|
system = 'volume'
|
||||||
|
|
||||||
|
if not system:
|
||||||
|
raise ConversionException('Trying to convert units not existing or not in one unit system (weight/volume)')
|
||||||
|
|
||||||
|
return Decimal(amount / Decimal(CONVERSION_TABLE[system][from_unit] / CONVERSION_TABLE[system][to_unit]))
|
||||||
|
|
||||||
|
def base_conversions(self, ingredient_list):
|
||||||
|
"""
|
||||||
|
Calculates all possible base unit conversions for each ingredient give.
|
||||||
|
Converts to all common base units IF they exist in the unit database of the space.
|
||||||
|
For useful results all ingredients passed should be of the same food, otherwise filtering afterwards might be required.
|
||||||
|
:param ingredient_list: list of ingredients to convert
|
||||||
|
:return: ingredient list with appended conversions
|
||||||
|
"""
|
||||||
|
base_conversion_ingredient_list = ingredient_list.copy()
|
||||||
|
for i in ingredient_list:
|
||||||
|
try:
|
||||||
|
conversion_unit = i.unit.name
|
||||||
|
if i.unit.base_unit:
|
||||||
|
conversion_unit = i.unit.base_unit
|
||||||
|
|
||||||
|
# TODO allow setting which units to convert to? possibly only once conversions become visible
|
||||||
|
units = caches['default'].get(CacheHelper(self.space).BASE_UNITS_CACHE_KEY, None)
|
||||||
|
if not units:
|
||||||
|
units = Unit.objects.filter(space=self.space, base_unit__in=(BASE_UNITS_VOLUME + BASE_UNITS_WEIGHT)).all()
|
||||||
|
caches['default'].set(CacheHelper(self.space).BASE_UNITS_CACHE_KEY, units, 60 * 60) # cache is cleared on unit save signal so long duration is fine
|
||||||
|
|
||||||
|
for u in units:
|
||||||
|
try:
|
||||||
|
ingredient = Ingredient(amount=self.convert_from_to(conversion_unit, u.base_unit, i.amount), unit=u, food=ingredient_list[0].food, )
|
||||||
|
if not any((x.unit.name == ingredient.unit.name or x.unit.base_unit == ingredient.unit.name) for x in base_conversion_ingredient_list):
|
||||||
|
base_conversion_ingredient_list.append(ingredient)
|
||||||
|
except ConversionException:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return base_conversion_ingredient_list
|
||||||
|
|
||||||
|
def get_conversions(self, ingredient):
|
||||||
|
"""
|
||||||
|
Converts an ingredient to all possible conversions based on the custom unit conversion database.
|
||||||
|
After that passes conversion to UnitConversionHelper.base_conversions() to get all base conversions possible.
|
||||||
|
:param ingredient: Ingredient object
|
||||||
|
:return: list of ingredients with all possible custom and base conversions
|
||||||
|
"""
|
||||||
|
conversions = [ingredient]
|
||||||
|
if ingredient.unit:
|
||||||
|
for c in ingredient.unit.unit_conversion_base_relation.all():
|
||||||
|
if c.space == self.space:
|
||||||
|
r = self._uc_convert(c, ingredient.amount, ingredient.unit, ingredient.food)
|
||||||
|
if r and r not in conversions:
|
||||||
|
conversions.append(r)
|
||||||
|
for c in ingredient.unit.unit_conversion_converted_relation.all():
|
||||||
|
if c.space == self.space:
|
||||||
|
r = self._uc_convert(c, ingredient.amount, ingredient.unit, ingredient.food)
|
||||||
|
if r and r not in conversions:
|
||||||
|
conversions.append(r)
|
||||||
|
|
||||||
|
conversions = self.base_conversions(conversions)
|
||||||
|
|
||||||
|
return conversions
|
||||||
|
|
||||||
|
def _uc_convert(self, uc, amount, unit, food):
|
||||||
|
"""
|
||||||
|
Helper to calculate values for custom unit conversions.
|
||||||
|
Converts given base values using the passed UnitConversion object into a converted Ingredient
|
||||||
|
:param uc: UnitConversion object
|
||||||
|
:param amount: base amount
|
||||||
|
:param unit: base unit
|
||||||
|
:param food: base food
|
||||||
|
:return: converted ingredient object from base amount/unit/food
|
||||||
|
"""
|
||||||
|
if uc.food is None or uc.food == food:
|
||||||
|
if unit == uc.base_unit:
|
||||||
|
return Ingredient(amount=amount * (uc.converted_amount / uc.base_amount), unit=uc.converted_unit, food=food, space=self.space)
|
||||||
|
else:
|
||||||
|
return Ingredient(amount=amount * (uc.base_amount / uc.converted_amount), unit=uc.base_unit, food=food, space=self.space)
|
||||||
@@ -51,6 +51,12 @@ class NextcloudCookbook(Integration):
|
|||||||
|
|
||||||
ingredients_added = False
|
ingredients_added = False
|
||||||
for s in recipe_json['recipeInstructions']:
|
for s in recipe_json['recipeInstructions']:
|
||||||
|
instruction_text = ''
|
||||||
|
if 'text' in s:
|
||||||
|
step = Step.objects.create(
|
||||||
|
instruction=s['text'], name=s['name'], space=self.request.space,
|
||||||
|
)
|
||||||
|
else:
|
||||||
step = Step.objects.create(
|
step = Step.objects.create(
|
||||||
instruction=s, space=self.request.space,
|
instruction=s, space=self.request.space,
|
||||||
)
|
)
|
||||||
@@ -102,7 +108,6 @@ class NextcloudCookbook(Integration):
|
|||||||
m = min % 60
|
m = min % 60
|
||||||
return f'PT{h}H{m}M0S'
|
return f'PT{h}H{m}M0S'
|
||||||
|
|
||||||
|
|
||||||
def get_file_from_recipe(self, recipe):
|
def get_file_from_recipe(self, recipe):
|
||||||
|
|
||||||
export = {}
|
export = {}
|
||||||
@@ -133,7 +138,6 @@ class NextcloudCookbook(Integration):
|
|||||||
export['recipeIngredient'] = recipeIngredient
|
export['recipeIngredient'] = recipeIngredient
|
||||||
export['recipeInstructions'] = recipeInstructions
|
export['recipeInstructions'] = recipeInstructions
|
||||||
|
|
||||||
|
|
||||||
return "recipe.json", json.dumps(export)
|
return "recipe.json", json.dumps(export)
|
||||||
|
|
||||||
def get_files_from_recipes(self, recipes, el, cookie):
|
def get_files_from_recipes(self, recipes, el, cookie):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
|
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
from cookbook.integration.integration import Integration
|
from cookbook.integration.integration import Integration
|
||||||
@@ -67,6 +68,7 @@ class Plantoeat(Integration):
|
|||||||
|
|
||||||
if image_url:
|
if image_url:
|
||||||
try:
|
try:
|
||||||
|
if validators.url(image_url, public=True):
|
||||||
response = requests.get(image_url)
|
response = requests.get(image_url)
|
||||||
self.import_recipe_image(recipe, BytesIO(response.content))
|
self.import_recipe_image(recipe, BytesIO(response.content))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import requests
|
|||||||
import validators
|
import validators
|
||||||
|
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
|
from cookbook.helper.recipe_url_import import parse_servings, parse_servings_text, parse_time
|
||||||
from cookbook.integration.integration import Integration
|
from cookbook.integration.integration import Integration
|
||||||
from cookbook.models import Ingredient, Recipe, Step
|
from cookbook.models import Ingredient, Recipe, Step
|
||||||
|
|
||||||
@@ -18,19 +19,21 @@ class RecipeSage(Integration):
|
|||||||
created_by=self.request.user, internal=True,
|
created_by=self.request.user, internal=True,
|
||||||
space=self.request.space)
|
space=self.request.space)
|
||||||
|
|
||||||
try:
|
|
||||||
if file['recipeYield'] != '':
|
if file['recipeYield'] != '':
|
||||||
recipe.servings = int(file['recipeYield'])
|
recipe.servings = parse_servings(file['recipeYield'])
|
||||||
|
recipe.servings_text = parse_servings_text(file['recipeYield'])
|
||||||
|
|
||||||
if file['totalTime'] != '':
|
try:
|
||||||
recipe.waiting_time = int(file['totalTime']) - int(file['timePrep'])
|
if 'totalTime' in file and file['totalTime'] != '':
|
||||||
|
recipe.working_time = parse_time(file['totalTime'])
|
||||||
|
|
||||||
if file['prepTime'] != '':
|
if 'timePrep' in file and file['prepTime'] != '':
|
||||||
recipe.working_time = int(file['timePrep'])
|
recipe.working_time = parse_time(file['timePrep'])
|
||||||
|
recipe.waiting_time = parse_time(file['totalTime']) - parse_time(file['timePrep'])
|
||||||
|
except Exception as e:
|
||||||
|
print('failed to parse time ', str(e))
|
||||||
|
|
||||||
recipe.save()
|
recipe.save()
|
||||||
except Exception as e:
|
|
||||||
print('failed to parse yield or time ', str(e))
|
|
||||||
|
|
||||||
ingredient_parser = IngredientParser(self.request, True)
|
ingredient_parser = IngredientParser(self.request, True)
|
||||||
ingredients_added = False
|
ingredients_added = False
|
||||||
|
|||||||
@@ -22,9 +22,12 @@ class Rezeptsuitede(Integration):
|
|||||||
name=recipe_xml.find('head').attrib['title'].strip(),
|
name=recipe_xml.find('head').attrib['title'].strip(),
|
||||||
created_by=self.request.user, internal=True, space=self.request.space)
|
created_by=self.request.user, internal=True, space=self.request.space)
|
||||||
|
|
||||||
|
try:
|
||||||
if recipe_xml.find('head').attrib['servingtype']:
|
if recipe_xml.find('head').attrib['servingtype']:
|
||||||
recipe.servings = parse_servings(recipe_xml.find('head').attrib['servingtype'].strip())
|
recipe.servings = parse_servings(recipe_xml.find('head').attrib['servingtype'].strip())
|
||||||
recipe.servings_text = parse_servings_text(recipe_xml.find('head').attrib['servingtype'].strip())
|
recipe.servings_text = parse_servings_text(recipe_xml.find('head').attrib['servingtype'].strip())
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
if recipe_xml.find('remark') is not None: # description is a list of <li>'s with text
|
if recipe_xml.find('remark') is not None: # description is a list of <li>'s with text
|
||||||
if recipe_xml.find('remark').find('line') is not None:
|
if recipe_xml.find('remark').find('line') is not None:
|
||||||
@@ -50,6 +53,8 @@ class Rezeptsuitede(Integration):
|
|||||||
for ingredient in recipe_xml.find('part').findall('ingredient'):
|
for ingredient in recipe_xml.find('part').findall('ingredient'):
|
||||||
f = ingredient_parser.get_food(ingredient.attrib['item'])
|
f = ingredient_parser.get_food(ingredient.attrib['item'])
|
||||||
u = ingredient_parser.get_unit(ingredient.attrib['unit'])
|
u = ingredient_parser.get_unit(ingredient.attrib['unit'])
|
||||||
|
amount = 0
|
||||||
|
if ingredient.attrib['qty'].strip() != '':
|
||||||
amount, unit, note = ingredient_parser.parse_amount(ingredient.attrib['qty'])
|
amount, unit, note = ingredient_parser.parse_amount(ingredient.attrib['qty'])
|
||||||
ingredient_step.ingredients.add(Ingredient.objects.create(food=f, unit=u, amount=amount, space=self.request.space, ))
|
ingredient_step.ingredients.add(Ingredient.objects.create(food=f, unit=u, amount=amount, space=self.request.space, ))
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
||||||
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
||||||
"Language-Team: Catalan <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Catalan <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -116,7 +116,7 @@ msgstr "Nombre de decimals dels ingredients."
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "Si vols poder crear i veure comentaris a sota de les receptes."
|
msgstr "Si vols poder crear i veure comentaris a sota de les receptes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -133,7 +133,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Barra de navegació s'enganxi a la part superior de la pàgina."
|
msgstr "Barra de navegació s'enganxi a la part superior de la pàgina."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Afegeix automàticament els ingredients del pla d'àpats a la llista de la "
|
"Afegeix automàticament els ingredients del pla d'àpats a la llista de la "
|
||||||
@@ -155,11 +155,11 @@ msgstr ""
|
|||||||
"Tots dos camps són opcionals. Si no se'n dóna cap, es mostrarà el nom "
|
"Tots dos camps són opcionals. Si no se'n dóna cap, es mostrarà el nom "
|
||||||
"d'usuari"
|
"d'usuari"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Paraules clau"
|
msgstr "Paraules clau"
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ msgstr "Temps de preparació en minuts"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Temps d'espera (cocció/fornejat) en minuts"
|
msgstr "Temps d'espera (cocció/fornejat) en minuts"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Ruta"
|
msgstr "Ruta"
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ msgstr "UID Emmagatzematge"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Per defecte"
|
msgstr "Per defecte"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -191,21 +191,21 @@ msgstr ""
|
|||||||
"Per evitar duplicats, s'ignoren les receptes amb el mateix nom que les "
|
"Per evitar duplicats, s'ignoren les receptes amb el mateix nom que les "
|
||||||
"existents. Marqueu aquesta casella per importar-ho tot."
|
"existents. Marqueu aquesta casella per importar-ho tot."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Afegir el teu comentari: "
|
msgstr "Afegir el teu comentari: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Deixeu-lo buit per a Dropbox i introduïu la contrasenya de l'aplicació per a "
|
"Deixeu-lo buit per a Dropbox i introduïu la contrasenya de l'aplicació per a "
|
||||||
"nextcloud."
|
"nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Deixeu-lo buit per a nextcloud i introduïu el token API per a Dropbox."
|
msgstr "Deixeu-lo buit per a nextcloud i introduïu el token API per a Dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -213,33 +213,33 @@ msgstr ""
|
|||||||
"Deixeu-lo buit per a Dropbox i introduïu només l'URL base per a Nextcloud "
|
"Deixeu-lo buit per a Dropbox i introduïu només l'URL base per a Nextcloud "
|
||||||
"(<code>/remote.php/webdav/</code> s'afegeix automàticament)"
|
"(<code>/remote.php/webdav/</code> s'afegeix automàticament)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Emmagatzematge"
|
msgstr "Emmagatzematge"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actiu"
|
msgstr "Actiu"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Cerca Cadena"
|
msgstr "Cerca Cadena"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "ID d'Arxiu"
|
msgstr "ID d'Arxiu"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Has de proporcionar com a mínim una recepta o un títol."
|
msgstr "Has de proporcionar com a mínim una recepta o un títol."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Podeu llistar els usuaris predeterminats amb els quals voleu compartir "
|
"Podeu llistar els usuaris predeterminats amb els quals voleu compartir "
|
||||||
"receptes a la configuració."
|
"receptes a la configuració."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -247,15 +247,15 @@ msgstr ""
|
|||||||
"Podeu utilitzar el marcador per donar format a aquest camp. Consulteu els <a "
|
"Podeu utilitzar el marcador per donar format a aquest camp. Consulteu els <a "
|
||||||
"href=\"/docs/markdown/\">documents aquí </a>"
|
"href=\"/docs/markdown/\">documents aquí </a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Nombre màxim d'usuaris assolit per a aquest espai."
|
msgstr "Nombre màxim d'usuaris assolit per a aquest espai."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "Adreça de correu electrònic existent!"
|
msgstr "Adreça de correu electrònic existent!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -263,15 +263,15 @@ msgstr ""
|
|||||||
"No cal una adreça de correu electrònic, però si està present, s'enviarà "
|
"No cal una adreça de correu electrònic, però si està present, s'enviarà "
|
||||||
"l'enllaç d'invitació a l'usuari."
|
"l'enllaç d'invitació a l'usuari."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Nom agafat."
|
msgstr "Nom agafat."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Accepteu les condicions i la privadesa"
|
msgstr "Accepteu les condicions i la privadesa"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -280,7 +280,7 @@ msgstr ""
|
|||||||
"de trigrama (p. ex., els valors baixos signifiquen que s'ignoren més errors "
|
"de trigrama (p. ex., els valors baixos signifiquen que s'ignoren més errors "
|
||||||
"ortogràfics)."
|
"ortogràfics)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -288,7 +288,7 @@ msgstr ""
|
|||||||
"Seleccioneu el tipus de mètode de cerca. Feu clic <a href=\"/docs/search/"
|
"Seleccioneu el tipus de mètode de cerca. Feu clic <a href=\"/docs/search/"
|
||||||
"\">aquí</a> per obtenir una descripció completa de les opcions."
|
"\">aquí</a> per obtenir una descripció completa de les opcions."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -296,7 +296,7 @@ msgstr ""
|
|||||||
"Utilitzeu la concordança difusa en unitats, paraules clau i ingredients quan "
|
"Utilitzeu la concordança difusa en unitats, paraules clau i ingredients quan "
|
||||||
"editeu i importeu receptes."
|
"editeu i importeu receptes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -304,7 +304,7 @@ msgstr ""
|
|||||||
"Camps per cercar ignorant els accents. La selecció d'aquesta opció pot "
|
"Camps per cercar ignorant els accents. La selecció d'aquesta opció pot "
|
||||||
"millorar o degradar la qualitat de la cerca en funció de l'idioma"
|
"millorar o degradar la qualitat de la cerca en funció de l'idioma"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -312,7 +312,7 @@ msgstr ""
|
|||||||
"Camps per cercar coincidències parcials. (p. ex., en cercar \"Pastís\" "
|
"Camps per cercar coincidències parcials. (p. ex., en cercar \"Pastís\" "
|
||||||
"tornarà \"pastís\" i \"peça\" i \"sabó\")"
|
"tornarà \"pastís\" i \"peça\" i \"sabó\")"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -320,7 +320,7 @@ msgstr ""
|
|||||||
"Camps per cercar l'inici de les coincidències de paraula. (p. ex., en cercar "
|
"Camps per cercar l'inici de les coincidències de paraula. (p. ex., en cercar "
|
||||||
"\"sa\" es tornarà \"amanida\" i \"entrepà\")"
|
"\"sa\" es tornarà \"amanida\" i \"entrepà\")"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -329,7 +329,7 @@ msgstr ""
|
|||||||
"trobareu \"recepta\".) Nota: aquesta opció entrarà en conflicte amb els "
|
"trobareu \"recepta\".) Nota: aquesta opció entrarà en conflicte amb els "
|
||||||
"mètodes de cerca \"web\" i \"cru\"."
|
"mètodes de cerca \"web\" i \"cru\"."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -337,35 +337,35 @@ msgstr ""
|
|||||||
"Camps per a la cerca de text complet. Nota: els mètodes de cerca \"web\", "
|
"Camps per a la cerca de text complet. Nota: els mètodes de cerca \"web\", "
|
||||||
"\"frase\" i \"en brut\" només funcionen amb camps de text complet."
|
"\"frase\" i \"en brut\" només funcionen amb camps de text complet."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Mètode de cerca"
|
msgstr "Mètode de cerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "Cerques difuses"
|
msgstr "Cerques difuses"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Ignora Accents"
|
msgstr "Ignora Accents"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "Cerca Parcial"
|
msgstr "Cerca Parcial"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Comença amb"
|
msgstr "Comença amb"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Cerca Difusa"
|
msgstr "Cerca Difusa"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Text Sencer"
|
msgstr "Text Sencer"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -373,7 +373,7 @@ msgstr ""
|
|||||||
"Els usuaris veuran tots els articles que afegiu a la vostra llista de la "
|
"Els usuaris veuran tots els articles que afegiu a la vostra llista de la "
|
||||||
"compra. Us han d'afegir per veure els elements de la seva llista."
|
"compra. Us han d'afegir per veure els elements de la seva llista."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -381,7 +381,7 @@ msgstr ""
|
|||||||
"Quan afegiu un pla d'àpats a la llista de la compra (de manera manual o "
|
"Quan afegiu un pla d'àpats a la llista de la compra (de manera manual o "
|
||||||
"automàtica), inclou totes les receptes relacionades."
|
"automàtica), inclou totes les receptes relacionades."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -389,93 +389,93 @@ msgstr ""
|
|||||||
"Quan afegiu un pla d'àpats a la llista de la compra (manual o "
|
"Quan afegiu un pla d'àpats a la llista de la compra (manual o "
|
||||||
"automàticament), excloeu els ingredients que teniu a mà."
|
"automàticament), excloeu els ingredients que teniu a mà."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nombre d'hores per defecte per retardar l'entrada d'una llista de la compra."
|
"Nombre d'hores per defecte per retardar l'entrada d'una llista de la compra."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Filtreu la llista de compres per incloure només categories de supermercats."
|
"Filtreu la llista de compres per incloure només categories de supermercats."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "Dies de les entrades recents de la llista de la compra per mostrar."
|
msgstr "Dies de les entrades recents de la llista de la compra per mostrar."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr "Marca el menjar com a \"A mà\" quan marqueu la llista de la compra."
|
msgstr "Marca el menjar com a \"A mà\" quan marqueu la llista de la compra."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "Delimitador per a les exportacions CSV."
|
msgstr "Delimitador per a les exportacions CSV."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "Prefix per afegir en copiar la llista al porta-retalls."
|
msgstr "Prefix per afegir en copiar la llista al porta-retalls."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Compartir Llista de la Compra"
|
msgstr "Compartir Llista de la Compra"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Autosync"
|
msgstr "Autosync"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Afegeix automàticament un pla d'àpats"
|
msgstr "Afegeix automàticament un pla d'àpats"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Exclou a mà"
|
msgstr "Exclou a mà"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Incloure Relacionats"
|
msgstr "Incloure Relacionats"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Hores de retard per defecte"
|
msgstr "Hores de retard per defecte"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Filtrar a supermercat"
|
msgstr "Filtrar a supermercat"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Dies recents"
|
msgstr "Dies recents"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "Delimitador CSV"
|
msgstr "Delimitador CSV"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Prefix de Llista"
|
msgstr "Prefix de Llista"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Auto a mà"
|
msgstr "Auto a mà"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Restablir Herència Alimentària"
|
msgstr "Restablir Herència Alimentària"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Restableix tots els aliments per heretar els camps configurats."
|
msgstr "Restableix tots els aliments per heretar els camps configurats."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Camps dels aliments que s'han d'heretar per defecte."
|
msgstr "Camps dels aliments que s'han d'heretar per defecte."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Mostra el recompte de receptes als filtres de cerca"
|
msgstr "Mostra el recompte de receptes als filtres de cerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -8,8 +8,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||||
"PO-Revision-Date: 2022-10-17 11:33+0000\n"
|
"PO-Revision-Date: 2023-05-31 17:19+0000\n"
|
||||||
"Last-Translator: Sokratis Potamias <sokratespot@gmail.com>\n"
|
"Last-Translator: sweeney <sweeneytodd91@protonmail.com>\n"
|
||||||
"Language-Team: Greek <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Greek <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
"recipes-backend/el/>\n"
|
"recipes-backend/el/>\n"
|
||||||
"Language: el\n"
|
"Language: el\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 4.10.1\n"
|
"X-Generator: Weblate 4.15\n"
|
||||||
|
|
||||||
#: .\cookbook\filters.py:23 .\cookbook\templates\forms\ingredients.html:34
|
#: .\cookbook\filters.py:23 .\cookbook\templates\forms\ingredients.html:34
|
||||||
#: .\cookbook\templates\stats.html:28
|
#: .\cookbook\templates\stats.html:28
|
||||||
@@ -26,7 +26,7 @@ msgstr "Συστατικά"
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:53
|
#: .\cookbook\forms.py:53
|
||||||
msgid "Default unit"
|
msgid "Default unit"
|
||||||
msgstr ""
|
msgstr "Προεπιλεγμένη μονάδα μέτρησης"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:54
|
#: .\cookbook\forms.py:54
|
||||||
msgid "Use fractions"
|
msgid "Use fractions"
|
||||||
@@ -34,7 +34,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:55
|
#: .\cookbook\forms.py:55
|
||||||
msgid "Use KJ"
|
msgid "Use KJ"
|
||||||
msgstr ""
|
msgstr "Χρήση KiloJoule(KJ)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:56
|
#: .\cookbook\forms.py:56
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
@@ -42,7 +42,7 @@ msgstr "Θέμα"
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:57
|
#: .\cookbook\forms.py:57
|
||||||
msgid "Navbar color"
|
msgid "Navbar color"
|
||||||
msgstr ""
|
msgstr "Χρώμα μπάρας πλοήγησης"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:58
|
#: .\cookbook\forms.py:58
|
||||||
msgid "Sticky navbar"
|
msgid "Sticky navbar"
|
||||||
@@ -50,19 +50,19 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:59
|
#: .\cookbook\forms.py:59
|
||||||
msgid "Default page"
|
msgid "Default page"
|
||||||
msgstr ""
|
msgstr "Προεπιλεγμένη σελίδα"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:60
|
#: .\cookbook\forms.py:60
|
||||||
msgid "Show recent recipes"
|
msgid "Show recent recipes"
|
||||||
msgstr ""
|
msgstr "Προβολή πρόσφατων συνταγών"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:61
|
#: .\cookbook\forms.py:61
|
||||||
msgid "Search style"
|
msgid "Search style"
|
||||||
msgstr ""
|
msgstr "Τρόπος αναζήτησης"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:62
|
#: .\cookbook\forms.py:62
|
||||||
msgid "Plan sharing"
|
msgid "Plan sharing"
|
||||||
msgstr ""
|
msgstr "Κοινοποίηση προγράμματος"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:63
|
#: .\cookbook\forms.py:63
|
||||||
msgid "Ingredient decimal places"
|
msgid "Ingredient decimal places"
|
||||||
@@ -70,7 +70,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:64
|
#: .\cookbook\forms.py:64
|
||||||
msgid "Shopping list auto sync period"
|
msgid "Shopping list auto sync period"
|
||||||
msgstr ""
|
msgstr "Χρονική περίοδος αυτόματου συγχρονισμού λίστας αγορών"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:65 .\cookbook\templates\recipe_view.html:21
|
#: .\cookbook\forms.py:65 .\cookbook\templates\recipe_view.html:21
|
||||||
#: .\cookbook\templates\stats.html:47
|
#: .\cookbook\templates\stats.html:47
|
||||||
@@ -79,17 +79,21 @@ msgstr "Σχόλια"
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:66
|
#: .\cookbook\forms.py:66
|
||||||
msgid "Left-handed mode"
|
msgid "Left-handed mode"
|
||||||
msgstr ""
|
msgstr "Έκδοση για αριστερόχειρες"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:70
|
#: .\cookbook\forms.py:70
|
||||||
msgid ""
|
msgid ""
|
||||||
"Color of the top navigation bar. Not all colors work with all themes, just "
|
"Color of the top navigation bar. Not all colors work with all themes, just "
|
||||||
"try them out!"
|
"try them out!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Χρώμα της πάνω μπάρας πλοήγησης. Δεν δουλεύουν όλα τα χρώματα με όλα τα "
|
||||||
|
"θέματα, απλά δοκιμάστε τα!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:72
|
#: .\cookbook\forms.py:72
|
||||||
msgid "Default Unit to be used when inserting a new ingredient into a recipe."
|
msgid "Default Unit to be used when inserting a new ingredient into a recipe."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Προεπιλεγμένη μονάδα μέτρησης που θα χρησιμοποιείται όταν προστίθεται ένα "
|
||||||
|
"υλικό σε μια συνταγή."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:74
|
#: .\cookbook\forms.py:74
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -104,18 +108,20 @@ msgstr ""
|
|||||||
#: .\cookbook\forms.py:77
|
#: .\cookbook\forms.py:77
|
||||||
msgid "Users with whom newly created meal plans should be shared by default."
|
msgid "Users with whom newly created meal plans should be shared by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Χρήστες με του οποίους η κοινοποίηση του προγραμματισμού των γευμάτων θα "
|
||||||
|
"γίνεται από προεπιλογή."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:78
|
#: .\cookbook\forms.py:78
|
||||||
msgid "Users with whom to share shopping lists."
|
msgid "Users with whom to share shopping lists."
|
||||||
msgstr ""
|
msgstr "Χρήστες με του οποίους θα γίνει κοινοποίηση των λιστών αγορών."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:80
|
#: .\cookbook\forms.py:80
|
||||||
msgid "Show recently viewed recipes on search page."
|
msgid "Show recently viewed recipes on search page."
|
||||||
msgstr ""
|
msgstr "Προβολή των προσφάτως προβεβλημένων συνταγών στη σελίδα αναζήτησης."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:81
|
#: .\cookbook\forms.py:81
|
||||||
msgid "Number of decimals to round ingredients."
|
msgid "Number of decimals to round ingredients."
|
||||||
msgstr ""
|
msgstr "Αριθμός των δεκαδικών στα οποία θα γίνεται στρογγυλοποίηση."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:82
|
#: .\cookbook\forms.py:82
|
||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
@@ -153,20 +159,20 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:128 .\cookbook\forms.py:301
|
#: .\cookbook\forms.py:128 .\cookbook\forms.py:301
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Όνομα"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:129 .\cookbook\forms.py:302
|
#: .\cookbook\forms.py:129 .\cookbook\forms.py:302
|
||||||
#: .\cookbook\templates\stats.html:24 .\cookbook\views\lists.py:88
|
#: .\cookbook\templates\stats.html:24 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr ""
|
msgstr "Λέξεις κλειδιά"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:130
|
#: .\cookbook\forms.py:130
|
||||||
msgid "Preparation time in minutes"
|
msgid "Preparation time in minutes"
|
||||||
msgstr ""
|
msgstr "Χρόνος προετοιμασίας σε λεπτά"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:131
|
#: .\cookbook\forms.py:131
|
||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr ""
|
msgstr "Χρόνος αναμονής (μαγείρεμα/ ψήσιμο) σε λεπτά"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:132 .\cookbook\forms.py:270 .\cookbook\forms.py:303
|
#: .\cookbook\forms.py:132 .\cookbook\forms.py:270 .\cookbook\forms.py:303
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
@@ -188,15 +194,18 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:200
|
#: .\cookbook\forms.py:200
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr ""
|
msgstr "Προσθήκη σχολίου: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:215
|
#: .\cookbook\forms.py:215
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Για dropbox παρακαλώ αφήστε το κενό και πληκτρολογήστε το password για "
|
||||||
|
"nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:222
|
#: .\cookbook\forms.py:222
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Για nextcloud αφήστε το κενό και για dropbox πληκτρολογήστε το api token."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:231
|
#: .\cookbook\forms.py:231
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -240,7 +249,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:372
|
#: .\cookbook\forms.py:372
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr ""
|
msgstr "Αυτή η διεύθυνση email δεν είναι διαθέσιμη!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:380
|
#: .\cookbook\forms.py:380
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -306,7 +315,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:463
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr ""
|
msgstr "Μέθοδος αναζήτησης"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:464
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
@@ -330,19 +339,24 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:469
|
#: .\cookbook\forms.py:469
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr ""
|
msgstr "Πλήρες κείμενο"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:494
|
#: .\cookbook\forms.py:494
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Οι χρήστες θα μπορούν να δουν όλα τα αντικείμενα που προστίθενται στην λίστα "
|
||||||
|
"αγορών σας. Για να δείτε τα αντικείμενα στις λίστα αυτών θα πρέπει να σας "
|
||||||
|
"προστέσουν."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:500
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Όταν προστίθεται ένα πρόγραμμα γευμάτων στη λίστα αγορών (χειροκίνητα ή "
|
||||||
|
"αυτόματα), να συμπεριλαμβάνονται όλες οι σχετικές συνταγές."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:501
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -353,18 +367,23 @@ msgstr ""
|
|||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:502
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Προεπιλεγμένος αριθμός ωρών για την καθυστέρηση μιας εγγραφής στη λίστα "
|
||||||
|
"αγορών."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:503
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Φιλτράρισμα λίστας αγορών ώστε να περιλαμβάνει μόνο τις κατηγορίες του "
|
||||||
|
"supermarker."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:504
|
#: .\cookbook\forms.py:504
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr "Αριθμός ημερών για τη προβολή των πρόσφατων εγγραφών της λίστας αγορών."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:505
|
#: .\cookbook\forms.py:505
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Χαρακτηρισμός ενός τροφίμου ως 'Διαθέσιμο' όταν τσεκαριστεί στη λίστα αγορών."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:506
|
#: .\cookbook\forms.py:506
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
@@ -376,27 +395,27 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:511
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr ""
|
msgstr "Κοινοποίηση λίστας αγορών"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:512
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr "Αυτόματος συγχρονισμός"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:513
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr "Αυτόματη προσθήκη προγραμματισμού γευμάτων"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:514
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr "Αποκλεισμός διαθέσιμων"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr "Συμπερίληψη σχετικών"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr "Προεπιλεγμένες ώρες καθυστέρησης"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
@@ -404,7 +423,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\forms.py:518
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr "Πρόσφατες ημέρες"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:519
|
#: .\cookbook\forms.py:519
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
@@ -439,11 +458,13 @@ msgid ""
|
|||||||
"In order to prevent spam, the requested email was not send. Please wait a "
|
"In order to prevent spam, the requested email was not send. Please wait a "
|
||||||
"few minutes and try again."
|
"few minutes and try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Για να αποκλείσουμε πιθανά spam, το email που ζητήθηκε δεν στάλθηκε. "
|
||||||
|
"Παρακαλώ περιμένετε λίγα λεπτά και δοκιμάστε ξανά."
|
||||||
|
|
||||||
#: .\cookbook\helper\permission_helper.py:149
|
#: .\cookbook\helper\permission_helper.py:149
|
||||||
#: .\cookbook\helper\permission_helper.py:172 .\cookbook\views\views.py:152
|
#: .\cookbook\helper\permission_helper.py:172 .\cookbook\views\views.py:152
|
||||||
msgid "You are not logged in and therefore cannot view this page!"
|
msgid "You are not logged in and therefore cannot view this page!"
|
||||||
msgstr ""
|
msgstr "Δεν μπορείτε να δείτε αυτή τη σελίδα γιατί δεν είστε συνδεδεμένος!"
|
||||||
|
|
||||||
#: .\cookbook\helper\permission_helper.py:153
|
#: .\cookbook\helper\permission_helper.py:153
|
||||||
#: .\cookbook\helper\permission_helper.py:159
|
#: .\cookbook\helper\permission_helper.py:159
|
||||||
@@ -455,7 +476,7 @@ msgstr ""
|
|||||||
#: .\cookbook\views\views.py:163 .\cookbook\views\views.py:170
|
#: .\cookbook\views\views.py:163 .\cookbook\views\views.py:170
|
||||||
#: .\cookbook\views\views.py:249
|
#: .\cookbook\views\views.py:249
|
||||||
msgid "You do not have the required permissions to view this page!"
|
msgid "You do not have the required permissions to view this page!"
|
||||||
msgstr ""
|
msgstr "Δεν έχετε τα απαιτούμενα δικαιώματα να δείτε αυτή τη σελίδα!"
|
||||||
|
|
||||||
#: .\cookbook\helper\permission_helper.py:177
|
#: .\cookbook\helper\permission_helper.py:177
|
||||||
#: .\cookbook\helper\permission_helper.py:200
|
#: .\cookbook\helper\permission_helper.py:200
|
||||||
@@ -463,14 +484,15 @@ msgstr ""
|
|||||||
#: .\cookbook\helper\permission_helper.py:237
|
#: .\cookbook\helper\permission_helper.py:237
|
||||||
msgid "You cannot interact with this object as it is not owned by you!"
|
msgid "You cannot interact with this object as it is not owned by you!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Δεν μπορείτε να αλληλεπιδράστε με αυτό το αντικείμενο γιατί δεν σας ανήκει!"
|
||||||
|
|
||||||
#: .\cookbook\helper\permission_helper.py:321
|
#: .\cookbook\helper\permission_helper.py:321
|
||||||
msgid "You have reached the maximum number of recipes for your space."
|
msgid "You have reached the maximum number of recipes for your space."
|
||||||
msgstr ""
|
msgstr "Έχετε υπερβεί τον μέγιστο αριθμό συνταγών για τον χώρο σας."
|
||||||
|
|
||||||
#: .\cookbook\helper\permission_helper.py:333
|
#: .\cookbook\helper\permission_helper.py:333
|
||||||
msgid "You have more users than allowed in your space."
|
msgid "You have more users than allowed in your space."
|
||||||
msgstr ""
|
msgstr "Έχετε περισσότερους χρήστες από το επιτρεπόμενο στον χώρο σας."
|
||||||
|
|
||||||
#: .\cookbook\helper\recipe_search.py:565
|
#: .\cookbook\helper\recipe_search.py:565
|
||||||
msgid "One of queryset or hash_key must be provided"
|
msgid "One of queryset or hash_key must be provided"
|
||||||
@@ -519,33 +541,33 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\integration\paprika.py:46
|
#: .\cookbook\integration\paprika.py:46
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
msgstr ""
|
msgstr "Σημειώσεις"
|
||||||
|
|
||||||
#: .\cookbook\integration\paprika.py:49
|
#: .\cookbook\integration\paprika.py:49
|
||||||
msgid "Nutritional Information"
|
msgid "Nutritional Information"
|
||||||
msgstr ""
|
msgstr "Διατροφικές πληροφορίες"
|
||||||
|
|
||||||
#: .\cookbook\integration\paprika.py:53
|
#: .\cookbook\integration\paprika.py:53
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr ""
|
msgstr "Πηγή"
|
||||||
|
|
||||||
#: .\cookbook\integration\saffron.py:23
|
#: .\cookbook\integration\saffron.py:23
|
||||||
msgid "Servings"
|
msgid "Servings"
|
||||||
msgstr ""
|
msgstr "Μερίδες"
|
||||||
|
|
||||||
#: .\cookbook\integration\saffron.py:25
|
#: .\cookbook\integration\saffron.py:25
|
||||||
msgid "Waiting time"
|
msgid "Waiting time"
|
||||||
msgstr ""
|
msgstr "Χρόνος αναμονής"
|
||||||
|
|
||||||
#: .\cookbook\integration\saffron.py:27
|
#: .\cookbook\integration\saffron.py:27
|
||||||
msgid "Preparation Time"
|
msgid "Preparation Time"
|
||||||
msgstr ""
|
msgstr "Χρόνος προετοιμασίας"
|
||||||
|
|
||||||
#: .\cookbook\integration\saffron.py:29
|
#: .\cookbook\integration\saffron.py:29
|
||||||
#: .\cookbook\templates\forms\ingredients.html:7
|
#: .\cookbook\templates\forms\ingredients.html:7
|
||||||
#: .\cookbook\templates\index.html:7
|
#: .\cookbook\templates\index.html:7
|
||||||
msgid "Cookbook"
|
msgid "Cookbook"
|
||||||
msgstr ""
|
msgstr "Βιβλίο συνταγών"
|
||||||
|
|
||||||
#: .\cookbook\integration\saffron.py:31
|
#: .\cookbook\integration\saffron.py:31
|
||||||
msgid "Section"
|
msgid "Section"
|
||||||
@@ -569,19 +591,19 @@ msgstr ""
|
|||||||
|
|
||||||
#: .\cookbook\migrations\0047_auto_20200602_1133.py:14
|
#: .\cookbook\migrations\0047_auto_20200602_1133.py:14
|
||||||
msgid "Breakfast"
|
msgid "Breakfast"
|
||||||
msgstr ""
|
msgstr "Πρωινό"
|
||||||
|
|
||||||
#: .\cookbook\migrations\0047_auto_20200602_1133.py:19
|
#: .\cookbook\migrations\0047_auto_20200602_1133.py:19
|
||||||
msgid "Lunch"
|
msgid "Lunch"
|
||||||
msgstr ""
|
msgstr "Μεσημεριανό"
|
||||||
|
|
||||||
#: .\cookbook\migrations\0047_auto_20200602_1133.py:24
|
#: .\cookbook\migrations\0047_auto_20200602_1133.py:24
|
||||||
msgid "Dinner"
|
msgid "Dinner"
|
||||||
msgstr ""
|
msgstr "Βραδινό"
|
||||||
|
|
||||||
#: .\cookbook\migrations\0047_auto_20200602_1133.py:29
|
#: .\cookbook\migrations\0047_auto_20200602_1133.py:29
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr ""
|
msgstr "Άλλο"
|
||||||
|
|
||||||
#: .\cookbook\models.py:251
|
#: .\cookbook\models.py:251
|
||||||
msgid ""
|
msgid ""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -102,7 +102,7 @@ msgstr ""
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -114,7 +114,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -132,11 +132,11 @@ msgid ""
|
|||||||
"instead"
|
"instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ msgstr ""
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -160,261 +160,261 @@ msgstr ""
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -13,9 +13,9 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-03-13 06:55+0000\n"
|
"PO-Revision-Date: 2023-05-26 16:19+0000\n"
|
||||||
"Last-Translator: Amara Ude <apu24@drexel.edu>\n"
|
"Last-Translator: Luis Cacho <luiscachog@gmail.com>\n"
|
||||||
"Language-Team: Spanish <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Spanish <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
"recipes-backend/es/>\n"
|
"recipes-backend/es/>\n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
@@ -117,7 +117,7 @@ msgstr "Número de decimales para redondear los ingredientes."
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "Si desea poder crear y ver comentarios debajo de las recetas."
|
msgstr "Si desea poder crear y ver comentarios debajo de las recetas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -135,7 +135,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Hace la barra de navegación fija en la parte superior de la página."
|
msgstr "Hace la barra de navegación fija en la parte superior de la página."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Añadir de manera automática los ingredientes del plan a la lista de la "
|
"Añadir de manera automática los ingredientes del plan a la lista de la "
|
||||||
@@ -157,11 +157,11 @@ msgstr ""
|
|||||||
"Ambos campos son opcionales. Si no se proporciona ninguno, se mostrará el "
|
"Ambos campos son opcionales. Si no se proporciona ninguno, se mostrará el "
|
||||||
"nombre de usuario en su lugar"
|
"nombre de usuario en su lugar"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Palabras clave"
|
msgstr "Palabras clave"
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ msgstr "Tiempo de preparación en minutos"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Tiempo de espera (cocinar/hornear) en minutos"
|
msgstr "Tiempo de espera (cocinar/hornear) en minutos"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Ruta"
|
msgstr "Ruta"
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ msgstr "UID de almacenamiento"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Por defecto"
|
msgstr "Por defecto"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -193,22 +193,22 @@ msgstr ""
|
|||||||
"Para evitar duplicados, las recetas con el mismo nombre serán ignoradas. "
|
"Para evitar duplicados, las recetas con el mismo nombre serán ignoradas. "
|
||||||
"Marca esta opción para importar todas las recetas."
|
"Marca esta opción para importar todas las recetas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Añada su comentario: "
|
msgstr "Añada su comentario: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Déjelo vacío para Dropbox e ingrese la contraseña de la aplicación para "
|
"Déjelo vacío para Dropbox e ingrese la contraseña de la aplicación para "
|
||||||
"nextcloud."
|
"nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Déjelo en blanco para nextcloud e ingrese el token de api para dropbox."
|
"Déjelo en blanco para nextcloud e ingrese el token de api para dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -216,33 +216,33 @@ msgstr ""
|
|||||||
"Dejar vació para Dropbox e introducir sólo la URL base para Nextcloud "
|
"Dejar vació para Dropbox e introducir sólo la URL base para Nextcloud "
|
||||||
"(<code>/remote.php/webdav/</code> se añade automáticamente)"
|
"(<code>/remote.php/webdav/</code> se añade automáticamente)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Almacenamiento"
|
msgstr "Almacenamiento"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Activo"
|
msgstr "Activo"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Cadena de búsqueda"
|
msgstr "Cadena de búsqueda"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "ID de Fichero"
|
msgstr "ID de Fichero"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Debe proporcionar al menos una receta o un título."
|
msgstr "Debe proporcionar al menos una receta o un título."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Puede enumerar los usuarios predeterminados con los que compartir recetas en "
|
"Puede enumerar los usuarios predeterminados con los que compartir recetas en "
|
||||||
"la configuración."
|
"la configuración."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -250,15 +250,15 @@ msgstr ""
|
|||||||
"Puede utilizar Markdown para formatear este campo. Vea la <a href=\"/docs/"
|
"Puede utilizar Markdown para formatear este campo. Vea la <a href=\"/docs/"
|
||||||
"markdown/\">documentación aqui</a>"
|
"markdown/\">documentación aqui</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Se ha alcanzado el número máximo de usuarios en este espacio."
|
msgstr "Se ha alcanzado el número máximo de usuarios en este espacio."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "¡El correo electrónico ya existe!"
|
msgstr "¡El correo electrónico ya existe!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -266,15 +266,15 @@ msgstr ""
|
|||||||
"El correo electrónico es opcional. Si se añade uno se mandará un link de "
|
"El correo electrónico es opcional. Si se añade uno se mandará un link de "
|
||||||
"invitación."
|
"invitación."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "El nombre ya existe."
|
msgstr "El nombre ya existe."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Aceptar términos y condiciones"
|
msgstr "Aceptar términos y condiciones"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -283,7 +283,7 @@ msgstr ""
|
|||||||
"similitud de trigramas(Ej. Valores más pequeños indican que más fallos se "
|
"similitud de trigramas(Ej. Valores más pequeños indican que más fallos se "
|
||||||
"van a ignorar)."
|
"van a ignorar)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -291,7 +291,7 @@ msgstr ""
|
|||||||
"Selecciona el tipo de búsqueda. Haz click <a href=\"/docs/search/\">aquí</"
|
"Selecciona el tipo de búsqueda. Haz click <a href=\"/docs/search/\">aquí</"
|
||||||
"a> para una descripción completa de las opciones."
|
"a> para una descripción completa de las opciones."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -299,7 +299,7 @@ msgstr ""
|
|||||||
"Utilizar comparación difusa en unidades, palabras clave e ingredientes al "
|
"Utilizar comparación difusa en unidades, palabras clave e ingredientes al "
|
||||||
"editar e importar recetas."
|
"editar e importar recetas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -307,7 +307,7 @@ msgstr ""
|
|||||||
"Campos de búsqueda ignorando acentos. La selección de esta opción puede "
|
"Campos de búsqueda ignorando acentos. La selección de esta opción puede "
|
||||||
"mejorar o degradar la calidad de la búsqueda dependiendo del idioma"
|
"mejorar o degradar la calidad de la búsqueda dependiendo del idioma"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -315,7 +315,7 @@ msgstr ""
|
|||||||
"Campos de búsqueda para coincidencias parciales. (por ejemplo, buscar 'Pie' "
|
"Campos de búsqueda para coincidencias parciales. (por ejemplo, buscar 'Pie' "
|
||||||
"devolverá 'pie' y 'piece' y 'soapie')"
|
"devolverá 'pie' y 'piece' y 'soapie')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -323,7 +323,7 @@ msgstr ""
|
|||||||
"Campos de búsqueda para coincidencias al principio de la palabra. (por "
|
"Campos de búsqueda para coincidencias al principio de la palabra. (por "
|
||||||
"ejemplo, buscar 'sa' devolverá 'ensalada' y 'sándwich')"
|
"ejemplo, buscar 'sa' devolverá 'ensalada' y 'sándwich')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -332,7 +332,7 @@ msgstr ""
|
|||||||
"'receta'). Nota: esta opción entrará en conflicto con los métodos de "
|
"'receta'). Nota: esta opción entrará en conflicto con los métodos de "
|
||||||
"búsqueda 'web' y 'raw'."
|
"búsqueda 'web' y 'raw'."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -340,35 +340,35 @@ msgstr ""
|
|||||||
"Campos para búsqueda de texto completo. Nota: los métodos de búsqueda 'web', "
|
"Campos para búsqueda de texto completo. Nota: los métodos de búsqueda 'web', "
|
||||||
"'phrase' y 'raw' solo funcionan con campos de texto completo."
|
"'phrase' y 'raw' solo funcionan con campos de texto completo."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Método de Búsqueda"
|
msgstr "Método de Búsqueda"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "Búsquedas difusas"
|
msgstr "Búsquedas difusas"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Ignorar Acento"
|
msgstr "Ignorar Acento"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "Coincidencia Parcial"
|
msgstr "Coincidencia Parcial"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Comienza Con"
|
msgstr "Comienza Con"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Búsqueda Difusa"
|
msgstr "Búsqueda Difusa"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Texto Completo"
|
msgstr "Texto Completo"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -376,7 +376,7 @@ msgstr ""
|
|||||||
"Los usuarios verán todos los elementos que agregues a tu lista de compras. "
|
"Los usuarios verán todos los elementos que agregues a tu lista de compras. "
|
||||||
"Deben agregarte para ver los elementos en su lista."
|
"Deben agregarte para ver los elementos en su lista."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -384,7 +384,7 @@ msgstr ""
|
|||||||
"Al agregar un plan de comidas a la lista de compras (manualmente o "
|
"Al agregar un plan de comidas a la lista de compras (manualmente o "
|
||||||
"automáticamente), incluir todas las recetas relacionadas."
|
"automáticamente), incluir todas las recetas relacionadas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -392,96 +392,96 @@ msgstr ""
|
|||||||
"Al agregar un plan de comidas a la lista de compras (manualmente o "
|
"Al agregar un plan de comidas a la lista de compras (manualmente o "
|
||||||
"automáticamente), excluir los ingredientes que están disponibles."
|
"automáticamente), excluir los ingredientes que están disponibles."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Número predeterminado de horas para retrasar una entrada en la lista de "
|
"Número predeterminado de horas para retrasar una entrada en la lista de "
|
||||||
"compras."
|
"compras."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Filtrar la lista de compras para incluir solo categorías de supermercados."
|
"Filtrar la lista de compras para incluir solo categorías de supermercados."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "Días de entradas recientes en la lista de compras a mostrar."
|
msgstr "Días de entradas recientes en la lista de compras a mostrar."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Marcar los alimentos como 'Disponible' cuando se marca en la lista de "
|
"Marcar los alimentos como 'Disponible' cuando se marca en la lista de "
|
||||||
"compras."
|
"compras."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "Delimitador a utilizar para exportaciones CSV."
|
msgstr "Delimitador a utilizar para exportaciones CSV."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "Prefijo a agregar al copiar la lista al portapapeles."
|
msgstr "Prefijo a agregar al copiar la lista al portapapeles."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Compartir Lista de la Compra"
|
msgstr "Compartir Lista de la Compra"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Autosincronización"
|
msgstr "Autosincronización"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Agregar Plan de Comidas automáticamente"
|
msgstr "Agregar Plan de Comidas automáticamente"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Excluir Disponible"
|
msgstr "Excluir Disponible"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Incluir Relacionados"
|
msgstr "Incluir Relacionados"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Horas de Retraso Predeterminadas"
|
msgstr "Horas de Retraso Predeterminadas"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Filtrar según Supermercado"
|
msgstr "Filtrar según Supermercado"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Días Recientes"
|
msgstr "Días Recientes"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "Delimitador CSV"
|
msgstr "Delimitador CSV"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Prefijo de la lista"
|
msgstr "Prefijo de la lista"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Auto en existencia"
|
msgstr "Auto en existencia"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Restablecer la herencia de alimentos"
|
msgstr "Restablecer la herencia de alimentos"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Reiniciar todos los alimentos para heredar los campos configurados."
|
msgstr "Reiniciar todos los alimentos para heredar los campos configurados."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Campos en los alimentos que deben ser heredados por defecto."
|
msgstr "Campos en los alimentos que deben ser heredados por defecto."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Mostrar cantidad de recetas en los filtros de búsquedas"
|
msgstr "Mostrar cantidad de recetas en los filtros de búsquedas"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Utilice la forma plural para las unidades y alimentos dentro de este espacio."
|
"Utilice la forma plural para las unidades y alimentos dentro de este espacio."
|
||||||
@@ -603,10 +603,8 @@ msgid "Imported %s recipes."
|
|||||||
msgstr "Se importaron %s recetas."
|
msgstr "Se importaron %s recetas."
|
||||||
|
|
||||||
#: .\cookbook\integration\openeats.py:26
|
#: .\cookbook\integration\openeats.py:26
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Recipe Home"
|
|
||||||
msgid "Recipe source:"
|
msgid "Recipe source:"
|
||||||
msgstr "Página de inicio"
|
msgstr "Recipe source:"
|
||||||
|
|
||||||
#: .\cookbook\integration\paprika.py:49
|
#: .\cookbook\integration\paprika.py:49
|
||||||
msgid "Notes"
|
msgid "Notes"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
||||||
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
||||||
"Language-Team: French <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
"Language-Team: French <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
||||||
@@ -121,7 +121,7 @@ msgstr ""
|
|||||||
"Si vous souhaitez pouvoir créer et consulter des commentaires en dessous des "
|
"Si vous souhaitez pouvoir créer et consulter des commentaires en dessous des "
|
||||||
"recettes."
|
"recettes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -139,7 +139,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Épingler la barre de navigation en haut de la page."
|
msgstr "Épingler la barre de navigation en haut de la page."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ajouter les ingrédients du menu de la semaine à la liste de courses "
|
"Ajouter les ingrédients du menu de la semaine à la liste de courses "
|
||||||
@@ -161,11 +161,11 @@ msgstr ""
|
|||||||
"Les deux champs sont facultatifs. Si aucun n’est rempli, le nom "
|
"Les deux champs sont facultatifs. Si aucun n’est rempli, le nom "
|
||||||
"d’utilisateur sera affiché à la place"
|
"d’utilisateur sera affiché à la place"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Mots-clés"
|
msgstr "Mots-clés"
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ msgstr "Temps de préparation en minutes"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Temps d’attente (cuisson) en minutes"
|
msgstr "Temps d’attente (cuisson) en minutes"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Chemin"
|
msgstr "Chemin"
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ msgstr "UID de stockage"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Par défaut"
|
msgstr "Par défaut"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -197,22 +197,22 @@ msgstr ""
|
|||||||
"Pour éviter les doublons, les recettes de même nom seront ignorées. Cocher "
|
"Pour éviter les doublons, les recettes de même nom seront ignorées. Cocher "
|
||||||
"cette case pour tout importer."
|
"cette case pour tout importer."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Ajoutez votre commentaire : "
|
msgstr "Ajoutez votre commentaire : "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Laissez vide pour Dropbox et renseignez votre mot de passe d’application "
|
"Laissez vide pour Dropbox et renseignez votre mot de passe d’application "
|
||||||
"pour Nextcloud."
|
"pour Nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Laissez vide pour Nextcloud et renseignez votre jeton d’API pour Dropbox."
|
"Laissez vide pour Nextcloud et renseignez votre jeton d’API pour Dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -220,33 +220,33 @@ msgstr ""
|
|||||||
"Laisser vide pour Dropbox et saisissez seulement l’URL de base pour "
|
"Laisser vide pour Dropbox et saisissez seulement l’URL de base pour "
|
||||||
"Nextcloud (<code>/remote.php/webdav/</code> est ajouté automatiquement)"
|
"Nextcloud (<code>/remote.php/webdav/</code> est ajouté automatiquement)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Stockage"
|
msgstr "Stockage"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actif"
|
msgstr "Actif"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Texte recherché"
|
msgstr "Texte recherché"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "ID du fichier"
|
msgstr "ID du fichier"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Vous devez au moins fournir une recette ou un titre."
|
msgstr "Vous devez au moins fournir une recette ou un titre."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous pouvez lister les utilisateurs par défaut avec qui partager des "
|
"Vous pouvez lister les utilisateurs par défaut avec qui partager des "
|
||||||
"recettes dans les paramètres."
|
"recettes dans les paramètres."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -254,15 +254,15 @@ msgstr ""
|
|||||||
"Vous pouvez utiliser du markdown pour mettre en forme ce champ. Voir la <a "
|
"Vous pouvez utiliser du markdown pour mettre en forme ce champ. Voir la <a "
|
||||||
"href=\"/docs/markdown/\">documentation ici</a>"
|
"href=\"/docs/markdown/\">documentation ici</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Nombre maximum d’utilisateurs atteint pour ce groupe."
|
msgstr "Nombre maximum d’utilisateurs atteint pour ce groupe."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "Adresse mail déjà utilisée !"
|
msgstr "Adresse mail déjà utilisée !"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -270,15 +270,15 @@ msgstr ""
|
|||||||
"Une adresse mail n’est pas requise mais si elle est renseignée, le lien "
|
"Une adresse mail n’est pas requise mais si elle est renseignée, le lien "
|
||||||
"d’invitation sera envoyé à l’utilisateur."
|
"d’invitation sera envoyé à l’utilisateur."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Nom déjà utilisé."
|
msgstr "Nom déjà utilisé."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Accepter les conditions d’utilisation"
|
msgstr "Accepter les conditions d’utilisation"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -287,7 +287,7 @@ msgstr ""
|
|||||||
"par similarité de trigrammes (par exemple, des valeurs faibles signifient "
|
"par similarité de trigrammes (par exemple, des valeurs faibles signifient "
|
||||||
"que davantage de fautes de frappe sont ignorées)."
|
"que davantage de fautes de frappe sont ignorées)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -295,7 +295,7 @@ msgstr ""
|
|||||||
"Sélectionner la méthode de recherche. Cliquer <a href=\"/docs/search/"
|
"Sélectionner la méthode de recherche. Cliquer <a href=\"/docs/search/"
|
||||||
"\">ici</a> pour une description complète des choix."
|
"\">ici</a> pour une description complète des choix."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -303,7 +303,7 @@ msgstr ""
|
|||||||
"Utilisez la correspondance floue sur les unités, les mots-clés et les "
|
"Utilisez la correspondance floue sur les unités, les mots-clés et les "
|
||||||
"ingrédients lors de l’édition et de l’importation de recettes."
|
"ingrédients lors de l’édition et de l’importation de recettes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -312,7 +312,7 @@ msgstr ""
|
|||||||
"peut améliorer ou dégrader la qualité de la recherche en fonction de la "
|
"peut améliorer ou dégrader la qualité de la recherche en fonction de la "
|
||||||
"langue."
|
"langue."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -320,7 +320,7 @@ msgstr ""
|
|||||||
"Champs à rechercher pour les correspondances partielles. (par exemple, la "
|
"Champs à rechercher pour les correspondances partielles. (par exemple, la "
|
||||||
"recherche de « Tarte » renverra « tarte », « tartelette » et « tartes »)"
|
"recherche de « Tarte » renverra « tarte », « tartelette » et « tartes »)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -329,7 +329,7 @@ msgstr ""
|
|||||||
"exemple, si vous recherchez « sa », vous obtiendrez « salade » et "
|
"exemple, si vous recherchez « sa », vous obtiendrez « salade » et "
|
||||||
"« sandwich»)."
|
"« sandwich»)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -338,7 +338,7 @@ msgstr ""
|
|||||||
"« rectte», vous trouverez « recette ».) Remarque : cette option est "
|
"« rectte», vous trouverez « recette ».) Remarque : cette option est "
|
||||||
"incompatible avec les méthodes de recherche « web » et « brute »."
|
"incompatible avec les méthodes de recherche « web » et « brute »."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -347,35 +347,35 @@ msgstr ""
|
|||||||
"« web », « phrase » et « brute » ne fonctionnent qu’avec des champs en texte "
|
"« web », « phrase » et « brute » ne fonctionnent qu’avec des champs en texte "
|
||||||
"intégral."
|
"intégral."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Méthode de recherche"
|
msgstr "Méthode de recherche"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "Recherches floues"
|
msgstr "Recherches floues"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Ignorer les accents"
|
msgstr "Ignorer les accents"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "correspondance partielle"
|
msgstr "correspondance partielle"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Commence par"
|
msgstr "Commence par"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Recherche floue"
|
msgstr "Recherche floue"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Texte intégral"
|
msgstr "Texte intégral"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -384,7 +384,7 @@ msgstr ""
|
|||||||
"courses. Ils doivent vous ajouter pour que vous puissiez voir les éléments "
|
"courses. Ils doivent vous ajouter pour que vous puissiez voir les éléments "
|
||||||
"de leur liste."
|
"de leur liste."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -392,7 +392,7 @@ msgstr ""
|
|||||||
"Lors de l’ajout d’un menu de la semaine à la liste de courses (manuel ou "
|
"Lors de l’ajout d’un menu de la semaine à la liste de courses (manuel ou "
|
||||||
"automatique), inclure toutes les recettes connexes."
|
"automatique), inclure toutes les recettes connexes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -400,97 +400,97 @@ msgstr ""
|
|||||||
"Lors de l’ajout d’un menu de la semaine à la liste de courses (manuel ou "
|
"Lors de l’ajout d’un menu de la semaine à la liste de courses (manuel ou "
|
||||||
"automatique), exclure les ingrédients disponibles."
|
"automatique), exclure les ingrédients disponibles."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nombre d'heures par défaut pour retarder l'ajoût d'un article à la liste de "
|
"Nombre d'heures par défaut pour retarder l'ajoût d'un article à la liste de "
|
||||||
"courses."
|
"courses."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Filtrer la liste de courses pour n’inclure que des catégories de "
|
"Filtrer la liste de courses pour n’inclure que des catégories de "
|
||||||
"supermarchés."
|
"supermarchés."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "Jours des entrées récentes de la liste de courses à afficher."
|
msgstr "Jours des entrées récentes de la liste de courses à afficher."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Marquer l’aliment comme disponible lorsqu’il est rayé de la liste de courses."
|
"Marquer l’aliment comme disponible lorsqu’il est rayé de la liste de courses."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "Caractère de séparation à utiliser pour les exportations CSV."
|
msgstr "Caractère de séparation à utiliser pour les exportations CSV."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "Préfixe à ajouter lors de la copie de la liste dans le presse-papiers."
|
msgstr "Préfixe à ajouter lors de la copie de la liste dans le presse-papiers."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Partager la liste de courses"
|
msgstr "Partager la liste de courses"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Synchronisation automatique"
|
msgstr "Synchronisation automatique"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Ajouter le menu de la semaine automatiquement"
|
msgstr "Ajouter le menu de la semaine automatiquement"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Exclure ingrédients disponibles"
|
msgstr "Exclure ingrédients disponibles"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Inclure recettes connexes"
|
msgstr "Inclure recettes connexes"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Heures de retard par défaut"
|
msgstr "Heures de retard par défaut"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Filtrer par supermarché"
|
msgstr "Filtrer par supermarché"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Jours récents"
|
msgstr "Jours récents"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "Caractère de séparation CSV"
|
msgstr "Caractère de séparation CSV"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Préfixe de la liste"
|
msgstr "Préfixe de la liste"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Disponible automatique"
|
msgstr "Disponible automatique"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Réinitialiser l'héritage alimentaire"
|
msgstr "Réinitialiser l'héritage alimentaire"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Réinitialiser tous les aliments pour hériter les champs configurés."
|
msgstr "Réinitialiser tous les aliments pour hériter les champs configurés."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Champs sur les aliments à hériter par défaut."
|
msgstr "Champs sur les aliments à hériter par défaut."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Afficher le nombre de consultations par recette sur les filtres de recherche"
|
"Afficher le nombre de consultations par recette sur les filtres de recherche"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Utiliser la forme plurielle pour les unités et les aliments dans ce groupe."
|
"Utiliser la forme plurielle pour les unités et les aliments dans ce groupe."
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
"PO-Revision-Date: 2023-04-12 11:55+0000\n"
|
||||||
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
"Last-Translator: noxonad <noxonad@proton.me>\n"
|
||||||
"Language-Team: Hungarian <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Hungarian <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -116,7 +116,7 @@ msgstr ""
|
|||||||
"Ha azt szeretné, hogy hozzászólásokat tudjon létrehozni és látni a receptek "
|
"Ha azt szeretné, hogy hozzászólásokat tudjon létrehozni és látni a receptek "
|
||||||
"alatt."
|
"alatt."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -133,7 +133,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "A navigációs sávot az oldal tetejére rögzíti."
|
msgstr "A navigációs sávot az oldal tetejére rögzíti."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Automatikusan hozzáadja az étkezési terv hozzávalóit a bevásárlólistához."
|
"Automatikusan hozzáadja az étkezési terv hozzávalóit a bevásárlólistához."
|
||||||
@@ -154,11 +154,11 @@ msgstr ""
|
|||||||
"Mindkét mező opcionális. Ha egyiket sem adjuk meg, akkor a felhasználónév "
|
"Mindkét mező opcionális. Ha egyiket sem adjuk meg, akkor a felhasználónév "
|
||||||
"jelenik meg helyette"
|
"jelenik meg helyette"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Név"
|
msgstr "Név"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Kulcsszavak"
|
msgstr "Kulcsszavak"
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ msgstr "Előkészítési idő percben"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Várakozási idő (sütés/főzés) percben"
|
msgstr "Várakozási idő (sütés/főzés) percben"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Elérési útvonal"
|
msgstr "Elérési útvonal"
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ msgstr "Tárhely UID"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Alapértelmezett"
|
msgstr "Alapértelmezett"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -191,23 +191,23 @@ msgstr ""
|
|||||||
"recepteket a rendszer figyelmen kívül hagyja. Jelölje be ezt a négyzetet, ha "
|
"recepteket a rendszer figyelmen kívül hagyja. Jelölje be ezt a négyzetet, ha "
|
||||||
"mindent importálni szeretne."
|
"mindent importálni szeretne."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Add hozzá a kommented: "
|
msgstr "Add hozzá a kommented: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"A dropbox esetében hagyja üresen, a nextcloud esetében pedig adja meg az "
|
"A dropbox esetében hagyja üresen, a nextcloud esetében pedig adja meg az "
|
||||||
"alkalmazás jelszavát."
|
"alkalmazás jelszavát."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"A nextcloud esetében hagyja üresen, a dropbox esetében pedig adja meg az api "
|
"A nextcloud esetében hagyja üresen, a dropbox esetében pedig adja meg az api "
|
||||||
"tokent."
|
"tokent."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -215,33 +215,33 @@ msgstr ""
|
|||||||
"Hagyja üresen a dropbox esetén, és csak a nextcloud alap url-jét adja meg "
|
"Hagyja üresen a dropbox esetén, és csak a nextcloud alap url-jét adja meg "
|
||||||
"(<code>/remote.php/webdav/</code> automatikusan hozzáadódik)"
|
"(<code>/remote.php/webdav/</code> automatikusan hozzáadódik)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Tárhely"
|
msgstr "Tárhely"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Aktív"
|
msgstr "Aktív"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Keresési kifejezés"
|
msgstr "Keresési kifejezés"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "Fájl ID"
|
msgstr "Fájl ID"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Legalább egy receptet vagy címet kell megadnia."
|
msgstr "Legalább egy receptet vagy címet kell megadnia."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"A beállításokban megadhatja a receptek megosztására szolgáló alapértelmezett "
|
"A beállításokban megadhatja a receptek megosztására szolgáló alapértelmezett "
|
||||||
"felhasználókat."
|
"felhasználókat."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -249,15 +249,15 @@ msgstr ""
|
|||||||
"A mező formázásához használhatja a markdown formátumot. Lásd a <a href=\"/"
|
"A mező formázásához használhatja a markdown formátumot. Lásd a <a href=\"/"
|
||||||
"docs/markdown/\">dokumentációt itt</a>"
|
"docs/markdown/\">dokumentációt itt</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Elérte a felhasználók maximális számát ezen a területen."
|
msgstr "Elérte a felhasználók maximális számát ezen a területen."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "Az e-mail cím már foglalt!"
|
msgstr "Az e-mail cím már foglalt!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -265,15 +265,15 @@ msgstr ""
|
|||||||
"Az e-mail cím megadása nem kötelező, de ha van, a meghívó linket elküldi a "
|
"Az e-mail cím megadása nem kötelező, de ha van, a meghívó linket elküldi a "
|
||||||
"felhasználónak."
|
"felhasználónak."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "A név már foglalt."
|
msgstr "A név már foglalt."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Feltételek és adatvédelem elfogadása"
|
msgstr "Feltételek és adatvédelem elfogadása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -282,7 +282,7 @@ msgstr ""
|
|||||||
"párosítást használ (pl. az alacsony értékek azt jelentik, hogy több gépelési "
|
"párosítást használ (pl. az alacsony értékek azt jelentik, hogy több gépelési "
|
||||||
"hibát figyelmen kívül hagynak)."
|
"hibát figyelmen kívül hagynak)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid ""
|
#| msgid ""
|
||||||
#| "Select type method of search. Click <a href=\"/docs/search/\">here</a> "
|
#| "Select type method of search. Click <a href=\"/docs/search/\">here</a> "
|
||||||
@@ -294,7 +294,7 @@ msgstr ""
|
|||||||
"Válassza ki a keresés típusát. Kattintson <a href=\"/docs/search/\">ide</a> "
|
"Válassza ki a keresés típusát. Kattintson <a href=\"/docs/search/\">ide</a> "
|
||||||
"a lehetőségek teljes leírásáért."
|
"a lehetőségek teljes leírásáért."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -302,7 +302,7 @@ msgstr ""
|
|||||||
"A receptek szerkesztése és importálása során az egységek, kulcsszavak és "
|
"A receptek szerkesztése és importálása során az egységek, kulcsszavak és "
|
||||||
"összetevők bizonytalan megfeleltetése."
|
"összetevők bizonytalan megfeleltetése."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -310,7 +310,7 @@ msgstr ""
|
|||||||
"Az ékezetek figyelmen kívül hagyásával keresendő mezők. Ennek az opciónak a "
|
"Az ékezetek figyelmen kívül hagyásával keresendő mezők. Ennek az opciónak a "
|
||||||
"kiválasztása javíthatja vagy ronthatja a keresés minőségét a nyelvtől függően"
|
"kiválasztása javíthatja vagy ronthatja a keresés minőségét a nyelvtől függően"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -318,7 +318,7 @@ msgstr ""
|
|||||||
"Részleges egyezések keresésére szolgáló mezők. (pl. a 'Pie' keresése a "
|
"Részleges egyezések keresésére szolgáló mezők. (pl. a 'Pie' keresése a "
|
||||||
"'pie' és a 'piece' és a 'soapie' kifejezéseket adja vissza.)"
|
"'pie' és a 'piece' és a 'soapie' kifejezéseket adja vissza.)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -326,7 +326,7 @@ msgstr ""
|
|||||||
"Mezők a szó eleji egyezések kereséséhez. (pl. a 'sa' keresés a 'salad' és a "
|
"Mezők a szó eleji egyezések kereséséhez. (pl. a 'sa' keresés a 'salad' és a "
|
||||||
"'sandwich' kifejezéseket adja vissza)"
|
"'sandwich' kifejezéseket adja vissza)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -335,7 +335,7 @@ msgstr ""
|
|||||||
"'recipe' szót.) Megjegyzés: ez az opció ütközik a 'web' és a 'raw' keresési "
|
"'recipe' szót.) Megjegyzés: ez az opció ütközik a 'web' és a 'raw' keresési "
|
||||||
"módszerekkel."
|
"módszerekkel."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -343,37 +343,37 @@ msgstr ""
|
|||||||
"Mezők a teljes szöveges kereséshez. Megjegyzés: A 'web', 'phrase' és 'raw' "
|
"Mezők a teljes szöveges kereséshez. Megjegyzés: A 'web', 'phrase' és 'raw' "
|
||||||
"keresési módszerek csak teljes szöveges mezőkkel működnek."
|
"keresési módszerek csak teljes szöveges mezőkkel működnek."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Keresési módszer"
|
msgstr "Keresési módszer"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "Bizonytalan keresések"
|
msgstr "Bizonytalan keresések"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Ékezetek ignorálása"
|
msgstr "Ékezetek ignorálása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "Részleges találat"
|
msgstr "Részleges találat"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Starts Wtih"
|
#| msgid "Starts Wtih"
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Kezdődik a következővel"
|
msgstr "Kezdődik a következővel"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Bizonytalan keresés"
|
msgstr "Bizonytalan keresés"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Teljes szöveg"
|
msgstr "Teljes szöveg"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -382,7 +382,7 @@ msgstr ""
|
|||||||
"Ahhoz, hogy láthassák a saját listájukon szereplő tételeket, hozzá kell "
|
"Ahhoz, hogy láthassák a saját listájukon szereplő tételeket, hozzá kell "
|
||||||
"adniuk téged."
|
"adniuk téged."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -390,7 +390,7 @@ msgstr ""
|
|||||||
"Amikor étkezési tervet ad hozzá a bevásárlólistához (kézzel vagy "
|
"Amikor étkezési tervet ad hozzá a bevásárlólistához (kézzel vagy "
|
||||||
"automatikusan), vegye fel az összes kapcsolódó receptet."
|
"automatikusan), vegye fel az összes kapcsolódó receptet."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -398,96 +398,96 @@ msgstr ""
|
|||||||
"Amikor étkezési tervet ad hozzá a bevásárlólistához (kézzel vagy "
|
"Amikor étkezési tervet ad hozzá a bevásárlólistához (kézzel vagy "
|
||||||
"automatikusan), zárja ki a kéznél lévő összetevőket."
|
"automatikusan), zárja ki a kéznél lévő összetevőket."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr "A bevásárlólista bejegyzés késleltetésének alapértelmezett ideje."
|
msgstr "A bevásárlólista bejegyzés késleltetésének alapértelmezett ideje."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Szűrje a bevásárlólistát úgy, hogy csak a szupermarket kategóriákat "
|
"Szűrje a bevásárlólistát úgy, hogy csak a szupermarket kategóriákat "
|
||||||
"tartalmazza."
|
"tartalmazza."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "A legutóbbi bevásárlólista bejegyzések megjelenítendő napjai."
|
msgstr "A legutóbbi bevásárlólista bejegyzések megjelenítendő napjai."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jelölje meg a \" Kéznél van\" jelölést, ha a bevásárlólistáról kipipálta az "
|
"Jelölje meg a \" Kéznél van\" jelölést, ha a bevásárlólistáról kipipálta az "
|
||||||
"élelmiszert."
|
"élelmiszert."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "A CSV exportáláshoz használandó elválasztójel."
|
msgstr "A CSV exportáláshoz használandó elválasztójel."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "A lista vágólapra másolásakor hozzáadandó előtag."
|
msgstr "A lista vágólapra másolásakor hozzáadandó előtag."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Bevásárlólista megosztása"
|
msgstr "Bevásárlólista megosztása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Automatikus szinkronizálás"
|
msgstr "Automatikus szinkronizálás"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Automatikus étkezési terv hozzáadása"
|
msgstr "Automatikus étkezési terv hozzáadása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Kéznél levő kihagyása"
|
msgstr "Kéznél levő kihagyása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Tartalmazza a kapcsolódókat"
|
msgstr "Tartalmazza a kapcsolódókat"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Alapértelmezett késleltetési órák"
|
msgstr "Alapértelmezett késleltetési órák"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Szűrő a szupermarkethez"
|
msgstr "Szűrő a szupermarkethez"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Legutóbbi napok"
|
msgstr "Legutóbbi napok"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "CSV elválasztó"
|
msgstr "CSV elválasztó"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Lista előtagja"
|
msgstr "Lista előtagja"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Automatikus Kéznél lévő"
|
msgstr "Automatikus Kéznél lévő"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Élelmiszer-öröklés visszaállítása"
|
msgstr "Élelmiszer-öröklés visszaállítása"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Állítsa vissza az összes ételt, hogy örökölje a konfigurált mezőket."
|
msgstr "Állítsa vissza az összes ételt, hogy örökölje a konfigurált mezőket."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Az élelmiszerek azon mezői, amelyeket alapértelmezés szerint örökölni kell."
|
"Az élelmiszerek azon mezői, amelyeket alapértelmezés szerint örökölni kell."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "A receptek számának megjelenítése a keresési szűrőkön"
|
msgstr "A receptek számának megjelenítése a keresési szűrőkön"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -11,7 +11,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-04-29 07:55+0000\n"
|
"PO-Revision-Date: 2023-04-29 07:55+0000\n"
|
||||||
"Last-Translator: Oliver Cervera <olivercervera@yahoo.it>\n"
|
"Last-Translator: Oliver Cervera <olivercervera@yahoo.it>\n"
|
||||||
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -116,7 +116,7 @@ msgid "If you want to be able to create and see comments underneath recipes."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Se vuoi essere in grado di creare e vedere i commenti sotto le ricette."
|
"Se vuoi essere in grado di creare e vedere i commenti sotto le ricette."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -134,7 +134,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Fissa la barra di navigazione nella parte superiore della pagina."
|
msgstr "Fissa la barra di navigazione nella parte superiore della pagina."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Aggiungi automaticamente gli ingredienti del piano alimentare alla lista "
|
"Aggiungi automaticamente gli ingredienti del piano alimentare alla lista "
|
||||||
@@ -156,11 +156,11 @@ msgstr ""
|
|||||||
"Entrambi i campi sono facoltativi. Se non viene fornito, verrà visualizzato "
|
"Entrambi i campi sono facoltativi. Se non viene fornito, verrà visualizzato "
|
||||||
"il nome utente"
|
"il nome utente"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Parole chiave"
|
msgstr "Parole chiave"
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ msgstr "Tempo di preparazione in minuti"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Tempo di attesa (cottura) in minuti"
|
msgstr "Tempo di attesa (cottura) in minuti"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Percorso"
|
msgstr "Percorso"
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ msgstr "UID di archiviazione"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Predefinito"
|
msgstr "Predefinito"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -192,20 +192,20 @@ msgstr ""
|
|||||||
"Per prevenire duplicati, vengono ignorate le ricette che hanno lo stesso "
|
"Per prevenire duplicati, vengono ignorate le ricette che hanno lo stesso "
|
||||||
"nome di quelle esistenti. Metti la spunta per importare tutto."
|
"nome di quelle esistenti. Metti la spunta per importare tutto."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Aggiungi il tuo commento: "
|
msgstr "Aggiungi il tuo commento: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Lascia vuoto per dropbox e inserisci la password dell'app per nextcloud."
|
"Lascia vuoto per dropbox e inserisci la password dell'app per nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Lascia vuoto per nextcloud e inserisci l'api token per dropbox."
|
msgstr "Lascia vuoto per nextcloud e inserisci l'api token per dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -213,33 +213,33 @@ msgstr ""
|
|||||||
"Lascia vuoto per dropbox e inserisci solo l'url base per nextcloud (<code>/"
|
"Lascia vuoto per dropbox e inserisci solo l'url base per nextcloud (<code>/"
|
||||||
"remote.php/webdav/</code> è aggiunto automaticamente)"
|
"remote.php/webdav/</code> è aggiunto automaticamente)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Archiviazione"
|
msgstr "Archiviazione"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Attivo"
|
msgstr "Attivo"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Stringa di Ricerca"
|
msgstr "Stringa di Ricerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "ID del File"
|
msgstr "ID del File"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Devi fornire almeno una ricetta o un titolo."
|
msgstr "Devi fornire almeno una ricetta o un titolo."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"È possibile visualizzare l'elenco degli utenti predefiniti con cui "
|
"È possibile visualizzare l'elenco degli utenti predefiniti con cui "
|
||||||
"condividere le ricette nelle impostazioni."
|
"condividere le ricette nelle impostazioni."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -247,15 +247,15 @@ msgstr ""
|
|||||||
"Puoi usare markdown per formattare questo campo. Guarda la <a href=\"/docs/"
|
"Puoi usare markdown per formattare questo campo. Guarda la <a href=\"/docs/"
|
||||||
"markdown/\">documentazione qui</a>"
|
"markdown/\">documentazione qui</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "È stato raggiunto il numero massimo di utenti per questa istanza."
|
msgstr "È stato raggiunto il numero massimo di utenti per questa istanza."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "Questo indirizzo email è già in uso!"
|
msgstr "Questo indirizzo email è già in uso!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -263,15 +263,15 @@ msgstr ""
|
|||||||
"Non è obbligatorio specificare l'indirizzo email, ma se presente verrà "
|
"Non è obbligatorio specificare l'indirizzo email, ma se presente verrà "
|
||||||
"utilizzato per mandare all'utente un link di invito."
|
"utilizzato per mandare all'utente un link di invito."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Nome già in uso."
|
msgstr "Nome già in uso."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Accetta i Termini d'uso e Privacy"
|
msgstr "Accetta i Termini d'uso e Privacy"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -280,7 +280,7 @@ msgstr ""
|
|||||||
"trigrammi (ad esempio, valori bassi significano che vengono ignorati più "
|
"trigrammi (ad esempio, valori bassi significano che vengono ignorati più "
|
||||||
"errori di battitura)."
|
"errori di battitura)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -288,7 +288,7 @@ msgstr ""
|
|||||||
"Seleziona il metodo di ricerca. Clicca <a href=\"/docs/search/\">qui</a> "
|
"Seleziona il metodo di ricerca. Clicca <a href=\"/docs/search/\">qui</a> "
|
||||||
"per avere maggiori informazioni."
|
"per avere maggiori informazioni."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -296,7 +296,7 @@ msgstr ""
|
|||||||
"Usa la corrispondenza vaga per unità, parole chiave e ingredienti durante la "
|
"Usa la corrispondenza vaga per unità, parole chiave e ingredienti durante la "
|
||||||
"modifica e l'importazione di ricette."
|
"modifica e l'importazione di ricette."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -304,7 +304,7 @@ msgstr ""
|
|||||||
"Campi da cercare ignorando gli accenti. A seconda alla lingua utilizzata, "
|
"Campi da cercare ignorando gli accenti. A seconda alla lingua utilizzata, "
|
||||||
"questa opzione può migliorare o peggiorare la ricerca"
|
"questa opzione può migliorare o peggiorare la ricerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -312,7 +312,7 @@ msgstr ""
|
|||||||
"Campi da cercare con corrispondenza parziale. (ad esempio, cercando 'Torta' "
|
"Campi da cercare con corrispondenza parziale. (ad esempio, cercando 'Torta' "
|
||||||
"verranno mostrati 'torta', 'tortino' e 'contorta')"
|
"verranno mostrati 'torta', 'tortino' e 'contorta')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -320,7 +320,7 @@ msgstr ""
|
|||||||
"Campi da cercare all'inizio di parole corrispondenti (es. cercando per 'ins' "
|
"Campi da cercare all'inizio di parole corrispondenti (es. cercando per 'ins' "
|
||||||
"mostrerà 'insalata' e 'insaccati')"
|
"mostrerà 'insalata' e 'insaccati')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -329,7 +329,7 @@ msgstr ""
|
|||||||
"verrà mostrato 'ricetta'). Nota: questa opzione non è compatibile con la "
|
"verrà mostrato 'ricetta'). Nota: questa opzione non è compatibile con la "
|
||||||
"ricerca 'web' o 'raw'."
|
"ricerca 'web' o 'raw'."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -337,35 +337,35 @@ msgstr ""
|
|||||||
"Campi per la ricerca full-text. Nota: i metodi di ricerca 'web', 'frase' e "
|
"Campi per la ricerca full-text. Nota: i metodi di ricerca 'web', 'frase' e "
|
||||||
"'raw' funzionano solo con i campi full-text."
|
"'raw' funzionano solo con i campi full-text."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Metodo di ricerca"
|
msgstr "Metodo di ricerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "Ricerche vaghe"
|
msgstr "Ricerche vaghe"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Ignora accento"
|
msgstr "Ignora accento"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "Corrispondenza parziale"
|
msgstr "Corrispondenza parziale"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Inizia con"
|
msgstr "Inizia con"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Ricerca vaga"
|
msgstr "Ricerca vaga"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Full Text"
|
msgstr "Full Text"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -373,7 +373,7 @@ msgstr ""
|
|||||||
"Gli utenti potranno vedere tutti gli elementi che aggiungi alla tua lista "
|
"Gli utenti potranno vedere tutti gli elementi che aggiungi alla tua lista "
|
||||||
"della spesa. Devono aggiungerti per vedere gli elementi nella loro lista."
|
"della spesa. Devono aggiungerti per vedere gli elementi nella loro lista."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -381,7 +381,7 @@ msgstr ""
|
|||||||
"Quando si aggiunge un piano alimentare alla lista della spesa (manualmente o "
|
"Quando si aggiunge un piano alimentare alla lista della spesa (manualmente o "
|
||||||
"automaticamente), includi tutte le ricette correlate."
|
"automaticamente), includi tutte le ricette correlate."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -389,97 +389,97 @@ msgstr ""
|
|||||||
"Quando si aggiunge un piano alimentare alla lista della spesa (manualmente o "
|
"Quando si aggiunge un piano alimentare alla lista della spesa (manualmente o "
|
||||||
"automaticamente), escludi gli ingredienti già disponibili."
|
"automaticamente), escludi gli ingredienti già disponibili."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Il numero predefinito di ore per ritardare l'inserimento di una lista della "
|
"Il numero predefinito di ore per ritardare l'inserimento di una lista della "
|
||||||
"spesa."
|
"spesa."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Filtra la lista della spesa per includere solo categorie dei supermercati."
|
"Filtra la lista della spesa per includere solo categorie dei supermercati."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "Giorni di visualizzazione di voci recenti della lista della spesa."
|
msgstr "Giorni di visualizzazione di voci recenti della lista della spesa."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Contrassegna gli alimenti come 'Disponibili' quando spuntati dalla lista "
|
"Contrassegna gli alimenti come 'Disponibili' quando spuntati dalla lista "
|
||||||
"della spesa."
|
"della spesa."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "Delimitatore usato per le esportazioni CSV."
|
msgstr "Delimitatore usato per le esportazioni CSV."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "Prefisso da aggiungere quando si copia una lista negli appunti."
|
msgstr "Prefisso da aggiungere quando si copia una lista negli appunti."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Condividi lista della spesa"
|
msgstr "Condividi lista della spesa"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Sincronizzazione automatica"
|
msgstr "Sincronizzazione automatica"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Aggiungi automaticamente al piano alimentare"
|
msgstr "Aggiungi automaticamente al piano alimentare"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Escludi Disponibile"
|
msgstr "Escludi Disponibile"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Includi correlati"
|
msgstr "Includi correlati"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Ore di ritardo predefinite"
|
msgstr "Ore di ritardo predefinite"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Filtra per supermercato"
|
msgstr "Filtra per supermercato"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Giorni recenti"
|
msgstr "Giorni recenti"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "Delimitatore CSV"
|
msgstr "Delimitatore CSV"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Prefisso lista"
|
msgstr "Prefisso lista"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Disponibilità automatica"
|
msgstr "Disponibilità automatica"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Ripristina Eredità Alimenti"
|
msgstr "Ripristina Eredità Alimenti"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Ripristina tutti gli alimenti per ereditare i campi configurati."
|
msgstr "Ripristina tutti gli alimenti per ereditare i campi configurati."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Campi su alimenti che devono essere ereditati per impostazione predefinita."
|
"Campi su alimenti che devono essere ereditati per impostazione predefinita."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Mostra il conteggio delle ricette nei filtri di ricerca"
|
msgstr "Mostra il conteggio delle ricette nei filtri di ricerca"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Usare la forma plurale per le unità e gli alimenti all'interno di questo "
|
"Usare la forma plurale per le unità e gli alimenti all'interno di questo "
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-01-08 17:55+0000\n"
|
"PO-Revision-Date: 2023-01-08 17:55+0000\n"
|
||||||
"Last-Translator: Joachim Weber <joachim.weber@gmx.de>\n"
|
"Last-Translator: Joachim Weber <joachim.weber@gmx.de>\n"
|
||||||
"Language-Team: Latvian <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Latvian <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -125,7 +125,7 @@ msgid "If you want to be able to create and see comments underneath recipes."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Ja vēlaties, lai jūs varētu izveidot un redzēt komentārus zem receptēm."
|
"Ja vēlaties, lai jūs varētu izveidot un redzēt komentārus zem receptēm."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -143,7 +143,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -163,11 +163,11 @@ msgstr ""
|
|||||||
"Abi lauki nav obligāti. Ja neviens nav norādīts, tā vietā tiks parādīts "
|
"Abi lauki nav obligāti. Ja neviens nav norādīts, tā vietā tiks parādīts "
|
||||||
"lietotājvārds"
|
"lietotājvārds"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Vārds"
|
msgstr "Vārds"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Atslēgvārdi"
|
msgstr "Atslēgvārdi"
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ msgstr "Pagatavošanas laiks minūtēs"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Gaidīšanas laiks (vārīšana / cepšana) minūtēs"
|
msgstr "Gaidīšanas laiks (vārīšana / cepšana) minūtēs"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Ceļš"
|
msgstr "Ceļš"
|
||||||
|
|
||||||
@@ -191,25 +191,25 @@ msgstr "Krātuves UID"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Pievienot komentāru: "
|
msgstr "Pievienot komentāru: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr "Atstājiet tukšu Dropbox un ievadiet lietotnes paroli Nextcloud."
|
msgstr "Atstājiet tukšu Dropbox un ievadiet lietotnes paroli Nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Atstājiet tukšu Nextcloud un ievadiet API tokenu Dropbox."
|
msgstr "Atstājiet tukšu Nextcloud un ievadiet API tokenu Dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -217,33 +217,33 @@ msgstr ""
|
|||||||
"Atstājiet tukšu Dropbox un ievadiet tikai Nextcloud bāzes URL (<kods> /"
|
"Atstājiet tukšu Dropbox un ievadiet tikai Nextcloud bāzes URL (<kods> /"
|
||||||
"remote.php/webdav/ </code> tiek pievienots automātiski)"
|
"remote.php/webdav/ </code> tiek pievienots automātiski)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Krātuve"
|
msgstr "Krātuve"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Meklēšanas virkne"
|
msgstr "Meklēšanas virkne"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "Faila ID"
|
msgstr "Faila ID"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Jums jānorāda vismaz recepte vai nosaukums."
|
msgstr "Jums jānorāda vismaz recepte vai nosaukums."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Iestatījumos varat uzskaitīt noklusējuma lietotājus, ar kuriem koplietot "
|
"Iestatījumos varat uzskaitīt noklusējuma lietotājus, ar kuriem koplietot "
|
||||||
"receptes."
|
"receptes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -251,219 +251,219 @@ msgstr ""
|
|||||||
"Lai formatētu šo lauku, varat izmantot Markdown. Skatiet <a href=\"/docs/"
|
"Lai formatētu šo lauku, varat izmantot Markdown. Skatiet <a href=\"/docs/"
|
||||||
"markdown/\"> dokumentus šeit </a>"
|
"markdown/\"> dokumentus šeit </a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Search"
|
#| msgid "Search"
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Meklēt"
|
msgstr "Meklēt"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Search"
|
#| msgid "Search"
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Meklēt"
|
msgstr "Meklēt"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Text"
|
#| msgid "Text"
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Teskts"
|
msgstr "Teskts"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Shopping List"
|
#| msgid "Shopping List"
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Iepirkumu saraksts"
|
msgstr "Iepirkumu saraksts"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Saraksta prefikss"
|
msgstr "Saraksta prefikss"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Food that should be replaced."
|
#| msgid "Food that should be replaced."
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Ēdiens, kas būtu jāaizstāj."
|
msgstr "Ēdiens, kas būtu jāaizstāj."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Show recently viewed recipes on search page."
|
#| msgid "Show recently viewed recipes on search page."
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Parādīt nesen skatītās receptes meklēšanas lapā."
|
msgstr "Parādīt nesen skatītās receptes meklēšanas lapā."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-02-27 13:55+0000\n"
|
"PO-Revision-Date: 2023-02-27 13:55+0000\n"
|
||||||
"Last-Translator: Jesse <jesse.kamps@pm.me>\n"
|
"Last-Translator: Jesse <jesse.kamps@pm.me>\n"
|
||||||
"Language-Team: Dutch <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
"Language-Team: Dutch <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
||||||
@@ -116,7 +116,7 @@ msgstr "Aantal decimalen om ingrediënten op af te ronden."
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "Als je opmerkingen onder recepten wil kunnen maken en zien."
|
msgstr "Als je opmerkingen onder recepten wil kunnen maken en zien."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -133,7 +133,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Zet de navbar vast aan de bovenkant van de pagina."
|
msgstr "Zet de navbar vast aan de bovenkant van de pagina."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr "Zet maaltijdplan ingrediënten automatisch op boodschappenlijst."
|
msgstr "Zet maaltijdplan ingrediënten automatisch op boodschappenlijst."
|
||||||
|
|
||||||
@@ -153,11 +153,11 @@ msgstr ""
|
|||||||
"Beide velden zijn optioneel. Indien niks is opgegeven wordt de "
|
"Beide velden zijn optioneel. Indien niks is opgegeven wordt de "
|
||||||
"gebruikersnaam weergegeven"
|
"gebruikersnaam weergegeven"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Naam"
|
msgstr "Naam"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Etiketten"
|
msgstr "Etiketten"
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ msgstr "Voorbereidingstijd in minuten"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Wacht tijd in minuten (koken en bakken)"
|
msgstr "Wacht tijd in minuten (koken en bakken)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Pad"
|
msgstr "Pad"
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ msgstr "Opslag UID"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Standaard waarde"
|
msgstr "Standaard waarde"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -189,19 +189,19 @@ msgstr ""
|
|||||||
"Om dubbelingen te voorkomen worden recepten met dezelfde naam als een "
|
"Om dubbelingen te voorkomen worden recepten met dezelfde naam als een "
|
||||||
"bestaand recept genegeerd. Vink aan om alles te importeren."
|
"bestaand recept genegeerd. Vink aan om alles te importeren."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Voeg een opmerking toe: "
|
msgstr "Voeg een opmerking toe: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr "Laat leeg voor dropbox en vul het app wachtwoord in voor nextcloud."
|
msgstr "Laat leeg voor dropbox en vul het app wachtwoord in voor nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Laat leeg voor nextcloud en vul de api token in voor dropbox."
|
msgstr "Laat leeg voor nextcloud en vul de api token in voor dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -209,33 +209,33 @@ msgstr ""
|
|||||||
"Laat leeg voor dropbox en vul enkel de base url voor nextcloud in. (<code>/"
|
"Laat leeg voor dropbox en vul enkel de base url voor nextcloud in. (<code>/"
|
||||||
"remote.php/webdav/</code> wordt automatisch toegevoegd.)"
|
"remote.php/webdav/</code> wordt automatisch toegevoegd.)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Opslag"
|
msgstr "Opslag"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actief"
|
msgstr "Actief"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Zoekopdracht"
|
msgstr "Zoekopdracht"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "Bestands ID"
|
msgstr "Bestands ID"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "Je moet minimaal één recept of titel te specificeren."
|
msgstr "Je moet minimaal één recept of titel te specificeren."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Je kan in de instellingen standaard gebruikers in stellen om de recepten met "
|
"Je kan in de instellingen standaard gebruikers in stellen om de recepten met "
|
||||||
"te delen."
|
"te delen."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -243,15 +243,15 @@ msgstr ""
|
|||||||
"Je kunt markdown gebruiken om dit veld te op te maken. Bekijk de <a href=\"/"
|
"Je kunt markdown gebruiken om dit veld te op te maken. Bekijk de <a href=\"/"
|
||||||
"docs/markdown/\">documentatie hier</a>"
|
"docs/markdown/\">documentatie hier</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Maximum aantal gebruikers voor deze ruimte bereikt."
|
msgstr "Maximum aantal gebruikers voor deze ruimte bereikt."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "E-mailadres reeds in gebruik!"
|
msgstr "E-mailadres reeds in gebruik!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -259,15 +259,15 @@ msgstr ""
|
|||||||
"Een e-mailadres is niet vereist, maar indien aanwezig zal de "
|
"Een e-mailadres is niet vereist, maar indien aanwezig zal de "
|
||||||
"uitnodigingslink naar de gebruiker worden gestuurd."
|
"uitnodigingslink naar de gebruiker worden gestuurd."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Naam reeds in gebruik."
|
msgstr "Naam reeds in gebruik."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Accepteer voorwaarden"
|
msgstr "Accepteer voorwaarden"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -275,7 +275,7 @@ msgstr ""
|
|||||||
"Bepaalt hoe 'fuzzy' een zoekopdracht is als het trigram vergelijken gebruikt "
|
"Bepaalt hoe 'fuzzy' een zoekopdracht is als het trigram vergelijken gebruikt "
|
||||||
"(lage waarden betekenen bijvoorbeeld dat meer typefouten genegeerd worden)."
|
"(lage waarden betekenen bijvoorbeeld dat meer typefouten genegeerd worden)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -283,7 +283,7 @@ msgstr ""
|
|||||||
"Selecteer zoekmethode. Klik <a href=\"/docs/search/\">hier</a> voor een "
|
"Selecteer zoekmethode. Klik <a href=\"/docs/search/\">hier</a> voor een "
|
||||||
"beschrijving van de keuzes."
|
"beschrijving van de keuzes."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -291,7 +291,7 @@ msgstr ""
|
|||||||
"Gebruik 'fuzzy' koppelen bij eenheden, etiketten en ingrediënten bij "
|
"Gebruik 'fuzzy' koppelen bij eenheden, etiketten en ingrediënten bij "
|
||||||
"bewerken en importeren van recepten."
|
"bewerken en importeren van recepten."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -300,7 +300,7 @@ msgstr ""
|
|||||||
"deze optie kan de zoekkwaliteit afhankelijk van de taal, zowel verbeteren "
|
"deze optie kan de zoekkwaliteit afhankelijk van de taal, zowel verbeteren "
|
||||||
"als verslechteren"
|
"als verslechteren"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
@@ -308,7 +308,7 @@ msgstr ""
|
|||||||
"Velden doorzoeken op gedeelde overeenkomsten. (zoeken op 'Appel' vindt "
|
"Velden doorzoeken op gedeelde overeenkomsten. (zoeken op 'Appel' vindt "
|
||||||
"'appel', 'aardappel' en 'appelsap')"
|
"'appel', 'aardappel' en 'appelsap')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
@@ -316,7 +316,7 @@ msgstr ""
|
|||||||
"Velden doorzoeken op overeenkomsten aan het begin van het woord. (zoeken op "
|
"Velden doorzoeken op overeenkomsten aan het begin van het woord. (zoeken op "
|
||||||
"'sa' vindt 'salade' en 'sandwich')"
|
"'sa' vindt 'salade' en 'sandwich')"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -324,7 +324,7 @@ msgstr ""
|
|||||||
"Velden 'fuzzy' doorzoeken. (zoeken op 'recetp' vindt ook 'recept') Noot: "
|
"Velden 'fuzzy' doorzoeken. (zoeken op 'recetp' vindt ook 'recept') Noot: "
|
||||||
"deze optie conflicteert met de zoekmethoden 'web' en 'raw'."
|
"deze optie conflicteert met de zoekmethoden 'web' en 'raw'."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
@@ -332,35 +332,35 @@ msgstr ""
|
|||||||
"Velden doorzoeken op volledige tekst. Noot: Web, Zin en Raw zoekmethoden "
|
"Velden doorzoeken op volledige tekst. Noot: Web, Zin en Raw zoekmethoden "
|
||||||
"werken alleen met volledige tekstvelden."
|
"werken alleen met volledige tekstvelden."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Zoekmethode"
|
msgstr "Zoekmethode"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "'Fuzzy' zoekopdrachten"
|
msgstr "'Fuzzy' zoekopdrachten"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "Negeer accent"
|
msgstr "Negeer accent"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "Gedeeltelijke overeenkomst"
|
msgstr "Gedeeltelijke overeenkomst"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "Begint met"
|
msgstr "Begint met"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "'Fuzzy' zoeken"
|
msgstr "'Fuzzy' zoeken"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Volledige tekst"
|
msgstr "Volledige tekst"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -368,7 +368,7 @@ msgstr ""
|
|||||||
"Gebruikers zien alle items die je op je boodschappenlijst zet. Ze moeten "
|
"Gebruikers zien alle items die je op je boodschappenlijst zet. Ze moeten "
|
||||||
"jou toevoegen om items op hun lijst te zien."
|
"jou toevoegen om items op hun lijst te zien."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
@@ -376,7 +376,7 @@ msgstr ""
|
|||||||
"Als een maaltijdplan aan de boodschappenlijst toegevoegd wordt (handmatig of "
|
"Als een maaltijdplan aan de boodschappenlijst toegevoegd wordt (handmatig of "
|
||||||
"automatisch), neem dan alle recepten op."
|
"automatisch), neem dan alle recepten op."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
@@ -384,94 +384,94 @@ msgstr ""
|
|||||||
"Als een maaltijdplan aan de boodschappenlijst toegevoegd wordt (handmatig of "
|
"Als een maaltijdplan aan de boodschappenlijst toegevoegd wordt (handmatig of "
|
||||||
"automatisch), sluit ingrediënten die op voorraad zijn dan uit."
|
"automatisch), sluit ingrediënten die op voorraad zijn dan uit."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr "Standaard aantal uren om een boodschappenlijst item te vertragen."
|
msgstr "Standaard aantal uren om een boodschappenlijst item te vertragen."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr "Filter boodschappenlijst om alleen supermarktcategorieën te bevatten."
|
msgstr "Filter boodschappenlijst om alleen supermarktcategorieën te bevatten."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "Dagen van recente boodschappenlijst items weer te geven."
|
msgstr "Dagen van recente boodschappenlijst items weer te geven."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markeer eten 'Op voorraad' wanneer het van het boodschappenlijstje is "
|
"Markeer eten 'Op voorraad' wanneer het van het boodschappenlijstje is "
|
||||||
"afgevinkt."
|
"afgevinkt."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "Scheidingsteken te gebruiken voor CSV exports."
|
msgstr "Scheidingsteken te gebruiken voor CSV exports."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Toe te voegen Voorvoegsel bij het kopiëren van een lijst naar het klembord."
|
"Toe te voegen Voorvoegsel bij het kopiëren van een lijst naar het klembord."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Deel boodschappenlijst"
|
msgstr "Deel boodschappenlijst"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "Autosync"
|
msgstr "Autosync"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "Voeg maaltijdplan automatisch toe"
|
msgstr "Voeg maaltijdplan automatisch toe"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "Sluit op voorraad uit"
|
msgstr "Sluit op voorraad uit"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "Neem gerelateerde op"
|
msgstr "Neem gerelateerde op"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "Standaard vertraging in uren"
|
msgstr "Standaard vertraging in uren"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "Filter op supermarkt"
|
msgstr "Filter op supermarkt"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "Afgelopen dagen"
|
msgstr "Afgelopen dagen"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "CSV scheidingsteken"
|
msgstr "CSV scheidingsteken"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "Lijst voorvoegsel"
|
msgstr "Lijst voorvoegsel"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "Auto op voorraad"
|
msgstr "Auto op voorraad"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "Herstel Ingrediënt overname"
|
msgstr "Herstel Ingrediënt overname"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "Herstel alle ingrediënten om de geconfigureerde velden over te nemen."
|
msgstr "Herstel alle ingrediënten om de geconfigureerde velden over te nemen."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Velden van ingrediënten die standaard overgenomen moeten worden."
|
msgstr "Velden van ingrediënten die standaard overgenomen moeten worden."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Toon recepten teller bij zoekfilters"
|
msgstr "Toon recepten teller bij zoekfilters"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr "Gebruik de meervoudsvorm voor eenheden en voedsel in deze ruimte."
|
msgstr "Gebruik de meervoudsvorm voor eenheden en voedsel in deze ruimte."
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-01-08 17:55+0000\n"
|
"PO-Revision-Date: 2023-01-08 17:55+0000\n"
|
||||||
"Last-Translator: Joachim Weber <joachim.weber@gmx.de>\n"
|
"Last-Translator: Joachim Weber <joachim.weber@gmx.de>\n"
|
||||||
"Language-Team: Portuguese <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Portuguese <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -114,7 +114,7 @@ msgstr "Número de casas decimais para arredondamentos."
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "Ativar a funcionalidade comentar receitas."
|
msgstr "Ativar a funcionalidade comentar receitas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -131,7 +131,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "Mantém a barra de navegação no topo da página."
|
msgstr "Mantém a barra de navegação no topo da página."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -151,11 +151,11 @@ msgstr ""
|
|||||||
"Ambos os campos são opcionais. Se nenhum for preenchido o nome de utilizador "
|
"Ambos os campos são opcionais. Se nenhum for preenchido o nome de utilizador "
|
||||||
"será apresentado"
|
"será apresentado"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "Palavras-chave"
|
msgstr "Palavras-chave"
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ msgstr "Tempo de preparação em minutos"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "Tempo de espera (cozedura) em minutos"
|
msgstr "Tempo de espera (cozedura) em minutos"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Caminho"
|
msgstr "Caminho"
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ msgstr "UID de armazenamento"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Predefinição"
|
msgstr "Predefinição"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -187,21 +187,21 @@ msgstr ""
|
|||||||
"Para evitar repetições, receitas com o mesmo nome de receitas já existentes "
|
"Para evitar repetições, receitas com o mesmo nome de receitas já existentes "
|
||||||
"são ignoradas. Marque esta caixa para importar tudo."
|
"são ignoradas. Marque esta caixa para importar tudo."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "Adicionar comentário: "
|
msgstr "Adicionar comentário: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Deixar vazio para Dropbox e inserir palavra-passe de aplicação para "
|
"Deixar vazio para Dropbox e inserir palavra-passe de aplicação para "
|
||||||
"Nextcloud."
|
"Nextcloud."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Deixar vazio para Nextcloud e inserir token api para Dropbox."
|
msgstr "Deixar vazio para Nextcloud e inserir token api para Dropbox."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -209,33 +209,33 @@ msgstr ""
|
|||||||
"Deixar vazio para Dropbox e inserir apenas url base para Nextcloud (<code>/"
|
"Deixar vazio para Dropbox e inserir apenas url base para Nextcloud (<code>/"
|
||||||
"remote.php/webdav/</code>é adicionado automaticamente). "
|
"remote.php/webdav/</code>é adicionado automaticamente). "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Armazenamento"
|
msgstr "Armazenamento"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Ativo"
|
msgstr "Ativo"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "Procurar"
|
msgstr "Procurar"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "ID the ficheiro"
|
msgstr "ID the ficheiro"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "É necessário inserir uma receita ou um título."
|
msgstr "É necessário inserir uma receita ou um título."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"É possível escolher os utilizadores com quem partilhar receitas por defeitos "
|
"É possível escolher os utilizadores com quem partilhar receitas por defeitos "
|
||||||
"nas definições."
|
"nas definições."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
@@ -243,15 +243,15 @@ msgstr ""
|
|||||||
"É possível utilizar markdown para editar este campo. Documentação <a href=\"/"
|
"É possível utilizar markdown para editar este campo. Documentação <a href=\"/"
|
||||||
"docs/markdown/\">disponível aqui</a>"
|
"docs/markdown/\">disponível aqui</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "Número máximo de utilizadores alcançado."
|
msgstr "Número máximo de utilizadores alcançado."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "Endereço email já utilizado!"
|
msgstr "Endereço email já utilizado!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
@@ -259,15 +259,15 @@ msgstr ""
|
|||||||
"Um endereço de email não é obrigatório mas se fornecido será enviada uma "
|
"Um endereço de email não é obrigatório mas se fornecido será enviada uma "
|
||||||
"mensagem ao utilizador."
|
"mensagem ao utilizador."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "Nome já existente."
|
msgstr "Nome já existente."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "Aceitar Termos e Condições"
|
msgstr "Aceitar Termos e Condições"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -276,7 +276,7 @@ msgstr ""
|
|||||||
"de semelhança de trigrama (valores mais baixos significam que mais erros são "
|
"de semelhança de trigrama (valores mais baixos significam que mais erros são "
|
||||||
"ignorados)."
|
"ignorados)."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid ""
|
#| msgid ""
|
||||||
#| "Select type method of search. Click <a href=\"/docs/search/\">here</a> "
|
#| "Select type method of search. Click <a href=\"/docs/search/\">here</a> "
|
||||||
@@ -288,7 +288,7 @@ msgstr ""
|
|||||||
"Selecionar o método de pesquisa. Uma descrição completa das opções pode ser "
|
"Selecionar o método de pesquisa. Uma descrição completa das opções pode ser "
|
||||||
"encontrada <a href=\"/docs/search/\">aqui</a>."
|
"encontrada <a href=\"/docs/search/\">aqui</a>."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
@@ -296,7 +296,7 @@ msgstr ""
|
|||||||
"Utilizar correspondência difusa em unidades, palavras-chave e ingredientes "
|
"Utilizar correspondência difusa em unidades, palavras-chave e ingredientes "
|
||||||
"ao editar e importar receitas."
|
"ao editar e importar receitas."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
@@ -304,171 +304,171 @@ msgstr ""
|
|||||||
"Campos de pesquisa que ignoram pontuação. Esta opção pode aumentar ou "
|
"Campos de pesquisa que ignoram pontuação. Esta opção pode aumentar ou "
|
||||||
"diminuir a qualidade de pesquisa dependendo da língua em uso"
|
"diminuir a qualidade de pesquisa dependendo da língua em uso"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Search"
|
#| msgid "Search"
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "Procurar"
|
msgstr "Procurar"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Search"
|
#| msgid "Search"
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "Procurar"
|
msgstr "Procurar"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Text"
|
#| msgid "Text"
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "Texto"
|
msgstr "Texto"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Shopping"
|
#| msgid "Shopping"
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "Compras"
|
msgstr "Compras"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Food that should be replaced."
|
#| msgid "Food that should be replaced."
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "Prato a ser alterado."
|
msgstr "Prato a ser alterado."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Mostrar receitas recentes na página de pesquisa"
|
msgstr "Mostrar receitas recentes na página de pesquisa"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -102,7 +102,7 @@ msgstr ""
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -114,7 +114,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -132,11 +132,11 @@ msgid ""
|
|||||||
"instead"
|
"instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ msgstr ""
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -160,261 +160,261 @@ msgstr ""
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2022-11-06 22:09+0000\n"
|
"PO-Revision-Date: 2022-11-06 22:09+0000\n"
|
||||||
"Last-Translator: Gorkem <g.kalipcilar@gmail.com>\n"
|
"Last-Translator: Gorkem <g.kalipcilar@gmail.com>\n"
|
||||||
"Language-Team: Turkish <http://translate.tandoor.dev/projects/tandoor/"
|
"Language-Team: Turkish <http://translate.tandoor.dev/projects/tandoor/"
|
||||||
@@ -110,7 +110,7 @@ msgstr "Malzeme birimleri için yuvarlanma basamağı."
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "Tariflerin altında yorumlar oluşturup görebilmek istiyorsanız."
|
msgstr "Tariflerin altında yorumlar oluşturup görebilmek istiyorsanız."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -127,7 +127,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -145,11 +145,11 @@ msgid ""
|
|||||||
"instead"
|
"instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "İsim"
|
msgstr "İsim"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ msgstr ""
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -173,263 +173,263 @@ msgstr ""
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "Varsayılan"
|
msgstr "Varsayılan"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Aktif"
|
msgstr "Aktif"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Show recently viewed recipes on search page."
|
#| msgid "Show recently viewed recipes on search page."
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "Son görüntülenen tarifleri arama sayfasında göster."
|
msgstr "Son görüntülenen tarifleri arama sayfasında göster."
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-26 07:46+0200\n"
|
"POT-Creation-Date: 2023-05-18 14:28+0200\n"
|
||||||
"PO-Revision-Date: 2023-02-26 13:15+0000\n"
|
"PO-Revision-Date: 2023-02-26 13:15+0000\n"
|
||||||
"Last-Translator: 吕楪 <thy@irithys.com>\n"
|
"Last-Translator: 吕楪 <thy@irithys.com>\n"
|
||||||
"Language-Team: Chinese (Simplified) <http://translate.tandoor.dev/projects/"
|
"Language-Team: Chinese (Simplified) <http://translate.tandoor.dev/projects/"
|
||||||
@@ -104,7 +104,7 @@ msgstr "四舍五入食材的小数点数量。"
|
|||||||
msgid "If you want to be able to create and see comments underneath recipes."
|
msgid "If you want to be able to create and see comments underneath recipes."
|
||||||
msgstr "如果你希望能够在菜谱下面创建并看到评论。"
|
msgstr "如果你希望能够在菜谱下面创建并看到评论。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:79 .\cookbook\forms.py:492
|
#: .\cookbook\forms.py:79 .\cookbook\forms.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
"Setting to 0 will disable auto sync. When viewing a shopping list the list "
|
||||||
"is updated every set seconds to sync changes someone else might have made. "
|
"is updated every set seconds to sync changes someone else might have made. "
|
||||||
@@ -119,7 +119,7 @@ msgstr ""
|
|||||||
msgid "Makes the navbar stick to the top of the page."
|
msgid "Makes the navbar stick to the top of the page."
|
||||||
msgstr "使导航栏悬浮在页面的顶部。"
|
msgstr "使导航栏悬浮在页面的顶部。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:83 .\cookbook\forms.py:495
|
#: .\cookbook\forms.py:83 .\cookbook\forms.py:512
|
||||||
msgid "Automatically add meal plan ingredients to shopping list."
|
msgid "Automatically add meal plan ingredients to shopping list."
|
||||||
msgstr "自动将膳食计划食材添加到购物清单中。"
|
msgstr "自动将膳食计划食材添加到购物清单中。"
|
||||||
|
|
||||||
@@ -137,11 +137,11 @@ msgid ""
|
|||||||
"instead"
|
"instead"
|
||||||
msgstr "这两个字段都是可选的。如果没有给出,将显示用户名"
|
msgstr "这两个字段都是可选的。如果没有给出,将显示用户名"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:123 .\cookbook\forms.py:297
|
#: .\cookbook\forms.py:123 .\cookbook\forms.py:314
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名字"
|
msgstr "名字"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:124 .\cookbook\forms.py:298 .\cookbook\views\lists.py:88
|
#: .\cookbook\forms.py:124 .\cookbook\forms.py:315 .\cookbook\views\lists.py:88
|
||||||
msgid "Keywords"
|
msgid "Keywords"
|
||||||
msgstr "关键词"
|
msgstr "关键词"
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ msgstr "准备时间(分钟)"
|
|||||||
msgid "Waiting time (cooking/baking) in minutes"
|
msgid "Waiting time (cooking/baking) in minutes"
|
||||||
msgstr "等候(烹饪、烘焙等)时间(分钟)"
|
msgstr "等候(烹饪、烘焙等)时间(分钟)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:127 .\cookbook\forms.py:266 .\cookbook\forms.py:299
|
#: .\cookbook\forms.py:127 .\cookbook\forms.py:283 .\cookbook\forms.py:316
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "路径"
|
msgstr "路径"
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ msgstr "存储 UID"
|
|||||||
msgid "Default"
|
msgid "Default"
|
||||||
msgstr "默认"
|
msgstr "默认"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:173
|
#: .\cookbook\forms.py:190
|
||||||
msgid ""
|
msgid ""
|
||||||
"To prevent duplicates recipes with the same name as existing ones are "
|
"To prevent duplicates recipes with the same name as existing ones are "
|
||||||
"ignored. Check this box to import everything."
|
"ignored. Check this box to import everything."
|
||||||
@@ -173,19 +173,19 @@ msgstr ""
|
|||||||
"为防止重复,忽略与现有同名的菜谱。选中此框可导入所有内容(危险操作,请先备"
|
"为防止重复,忽略与现有同名的菜谱。选中此框可导入所有内容(危险操作,请先备"
|
||||||
"份)。"
|
"份)。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:196
|
#: .\cookbook\forms.py:213
|
||||||
msgid "Add your comment: "
|
msgid "Add your comment: "
|
||||||
msgstr "发表评论: "
|
msgstr "发表评论: "
|
||||||
|
|
||||||
#: .\cookbook\forms.py:211
|
#: .\cookbook\forms.py:228
|
||||||
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
msgid "Leave empty for dropbox and enter app password for nextcloud."
|
||||||
msgstr "Dropbox 留空并输入 Nextcloud 应用密码。"
|
msgstr "Dropbox 留空并输入 Nextcloud 应用密码。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:218
|
#: .\cookbook\forms.py:235
|
||||||
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
msgid "Leave empty for nextcloud and enter api token for dropbox."
|
||||||
msgstr "Nextcloud 留空并输入 Dropbox API 令牌。"
|
msgstr "Nextcloud 留空并输入 Dropbox API 令牌。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:227
|
#: .\cookbook\forms.py:244
|
||||||
msgid ""
|
msgid ""
|
||||||
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
|
||||||
"php/webdav/</code> is added automatically)"
|
"php/webdav/</code> is added automatically)"
|
||||||
@@ -193,60 +193,60 @@ msgstr ""
|
|||||||
"Dropbox 留空并输入基础 Nextcloud 网址(<code>/remote.php/webdav/</code> 会自"
|
"Dropbox 留空并输入基础 Nextcloud 网址(<code>/remote.php/webdav/</code> 会自"
|
||||||
"动添加)"
|
"动添加)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:265 .\cookbook\views\edit.py:157
|
#: .\cookbook\forms.py:282 .\cookbook\views\edit.py:157
|
||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "存储"
|
msgstr "存储"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:267
|
#: .\cookbook\forms.py:284
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "活跃"
|
msgstr "活跃"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:273
|
#: .\cookbook\forms.py:290
|
||||||
msgid "Search String"
|
msgid "Search String"
|
||||||
msgstr "搜索字符串"
|
msgstr "搜索字符串"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:300
|
#: .\cookbook\forms.py:317
|
||||||
msgid "File ID"
|
msgid "File ID"
|
||||||
msgstr "文件编号"
|
msgstr "文件编号"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:322
|
#: .\cookbook\forms.py:339
|
||||||
msgid "You must provide at least a recipe or a title."
|
msgid "You must provide at least a recipe or a title."
|
||||||
msgstr "你必须至少提供一份菜谱或一个标题。"
|
msgstr "你必须至少提供一份菜谱或一个标题。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:335
|
#: .\cookbook\forms.py:352
|
||||||
msgid "You can list default users to share recipes with in the settings."
|
msgid "You can list default users to share recipes with in the settings."
|
||||||
msgstr "你可以在设置中列出默认用户来分享菜谱。"
|
msgstr "你可以在设置中列出默认用户来分享菜谱。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:336
|
#: .\cookbook\forms.py:353
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
"You can use markdown to format this field. See the <a href=\"/docs/markdown/"
|
||||||
"\">docs here</a>"
|
"\">docs here</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"可以使用 Markdown 设置此字段格式。<a href=\"/docs/markdown/\">查看文档</a>"
|
"可以使用 Markdown 设置此字段格式。<a href=\"/docs/markdown/\">查看文档</a>"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:362
|
#: .\cookbook\forms.py:379
|
||||||
msgid "Maximum number of users for this space reached."
|
msgid "Maximum number of users for this space reached."
|
||||||
msgstr "已达到该空间的最大用户数。"
|
msgstr "已达到该空间的最大用户数。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:368
|
#: .\cookbook\forms.py:385
|
||||||
msgid "Email address already taken!"
|
msgid "Email address already taken!"
|
||||||
msgstr "电子邮件地址已被注册!"
|
msgstr "电子邮件地址已被注册!"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:376
|
#: .\cookbook\forms.py:393
|
||||||
msgid ""
|
msgid ""
|
||||||
"An email address is not required but if present the invite link will be sent "
|
"An email address is not required but if present the invite link will be sent "
|
||||||
"to the user."
|
"to the user."
|
||||||
msgstr "电子邮件地址不是必需的,但如果存在,邀请链接将被发送给用户。"
|
msgstr "电子邮件地址不是必需的,但如果存在,邀请链接将被发送给用户。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:391
|
#: .\cookbook\forms.py:408
|
||||||
msgid "Name already taken."
|
msgid "Name already taken."
|
||||||
msgstr "名字已被占用。"
|
msgstr "名字已被占用。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:402
|
#: .\cookbook\forms.py:419
|
||||||
msgid "Accept Terms and Privacy"
|
msgid "Accept Terms and Privacy"
|
||||||
msgstr "接受条款及隐私政策"
|
msgstr "接受条款及隐私政策"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:434
|
#: .\cookbook\forms.py:451
|
||||||
msgid ""
|
msgid ""
|
||||||
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
|
||||||
"g. low values mean more typos are ignored)."
|
"g. low values mean more typos are ignored)."
|
||||||
@@ -254,7 +254,7 @@ msgstr ""
|
|||||||
"确定使用三元图相似性匹配时搜索的模糊程度(例如,较低的值意味着忽略更多的打字"
|
"确定使用三元图相似性匹配时搜索的模糊程度(例如,较低的值意味着忽略更多的打字"
|
||||||
"错误)。"
|
"错误)。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:444
|
#: .\cookbook\forms.py:461
|
||||||
msgid ""
|
msgid ""
|
||||||
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
"Select type method of search. Click <a href=\"/docs/search/\">here</a> for "
|
||||||
"full description of choices."
|
"full description of choices."
|
||||||
@@ -262,31 +262,31 @@ msgstr ""
|
|||||||
"选择搜索类型方法。 <a href=\"/docs/search/\">点击此处</a> 查看选项的完整说"
|
"选择搜索类型方法。 <a href=\"/docs/search/\">点击此处</a> 查看选项的完整说"
|
||||||
"明。"
|
"明。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:445
|
#: .\cookbook\forms.py:462
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
"Use fuzzy matching on units, keywords and ingredients when editing and "
|
||||||
"importing recipes."
|
"importing recipes."
|
||||||
msgstr "编辑和导入菜谱时,对单位、关键词和食材使用模糊匹配。"
|
msgstr "编辑和导入菜谱时,对单位、关键词和食材使用模糊匹配。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:447
|
#: .\cookbook\forms.py:464
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||||
"degrade search quality depending on language"
|
"degrade search quality depending on language"
|
||||||
msgstr "忽略搜索字段的重音。此选项会因语言差异导致搜索质量产生变化"
|
msgstr "忽略搜索字段的重音。此选项会因语言差异导致搜索质量产生变化"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:449
|
#: .\cookbook\forms.py:466
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||||
"'pie' and 'piece' and 'soapie')"
|
"'pie' and 'piece' and 'soapie')"
|
||||||
msgstr "用于搜索部分匹配的字段。(如搜索“Pie”会返回“pie”、“piece”和“soapie”)"
|
msgstr "用于搜索部分匹配的字段。(如搜索“Pie”会返回“pie”、“piece”和“soapie”)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:451
|
#: .\cookbook\forms.py:468
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
|
||||||
"will return 'salad' and 'sandwich')"
|
"will return 'salad' and 'sandwich')"
|
||||||
msgstr "用于搜索开头匹配的字段。(如搜索“sa”会返回“salad”和“sandwich”)"
|
msgstr "用于搜索开头匹配的字段。(如搜索“sa”会返回“salad”和“sandwich”)"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:453
|
#: .\cookbook\forms.py:470
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
|
||||||
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
"Note: this option will conflict with 'web' and 'raw' methods of search."
|
||||||
@@ -294,41 +294,41 @@ msgstr ""
|
|||||||
"“模糊”搜索字段。(例如搜索“recpie”将会找到“recipe”。)注意:此选项将"
|
"“模糊”搜索字段。(例如搜索“recpie”将会找到“recipe”。)注意:此选项将"
|
||||||
"与“web”和“raw”搜索方法冲突。"
|
"与“web”和“raw”搜索方法冲突。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:455
|
#: .\cookbook\forms.py:472
|
||||||
msgid ""
|
msgid ""
|
||||||
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
|
||||||
"only function with fulltext fields."
|
"only function with fulltext fields."
|
||||||
msgstr "全文搜索字段。“web”、“phrase”和“raw”搜索方法仅适用于全文字段。"
|
msgstr "全文搜索字段。“web”、“phrase”和“raw”搜索方法仅适用于全文字段。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:459
|
#: .\cookbook\forms.py:476
|
||||||
msgid "Search Method"
|
msgid "Search Method"
|
||||||
msgstr "搜索方法"
|
msgstr "搜索方法"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:460
|
#: .\cookbook\forms.py:477
|
||||||
msgid "Fuzzy Lookups"
|
msgid "Fuzzy Lookups"
|
||||||
msgstr "模糊查找"
|
msgstr "模糊查找"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:461
|
#: .\cookbook\forms.py:478
|
||||||
msgid "Ignore Accent"
|
msgid "Ignore Accent"
|
||||||
msgstr "忽略重音"
|
msgstr "忽略重音"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:462
|
#: .\cookbook\forms.py:479
|
||||||
msgid "Partial Match"
|
msgid "Partial Match"
|
||||||
msgstr "部分匹配"
|
msgstr "部分匹配"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:463
|
#: .\cookbook\forms.py:480
|
||||||
msgid "Starts With"
|
msgid "Starts With"
|
||||||
msgstr "起始于"
|
msgstr "起始于"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:464
|
#: .\cookbook\forms.py:481
|
||||||
msgid "Fuzzy Search"
|
msgid "Fuzzy Search"
|
||||||
msgstr "模糊搜索"
|
msgstr "模糊搜索"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:465
|
#: .\cookbook\forms.py:482
|
||||||
msgid "Full Text"
|
msgid "Full Text"
|
||||||
msgstr "全文"
|
msgstr "全文"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:490
|
#: .\cookbook\forms.py:507
|
||||||
msgid ""
|
msgid ""
|
||||||
"Users will see all items you add to your shopping list. They must add you "
|
"Users will see all items you add to your shopping list. They must add you "
|
||||||
"to see items on their list."
|
"to see items on their list."
|
||||||
@@ -336,103 +336,103 @@ msgstr ""
|
|||||||
"用户将看到你添加到购物清单中的所有商品。他们必须将你添加到列表才能看到他们清"
|
"用户将看到你添加到购物清单中的所有商品。他们必须将你添加到列表才能看到他们清"
|
||||||
"单上的项目。"
|
"单上的项目。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:496
|
#: .\cookbook\forms.py:513
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"include all related recipes."
|
"include all related recipes."
|
||||||
msgstr "将膳食计划(手动或自动)添加到购物清单时,包括所有相关食谱。"
|
msgstr "将膳食计划(手动或自动)添加到购物清单时,包括所有相关食谱。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:497
|
#: .\cookbook\forms.py:514
|
||||||
msgid ""
|
msgid ""
|
||||||
"When adding a meal plan to the shopping list (manually or automatically), "
|
"When adding a meal plan to the shopping list (manually or automatically), "
|
||||||
"exclude ingredients that are on hand."
|
"exclude ingredients that are on hand."
|
||||||
msgstr "将膳食计划(手动或自动)添加到购物清单时,排除现有食材。"
|
msgstr "将膳食计划(手动或自动)添加到购物清单时,排除现有食材。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:498
|
#: .\cookbook\forms.py:515
|
||||||
msgid "Default number of hours to delay a shopping list entry."
|
msgid "Default number of hours to delay a shopping list entry."
|
||||||
msgstr "延迟购物清单条目的默认小时数。"
|
msgstr "延迟购物清单条目的默认小时数。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:499
|
#: .\cookbook\forms.py:516
|
||||||
msgid "Filter shopping list to only include supermarket categories."
|
msgid "Filter shopping list to only include supermarket categories."
|
||||||
msgstr "筛选购物清单仅包含超市分类。"
|
msgstr "筛选购物清单仅包含超市分类。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:500
|
#: .\cookbook\forms.py:517
|
||||||
msgid "Days of recent shopping list entries to display."
|
msgid "Days of recent shopping list entries to display."
|
||||||
msgstr "显示最近几天的购物清单列表。"
|
msgstr "显示最近几天的购物清单列表。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:501
|
#: .\cookbook\forms.py:518
|
||||||
msgid "Mark food 'On Hand' when checked off shopping list."
|
msgid "Mark food 'On Hand' when checked off shopping list."
|
||||||
msgstr "在核对购物清单时,将食物标记为“入手”。"
|
msgstr "在核对购物清单时,将食物标记为“入手”。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:502
|
#: .\cookbook\forms.py:519
|
||||||
msgid "Delimiter to use for CSV exports."
|
msgid "Delimiter to use for CSV exports."
|
||||||
msgstr "用于 CSV 导出的分隔符。"
|
msgstr "用于 CSV 导出的分隔符。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:503
|
#: .\cookbook\forms.py:520
|
||||||
msgid "Prefix to add when copying list to the clipboard."
|
msgid "Prefix to add when copying list to the clipboard."
|
||||||
msgstr "将清单复制到剪贴板时要添加的前缀。"
|
msgstr "将清单复制到剪贴板时要添加的前缀。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:507
|
#: .\cookbook\forms.py:524
|
||||||
msgid "Share Shopping List"
|
msgid "Share Shopping List"
|
||||||
msgstr "分享购物清单"
|
msgstr "分享购物清单"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:508
|
#: .\cookbook\forms.py:525
|
||||||
msgid "Autosync"
|
msgid "Autosync"
|
||||||
msgstr "自动同步"
|
msgstr "自动同步"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:509
|
#: .\cookbook\forms.py:526
|
||||||
msgid "Auto Add Meal Plan"
|
msgid "Auto Add Meal Plan"
|
||||||
msgstr "自动添加膳食计划"
|
msgstr "自动添加膳食计划"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:510
|
#: .\cookbook\forms.py:527
|
||||||
msgid "Exclude On Hand"
|
msgid "Exclude On Hand"
|
||||||
msgstr "排除现有"
|
msgstr "排除现有"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:511
|
#: .\cookbook\forms.py:528
|
||||||
msgid "Include Related"
|
msgid "Include Related"
|
||||||
msgstr "包括相关"
|
msgstr "包括相关"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:512
|
#: .\cookbook\forms.py:529
|
||||||
msgid "Default Delay Hours"
|
msgid "Default Delay Hours"
|
||||||
msgstr "默认延迟时间"
|
msgstr "默认延迟时间"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:513
|
#: .\cookbook\forms.py:530
|
||||||
msgid "Filter to Supermarket"
|
msgid "Filter to Supermarket"
|
||||||
msgstr "按超市筛选"
|
msgstr "按超市筛选"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:514
|
#: .\cookbook\forms.py:531
|
||||||
msgid "Recent Days"
|
msgid "Recent Days"
|
||||||
msgstr "最近几天"
|
msgstr "最近几天"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:515
|
#: .\cookbook\forms.py:532
|
||||||
msgid "CSV Delimiter"
|
msgid "CSV Delimiter"
|
||||||
msgstr "CSV 分隔符"
|
msgstr "CSV 分隔符"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:516
|
#: .\cookbook\forms.py:533
|
||||||
msgid "List Prefix"
|
msgid "List Prefix"
|
||||||
msgstr "清单前缀"
|
msgstr "清单前缀"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:517
|
#: .\cookbook\forms.py:534
|
||||||
msgid "Auto On Hand"
|
msgid "Auto On Hand"
|
||||||
msgstr "自动入手"
|
msgstr "自动入手"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:527
|
#: .\cookbook\forms.py:544
|
||||||
msgid "Reset Food Inheritance"
|
msgid "Reset Food Inheritance"
|
||||||
msgstr "重置食物材料"
|
msgstr "重置食物材料"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:528
|
#: .\cookbook\forms.py:545
|
||||||
msgid "Reset all food to inherit the fields configured."
|
msgid "Reset all food to inherit the fields configured."
|
||||||
msgstr "重置所有食物以继承配置的字段。"
|
msgstr "重置所有食物以继承配置的字段。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:540
|
#: .\cookbook\forms.py:557
|
||||||
msgid "Fields on food that should be inherited by default."
|
msgid "Fields on food that should be inherited by default."
|
||||||
msgstr "默认情况下应继承的食物上的字段。"
|
msgstr "默认情况下应继承的食物上的字段。"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:541
|
#: .\cookbook\forms.py:558
|
||||||
msgid "Show recipe counts on search filters"
|
msgid "Show recipe counts on search filters"
|
||||||
msgstr "显示搜索筛选器上的食谱计数"
|
msgstr "显示搜索筛选器上的食谱计数"
|
||||||
|
|
||||||
#: .\cookbook\forms.py:542
|
#: .\cookbook\forms.py:559
|
||||||
msgid "Use the plural form for units and food inside this space."
|
msgid "Use the plural form for units and food inside this space."
|
||||||
msgstr "在此空间内使用复数形式表示单位和食物。"
|
msgstr "在此空间内使用复数形式表示单位和食物。"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
# Generated by Django 4.1.9 on 2023-05-25 13:05
|
||||||
|
|
||||||
|
import cookbook.models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django_prometheus.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('cookbook', '0188_space_no_sharing_limit'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Property',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('property_amount', models.DecimalField(decimal_places=4, default=0, max_digits=32)),
|
||||||
|
],
|
||||||
|
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PropertyType',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=128)),
|
||||||
|
('unit', models.CharField(blank=True, max_length=64, null=True)),
|
||||||
|
('icon', models.CharField(blank=True, max_length=16, null=True)),
|
||||||
|
('description', models.CharField(blank=True, max_length=512, null=True)),
|
||||||
|
('category', models.CharField(blank=True, choices=[('NUTRITION', 'Nutrition'), ('ALLERGEN', 'Allergen'), ('PRICE', 'Price'), ('GOAL', 'Goal'), ('OTHER', 'Other')], max_length=64, null=True)),
|
||||||
|
('open_data_slug', models.CharField(blank=True, default=None, max_length=128, null=True)),
|
||||||
|
],
|
||||||
|
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UnitConversion',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('base_amount', models.DecimalField(decimal_places=16, default=0, max_digits=32)),
|
||||||
|
('converted_amount', models.DecimalField(decimal_places=16, default=0, max_digits=32)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('open_data_slug', models.CharField(blank=True, default=None, max_length=128, null=True)),
|
||||||
|
],
|
||||||
|
bases=(django_prometheus.models.ExportModelOperationsMixin('unit_conversion'), models.Model, cookbook.models.PermissionModelMixin),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='fdc_id',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=128, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='open_data_slug',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=128, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='preferred_shopping_unit',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_shopping_unit', to='cookbook.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='preferred_unit',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preferred_unit', to='cookbook.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties_food_amount',
|
||||||
|
field=models.IntegerField(blank=True, default=100),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties_food_unit',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='cookbook.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='supermarket',
|
||||||
|
name='open_data_slug',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=128, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='supermarketcategory',
|
||||||
|
name='open_data_slug',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=128, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unit',
|
||||||
|
name='base_unit',
|
||||||
|
field=models.TextField(blank=True, default=None, max_length=256, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unit',
|
||||||
|
name='open_data_slug',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=128, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='supermarketcategoryrelation',
|
||||||
|
constraint=models.UniqueConstraint(fields=('supermarket', 'category'), name='unique_sm_category_relation'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unitconversion',
|
||||||
|
name='base_unit',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='unit_conversion_base_relation', to='cookbook.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unitconversion',
|
||||||
|
name='converted_unit',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='unit_conversion_converted_relation', to='cookbook.unit'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unitconversion',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unitconversion',
|
||||||
|
name='food',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cookbook.food'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unitconversion',
|
||||||
|
name='space',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='propertytype',
|
||||||
|
name='space',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='property',
|
||||||
|
name='property_type',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cookbook.propertytype'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='property',
|
||||||
|
name='space',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties',
|
||||||
|
field=models.ManyToManyField(blank=True, to='cookbook.property'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recipe',
|
||||||
|
name='properties',
|
||||||
|
field=models.ManyToManyField(blank=True, to='cookbook.property'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='unitconversion',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'base_unit', 'converted_unit', 'food'), name='f_unique_conversion_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='propertytype',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'name'), name='property_type_unique_name_per_space'),
|
||||||
|
),
|
||||||
|
]
|
||||||
38
cookbook/migrations/0190_auto_20230525_1506.py
Normal file
38
cookbook/migrations/0190_auto_20230525_1506.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.1.9 on 2023-05-25 13:06
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
def migrate_old_nutrition_data(apps, schema_editor):
|
||||||
|
print('Transforming nutrition information, this might take a while on large databases')
|
||||||
|
with scopes_disabled():
|
||||||
|
PropertyType = apps.get_model('cookbook', 'PropertyType')
|
||||||
|
RecipeProperty = apps.get_model('cookbook', 'Property')
|
||||||
|
Recipe = apps.get_model('cookbook', 'Recipe')
|
||||||
|
Space = apps.get_model('cookbook', 'Space')
|
||||||
|
|
||||||
|
# TODO respect space
|
||||||
|
for s in Space.objects.all():
|
||||||
|
property_fat = PropertyType.objects.get_or_create(name=_('Fat'), unit=_('g'), space=s, )[0]
|
||||||
|
property_carbohydrates = PropertyType.objects.get_or_create(name=_('Carbohydrates'), unit=_('g'), space=s, )[0]
|
||||||
|
property_proteins = PropertyType.objects.get_or_create(name=_('Proteins'), unit=_('g'), space=s, )[0]
|
||||||
|
property_calories = PropertyType.objects.get_or_create(name=_('Calories'), unit=_('kcal'), space=s, )[0]
|
||||||
|
|
||||||
|
for r in Recipe.objects.filter(nutrition__isnull=False, space=s).all():
|
||||||
|
rp_fat = RecipeProperty.objects.create(property_type=property_fat, property_amount=r.nutrition.fats, space=s)
|
||||||
|
rp_carbohydrates = RecipeProperty.objects.create(property_type=property_carbohydrates, property_amount=r.nutrition.carbohydrates, space=s)
|
||||||
|
rp_proteins = RecipeProperty.objects.create(property_type=property_proteins, property_amount=r.nutrition.proteins, space=s)
|
||||||
|
rp_calories = RecipeProperty.objects.create(property_type=property_calories, property_amount=r.nutrition.calories, space=s)
|
||||||
|
r.properties.add(rp_fat, rp_carbohydrates, rp_proteins, rp_calories)
|
||||||
|
r.nutrition = None
|
||||||
|
r.save()
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0189_property_propertytype_unitconversion_food_fdc_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(migrate_old_nutrition_data)
|
||||||
|
]
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Generated by Django 4.1.9 on 2023-06-20 13:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0190_auto_20230525_1506'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.SeparateDatabaseAndState(
|
||||||
|
database_operations=[
|
||||||
|
migrations.RunSQL(
|
||||||
|
sql="ALTER TABLE cookbook_food_properties RENAME TO cookbook_foodproperty",
|
||||||
|
reverse_sql="ALTER TABLE cookbook_foodproperty RENAME TO cookbook_food_properties",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
state_operations=[
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FoodProperty',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('food', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.food')),
|
||||||
|
('property', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.property')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='food',
|
||||||
|
name='properties',
|
||||||
|
field=models.ManyToManyField(blank=True, through='cookbook.FoodProperty', to='cookbook.property'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='foodproperty',
|
||||||
|
constraint=models.UniqueConstraint(fields=('food', 'property'), name='property_unique_food'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='property',
|
||||||
|
name='import_food_id',
|
||||||
|
field=models.IntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='property',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'property_type', 'import_food_id'), name='property_unique_import_food_per_space'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 4.1.9 on 2023-06-20 13:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0191_foodproperty_property_import_food_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='food',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='food_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='propertytype',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='property_type_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='supermarket',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='supermarket_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='supermarketcategory',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='supermarket_category_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='unit',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='unit_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='unitconversion',
|
||||||
|
constraint=models.UniqueConstraint(fields=('space', 'open_data_slug'), name='unit_conversion_unique_open_data_slug_per_space'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
cookbook/migrations/0193_space_internal_note.py
Normal file
18
cookbook/migrations/0193_space_internal_note.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.9 on 2023-06-21 13:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0192_food_food_unique_open_data_slug_per_space_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='space',
|
||||||
|
name='internal_note',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -82,10 +82,13 @@ class TreeManager(MP_NodeManager):
|
|||||||
# model.Manager get_or_create() is not compatible with MP_Tree
|
# model.Manager get_or_create() is not compatible with MP_Tree
|
||||||
def get_or_create(self, *args, **kwargs):
|
def get_or_create(self, *args, **kwargs):
|
||||||
kwargs['name'] = kwargs['name'].strip()
|
kwargs['name'] = kwargs['name'].strip()
|
||||||
|
if hasattr(self, 'space'):
|
||||||
if obj := self.filter(name__iexact=kwargs['name'], space=kwargs['space']).first():
|
if obj := self.filter(name__iexact=kwargs['name'], space=kwargs['space']).first():
|
||||||
return obj, False
|
return obj, False
|
||||||
else:
|
else:
|
||||||
|
if obj := self.filter(name__iexact=kwargs['name']).first():
|
||||||
|
return obj, False
|
||||||
|
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
try:
|
try:
|
||||||
defaults = kwargs.pop('defaults', None)
|
defaults = kwargs.pop('defaults', None)
|
||||||
@@ -267,6 +270,8 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
|
|||||||
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
|
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
|
||||||
show_facet_count = models.BooleanField(default=False)
|
show_facet_count = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
internal_note = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
def safe_delete(self):
|
def safe_delete(self):
|
||||||
"""
|
"""
|
||||||
Safely deletes a space by deleting all objects belonging to the space first and then deleting the space itself
|
Safely deletes a space by deleting all objects belonging to the space first and then deleting the space itself
|
||||||
@@ -454,6 +459,7 @@ class Sync(models.Model, PermissionModelMixin):
|
|||||||
class SupermarketCategory(models.Model, PermissionModelMixin):
|
class SupermarketCategory(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
@@ -463,7 +469,8 @@ class SupermarketCategory(models.Model, PermissionModelMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(fields=['space', 'name'], name='smc_unique_name_per_space')
|
models.UniqueConstraint(fields=['space', 'name'], name='smc_unique_name_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='supermarket_category_unique_open_data_slug_per_space')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -471,6 +478,7 @@ class Supermarket(models.Model, PermissionModelMixin):
|
|||||||
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
categories = models.ManyToManyField(SupermarketCategory, through='SupermarketCategoryRelation')
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
@@ -480,7 +488,8 @@ class Supermarket(models.Model, PermissionModelMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(fields=['space', 'name'], name='sm_unique_name_per_space')
|
models.UniqueConstraint(fields=['space', 'name'], name='sm_unique_name_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='supermarket_unique_open_data_slug_per_space')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -496,6 +505,9 @@ class SupermarketCategoryRelation(models.Model, PermissionModelMixin):
|
|||||||
return 'supermarket', 'space'
|
return 'supermarket', 'space'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(fields=['supermarket', 'category'], name='unique_sm_category_relation')
|
||||||
|
]
|
||||||
ordering = ('order',)
|
ordering = ('order',)
|
||||||
|
|
||||||
|
|
||||||
@@ -534,6 +546,8 @@ class Unit(ExportModelOperationsMixin('unit'), models.Model, PermissionModelMixi
|
|||||||
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
name = models.CharField(max_length=128, validators=[MinLengthValidator(1)])
|
||||||
plural_name = models.CharField(max_length=128, null=True, blank=True, default=None)
|
plural_name = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
|
base_unit = models.TextField(max_length=256, null=True, blank=True, default=None)
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
@@ -543,7 +557,8 @@ class Unit(ExportModelOperationsMixin('unit'), models.Model, PermissionModelMixi
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(fields=['space', 'name'], name='u_unique_name_per_space')
|
models.UniqueConstraint(fields=['space', 'name'], name='u_unique_name_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='unit_unique_open_data_slug_per_space')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -569,6 +584,15 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
substitute_children = models.BooleanField(default=False)
|
substitute_children = models.BooleanField(default=False)
|
||||||
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
|
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
|
||||||
|
|
||||||
|
properties = models.ManyToManyField("Property", blank=True, through='FoodProperty')
|
||||||
|
properties_food_amount = models.IntegerField(default=100, blank=True)
|
||||||
|
properties_food_unit = models.ForeignKey(Unit, on_delete=models.PROTECT, blank=True, null=True)
|
||||||
|
|
||||||
|
preferred_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_unit')
|
||||||
|
preferred_shopping_unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True, default=None, related_name='preferred_shopping_unit')
|
||||||
|
fdc_id = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space', _manager_class=TreeManager)
|
objects = ScopedManager(space='space', _manager_class=TreeManager)
|
||||||
|
|
||||||
@@ -642,7 +666,8 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(fields=['space', 'name'], name='f_unique_name_per_space')
|
models.UniqueConstraint(fields=['space', 'name'], name='f_unique_name_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='food_unique_open_data_slug_per_space')
|
||||||
]
|
]
|
||||||
indexes = (
|
indexes = (
|
||||||
Index(fields=['id']),
|
Index(fields=['id']),
|
||||||
@@ -650,6 +675,32 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversion(ExportModelOperationsMixin('unit_conversion'), models.Model, PermissionModelMixin):
|
||||||
|
base_amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
|
base_unit = models.ForeignKey('Unit', on_delete=models.CASCADE, related_name='unit_conversion_base_relation')
|
||||||
|
converted_amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
|
converted_unit = models.ForeignKey('Unit', on_delete=models.CASCADE, related_name='unit_conversion_converted_relation')
|
||||||
|
|
||||||
|
food = models.ForeignKey('Food', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.base_amount} {self.base_unit} -> {self.converted_amount} {self.converted_unit} {self.food}'
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(fields=['space', 'base_unit', 'converted_unit', 'food'], name='f_unique_conversion_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='unit_conversion_unique_open_data_slug_per_space')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, PermissionModelMixin):
|
class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, PermissionModelMixin):
|
||||||
# delete method on Food and Unit checks if they are part of a Recipe, if it is raises a ProtectedError instead of cascading the delete
|
# delete method on Food and Unit checks if they are part of a Recipe, if it is raises a ProtectedError instead of cascading the delete
|
||||||
food = models.ForeignKey(Food, on_delete=models.CASCADE, null=True, blank=True)
|
food = models.ForeignKey(Food, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
@@ -663,8 +714,6 @@ class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, Permiss
|
|||||||
order = models.IntegerField(default=0)
|
order = models.IntegerField(default=0)
|
||||||
original_text = models.CharField(max_length=512, null=True, blank=True, default=None)
|
original_text = models.CharField(max_length=512, null=True, blank=True, default=None)
|
||||||
|
|
||||||
original_text = models.CharField(max_length=512, null=True, blank=True, default=None)
|
|
||||||
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
objects = ScopedManager(space='space')
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
@@ -720,6 +769,64 @@ class Step(ExportModelOperationsMixin('step'), models.Model, PermissionModelMixi
|
|||||||
indexes = (GinIndex(fields=["search_vector"]),)
|
indexes = (GinIndex(fields=["search_vector"]),)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyType(models.Model, PermissionModelMixin):
|
||||||
|
NUTRITION = 'NUTRITION'
|
||||||
|
ALLERGEN = 'ALLERGEN'
|
||||||
|
PRICE = 'PRICE'
|
||||||
|
GOAL = 'GOAL'
|
||||||
|
OTHER = 'OTHER'
|
||||||
|
|
||||||
|
name = models.CharField(max_length=128)
|
||||||
|
unit = models.CharField(max_length=64, blank=True, null=True)
|
||||||
|
icon = models.CharField(max_length=16, blank=True, null=True)
|
||||||
|
description = models.CharField(max_length=512, blank=True, null=True)
|
||||||
|
category = models.CharField(max_length=64, choices=((NUTRITION, _('Nutrition')), (ALLERGEN, _('Allergen')), (PRICE, _('Price')), (GOAL, _('Goal')), (OTHER, _('Other'))), null=True, blank=True)
|
||||||
|
open_data_slug = models.CharField(max_length=128, null=True, blank=True, default=None)
|
||||||
|
|
||||||
|
# TODO show if empty property?
|
||||||
|
# TODO formatting property?
|
||||||
|
|
||||||
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.name}'
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(fields=['space', 'name'], name='property_type_unique_name_per_space'),
|
||||||
|
models.UniqueConstraint(fields=['space', 'open_data_slug'], name='property_type_unique_open_data_slug_per_space')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Property(models.Model, PermissionModelMixin):
|
||||||
|
property_amount = models.DecimalField(default=0, decimal_places=4, max_digits=32)
|
||||||
|
property_type = models.ForeignKey(PropertyType, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
import_food_id = models.IntegerField(null=True, blank=True) # field to hold food id when importing properties from the open data project
|
||||||
|
|
||||||
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
|
objects = ScopedManager(space='space')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.property_amount} {self.property_type.unit} {self.property_type.name}'
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(fields=['space', 'property_type', 'import_food_id'], name='property_unique_import_food_per_space')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FoodProperty(models.Model):
|
||||||
|
food = models.ForeignKey(Food, on_delete=models.CASCADE)
|
||||||
|
property = models.ForeignKey(Property, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(fields=['food', 'property'], name='property_unique_food')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class NutritionInformation(models.Model, PermissionModelMixin):
|
class NutritionInformation(models.Model, PermissionModelMixin):
|
||||||
fats = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
fats = models.DecimalField(default=0, decimal_places=16, max_digits=32)
|
||||||
carbohydrates = models.DecimalField(
|
carbohydrates = models.DecimalField(
|
||||||
@@ -736,14 +843,6 @@ class NutritionInformation(models.Model, PermissionModelMixin):
|
|||||||
return f'Nutrition {self.pk}'
|
return f'Nutrition {self.pk}'
|
||||||
|
|
||||||
|
|
||||||
# class NutritionType(models.Model, PermissionModelMixin):
|
|
||||||
# name = models.CharField(max_length=128)
|
|
||||||
# icon = models.CharField(max_length=16, blank=True, null=True)
|
|
||||||
# description = models.CharField(max_length=512, blank=True, null=True)
|
|
||||||
#
|
|
||||||
# space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
|
||||||
# objects = ScopedManager(space='space')
|
|
||||||
|
|
||||||
class RecipeManager(models.Manager.from_queryset(models.QuerySet)):
|
class RecipeManager(models.Manager.from_queryset(models.QuerySet)):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super(RecipeManager, self).get_queryset().annotate(rating=Avg('cooklog__rating')).annotate(last_cooked=Max('cooklog__created_at'))
|
return super(RecipeManager, self).get_queryset().annotate(rating=Avg('cooklog__rating')).annotate(last_cooked=Max('cooklog__created_at'))
|
||||||
@@ -766,6 +865,7 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
|
|||||||
waiting_time = models.IntegerField(default=0)
|
waiting_time = models.IntegerField(default=0)
|
||||||
internal = models.BooleanField(default=False)
|
internal = models.BooleanField(default=False)
|
||||||
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
||||||
|
properties = models.ManyToManyField(Property, blank=True)
|
||||||
show_ingredient_overview = models.BooleanField(default=True)
|
show_ingredient_overview = models.BooleanField(default=True)
|
||||||
private = models.BooleanField(default=False)
|
private = models.BooleanField(default=False)
|
||||||
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from html import escape
|
|||||||
from smtplib import SMTPException
|
from smtplib import SMTPException
|
||||||
|
|
||||||
from django.contrib.auth.models import Group, User, AnonymousUser
|
from django.contrib.auth.models import Group, User, AnonymousUser
|
||||||
|
from django.core.cache import caches
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.db.models import Avg, Q, QuerySet, Sum
|
from django.db.models import Avg, Q, QuerySet, Sum
|
||||||
from django.http import BadHeaderError
|
from django.http import BadHeaderError
|
||||||
@@ -21,15 +22,18 @@ from rest_framework.exceptions import NotFound, ValidationError
|
|||||||
|
|
||||||
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
|
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
|
||||||
from cookbook.helper.HelperFunctions import str2bool
|
from cookbook.helper.HelperFunctions import str2bool
|
||||||
|
from cookbook.helper.property_helper import FoodPropertyHelper
|
||||||
from cookbook.helper.permission_helper import above_space_limit
|
from cookbook.helper.permission_helper import above_space_limit
|
||||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
||||||
|
from cookbook.helper.unit_conversion_helper import UnitConversionHelper
|
||||||
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter,
|
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter,
|
||||||
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, InviteLink,
|
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, InviteLink,
|
||||||
Keyword, MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
|
Keyword, MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
|
||||||
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
||||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
|
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, Property,
|
||||||
|
PropertyType, Property)
|
||||||
from cookbook.templatetags.custom_tags import markdown
|
from cookbook.templatetags.custom_tags import markdown
|
||||||
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
||||||
|
|
||||||
@@ -102,15 +106,21 @@ class CustomOnHandField(serializers.Field):
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
shared_users = None
|
if not self.context["request"].user.is_authenticated:
|
||||||
if request := self.context.get('request', None):
|
return []
|
||||||
shared_users = getattr(request, '_shared_users', None)
|
shared_users = []
|
||||||
if shared_users is None:
|
if c := caches['default'].get(f'shopping_shared_users_{self.context["request"].space.id}_{self.context["request"].user.id}', None):
|
||||||
|
shared_users = c
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
|
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
|
||||||
self.context['request'].user.id]
|
self.context['request'].user.id]
|
||||||
|
caches['default'].set(
|
||||||
|
f'shopping_shared_users_{self.context["request"].space.id}_{self.context["request"].user.id}',
|
||||||
|
shared_users, timeout=5 * 60)
|
||||||
|
# TODO ugly hack that improves API performance significantly, should be done properly
|
||||||
except AttributeError: # Anonymous users (using share links) don't have shared users
|
except AttributeError: # Anonymous users (using share links) don't have shared users
|
||||||
shared_users = []
|
pass
|
||||||
return obj.onhand_users.filter(id__in=shared_users).exists()
|
return obj.onhand_users.filter(id__in=shared_users).exists()
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
@@ -276,10 +286,13 @@ class SpaceSerializer(WritableNestedModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Space
|
model = Space
|
||||||
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
|
fields = (
|
||||||
|
'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
|
||||||
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb',
|
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb',
|
||||||
'image', 'use_plural',)
|
'image', 'use_plural',)
|
||||||
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
|
read_only_fields = (
|
||||||
|
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
|
||||||
|
'demo',)
|
||||||
|
|
||||||
|
|
||||||
class UserSpaceSerializer(WritableNestedModelSerializer):
|
class UserSpaceSerializer(WritableNestedModelSerializer):
|
||||||
@@ -440,7 +453,8 @@ class UnitSerializer(UniqueFieldsMixin, ExtendedRecipeMixin):
|
|||||||
return unit
|
return unit
|
||||||
|
|
||||||
space = validated_data.pop('space', self.context['request'].space)
|
space = validated_data.pop('space', self.context['request'].space)
|
||||||
obj, created = Unit.objects.get_or_create(name=name, plural_name=plural_name, space=space, defaults=validated_data)
|
obj, created = Unit.objects.get_or_create(name=name, plural_name=plural_name, space=space,
|
||||||
|
defaults=validated_data)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
@@ -451,7 +465,7 @@ class UnitSerializer(UniqueFieldsMixin, ExtendedRecipeMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Unit
|
model = Unit
|
||||||
fields = ('id', 'name', 'plural_name', 'description', 'numrecipe', 'image')
|
fields = ('id', 'name', 'plural_name', 'description', 'numrecipe', 'image', 'open_data_slug')
|
||||||
read_only_fields = ('id', 'numrecipe', 'image')
|
read_only_fields = ('id', 'numrecipe', 'image')
|
||||||
|
|
||||||
|
|
||||||
@@ -484,7 +498,37 @@ class SupermarketSerializer(UniqueFieldsMixin, SpacedModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Supermarket
|
model = Supermarket
|
||||||
fields = ('id', 'name', 'description', 'category_to_supermarket')
|
fields = ('id', 'name', 'description', 'category_to_supermarket', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTypeSerializer(serializers.ModelSerializer):
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
|
|
||||||
|
if property_type := PropertyType.objects.filter(Q(name=validated_data['name'])).first():
|
||||||
|
return property_type
|
||||||
|
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PropertyType
|
||||||
|
fields = ('id', 'name', 'icon', 'unit', 'description', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
|
class PropertySerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
||||||
|
property_type = PropertyTypeSerializer()
|
||||||
|
property_amount = CustomDecimalField()
|
||||||
|
|
||||||
|
# TODO prevent updates
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Property
|
||||||
|
fields = ('id', 'property_amount', 'property_type')
|
||||||
|
read_only_fields = ('id',)
|
||||||
|
|
||||||
|
|
||||||
class RecipeSimpleSerializer(WritableNestedModelSerializer):
|
class RecipeSimpleSerializer(WritableNestedModelSerializer):
|
||||||
@@ -523,19 +567,29 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
substitute_onhand = serializers.SerializerMethodField('get_substitute_onhand')
|
substitute_onhand = serializers.SerializerMethodField('get_substitute_onhand')
|
||||||
substitute = FoodSimpleSerializer(many=True, allow_null=True, required=False)
|
substitute = FoodSimpleSerializer(many=True, allow_null=True, required=False)
|
||||||
|
|
||||||
|
properties = PropertySerializer(many=True, allow_null=True, required=False)
|
||||||
|
properties_food_unit = UnitSerializer(allow_null=True, required=False)
|
||||||
|
|
||||||
recipe_filter = 'steps__ingredients__food'
|
recipe_filter = 'steps__ingredients__food'
|
||||||
images = ['recipe__image']
|
images = ['recipe__image']
|
||||||
|
|
||||||
def get_substitute_onhand(self, obj):
|
def get_substitute_onhand(self, obj):
|
||||||
shared_users = None
|
if not self.context["request"].user.is_authenticated:
|
||||||
if request := self.context.get('request', None):
|
return []
|
||||||
shared_users = getattr(request, '_shared_users', None)
|
shared_users = []
|
||||||
if shared_users is None:
|
if c := caches['default'].get(
|
||||||
|
f'shopping_shared_users_{self.context["request"].space.id}_{self.context["request"].user.id}', None):
|
||||||
|
shared_users = c
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
|
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
|
||||||
self.context['request'].user.id]
|
self.context['request'].user.id]
|
||||||
except AttributeError:
|
caches['default'].set(
|
||||||
shared_users = []
|
f'shopping_shared_users_{self.context["request"].space.id}_{self.context["request"].user.id}',
|
||||||
|
shared_users, timeout=5 * 60)
|
||||||
|
# TODO ugly hack that improves API performance significantly, should be done properly
|
||||||
|
except AttributeError: # Anonymous users (using share links) don't have shared users
|
||||||
|
pass
|
||||||
filter = Q(id__in=obj.substitute.all())
|
filter = Q(id__in=obj.substitute.all())
|
||||||
if obj.substitute_siblings:
|
if obj.substitute_siblings:
|
||||||
filter |= Q(path__startswith=obj.path[:Food.steplen * (obj.depth - 1)], depth=obj.depth)
|
filter |= Q(path__startswith=obj.path[:Food.steplen * (obj.depth - 1)], depth=obj.depth)
|
||||||
@@ -547,7 +601,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
# return ShoppingListEntry.objects.filter(space=obj.space, food=obj, checked=False).count() > 0
|
# return ShoppingListEntry.objects.filter(space=obj.space, food=obj, checked=False).count() > 0
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
name = validated_data.pop('name').strip()
|
name = validated_data['name'].strip()
|
||||||
|
|
||||||
if plural_name := validated_data.pop('plural_name', None):
|
if plural_name := validated_data.pop('plural_name', None):
|
||||||
plural_name = plural_name.strip()
|
plural_name = plural_name.strip()
|
||||||
@@ -579,7 +633,11 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
else:
|
else:
|
||||||
validated_data['onhand_users'] = list(set(onhand_users) - set(shared_users))
|
validated_data['onhand_users'] = list(set(onhand_users) - set(shared_users))
|
||||||
|
|
||||||
obj, created = Food.objects.get_or_create(name=name, plural_name=plural_name, space=space, defaults=validated_data)
|
if properties_food_unit := validated_data.pop('properties_food_unit', None):
|
||||||
|
properties_food_unit = Unit.objects.filter(name=properties_food_unit['name']).first()
|
||||||
|
|
||||||
|
obj, created = Food.objects.get_or_create(name=name, plural_name=plural_name, space=space, properties_food_unit=properties_food_unit,
|
||||||
|
defaults=validated_data)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
@@ -606,9 +664,11 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Food
|
model = Food
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'name', 'plural_name', 'description', 'shopping', 'recipe', 'food_onhand', 'supermarket_category',
|
'id', 'name', 'plural_name', 'description', 'shopping', 'recipe',
|
||||||
|
'properties', 'properties_food_amount', 'properties_food_unit',
|
||||||
|
'food_onhand', 'supermarket_category',
|
||||||
'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping',
|
'image', 'parent', 'numchild', 'numrecipe', 'inherit_fields', 'full_name', 'ignore_shopping',
|
||||||
'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand', 'child_inherit_fields'
|
'substitute', 'substitute_siblings', 'substitute_children', 'substitute_onhand', 'child_inherit_fields', 'open_data_slug',
|
||||||
)
|
)
|
||||||
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
|
||||||
|
|
||||||
@@ -618,9 +678,24 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
|
|||||||
unit = UnitSerializer(allow_null=True)
|
unit = UnitSerializer(allow_null=True)
|
||||||
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
|
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
|
||||||
amount = CustomDecimalField()
|
amount = CustomDecimalField()
|
||||||
|
conversions = serializers.SerializerMethodField('get_conversions')
|
||||||
|
|
||||||
def get_used_in_recipes(self, obj):
|
def get_used_in_recipes(self, obj):
|
||||||
return list(Recipe.objects.filter(steps__ingredients=obj.id).values('id', 'name'))
|
used_in = []
|
||||||
|
for s in obj.step_set.all():
|
||||||
|
for r in s.recipe_set.all():
|
||||||
|
used_in.append({'id': r.id, 'name': r.name})
|
||||||
|
return used_in
|
||||||
|
|
||||||
|
def get_conversions(self, obj):
|
||||||
|
if obj.unit and obj.food:
|
||||||
|
uch = UnitConversionHelper(self.context['request'].space)
|
||||||
|
conversions = []
|
||||||
|
for c in uch.get_conversions(obj):
|
||||||
|
conversions.append({'food': c.food.name, 'unit': c.unit.name, 'amount': c.amount}) # TODO do formatting in helper
|
||||||
|
return conversions
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['space'] = self.context['request'].space
|
validated_data['space'] = self.context['request'].space
|
||||||
@@ -633,10 +708,11 @@ class IngredientSimpleSerializer(WritableNestedModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Ingredient
|
model = Ingredient
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'food', 'unit', 'amount', 'note', 'order',
|
'id', 'food', 'unit', 'amount', 'conversions', 'note', 'order',
|
||||||
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
|
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
|
||||||
'always_use_plural_unit', 'always_use_plural_food',
|
'always_use_plural_unit', 'always_use_plural_food',
|
||||||
)
|
)
|
||||||
|
read_only_fields = ['conversions', ]
|
||||||
|
|
||||||
|
|
||||||
class IngredientSerializer(IngredientSimpleSerializer):
|
class IngredientSerializer(IngredientSimpleSerializer):
|
||||||
@@ -688,6 +764,30 @@ class StepRecipeSerializer(WritableNestedModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversionSerializer(WritableNestedModelSerializer):
|
||||||
|
name = serializers.SerializerMethodField('get_conversion_name')
|
||||||
|
base_unit = UnitSerializer()
|
||||||
|
converted_unit = UnitSerializer()
|
||||||
|
food = FoodSerializer(allow_null=True, required=False)
|
||||||
|
base_amount = CustomDecimalField()
|
||||||
|
converted_amount = CustomDecimalField()
|
||||||
|
|
||||||
|
def get_conversion_name(self, obj):
|
||||||
|
text = f'{round(obj.base_amount)} {obj.base_unit} '
|
||||||
|
if obj.food:
|
||||||
|
text += f' {obj.food}'
|
||||||
|
return text + f' = {round(obj.converted_amount)} {obj.converted_unit}'
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['space'] = self.context['request'].space
|
||||||
|
validated_data['created_by'] = self.context['request'].user
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = UnitConversion
|
||||||
|
fields = ('id', 'name', 'base_amount', 'base_unit', 'converted_amount', 'converted_unit', 'food', 'open_data_slug')
|
||||||
|
|
||||||
|
|
||||||
class NutritionInformationSerializer(serializers.ModelSerializer):
|
class NutritionInformationSerializer(serializers.ModelSerializer):
|
||||||
carbohydrates = CustomDecimalField()
|
carbohydrates = CustomDecimalField()
|
||||||
fats = CustomDecimalField()
|
fats = CustomDecimalField()
|
||||||
@@ -738,21 +838,28 @@ class RecipeOverviewSerializer(RecipeBaseSerializer):
|
|||||||
|
|
||||||
class RecipeSerializer(RecipeBaseSerializer):
|
class RecipeSerializer(RecipeBaseSerializer):
|
||||||
nutrition = NutritionInformationSerializer(allow_null=True, required=False)
|
nutrition = NutritionInformationSerializer(allow_null=True, required=False)
|
||||||
|
properties = PropertySerializer(many=True, required=False)
|
||||||
steps = StepSerializer(many=True)
|
steps = StepSerializer(many=True)
|
||||||
keywords = KeywordSerializer(many=True)
|
keywords = KeywordSerializer(many=True)
|
||||||
shared = UserSerializer(many=True, required=False)
|
shared = UserSerializer(many=True, required=False)
|
||||||
rating = CustomDecimalField(required=False, allow_null=True, read_only=True)
|
rating = CustomDecimalField(required=False, allow_null=True, read_only=True)
|
||||||
last_cooked = serializers.DateTimeField(required=False, allow_null=True, read_only=True)
|
last_cooked = serializers.DateTimeField(required=False, allow_null=True, read_only=True)
|
||||||
|
food_properties = serializers.SerializerMethodField('get_food_properties')
|
||||||
|
|
||||||
|
def get_food_properties(self, obj):
|
||||||
|
fph = FoodPropertyHelper(obj.space) # initialize with object space since recipes might be viewed anonymously
|
||||||
|
return fph.calculate_recipe_properties(obj)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Recipe
|
model = Recipe
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'name', 'description', 'image', 'keywords', 'steps', 'working_time',
|
'id', 'name', 'description', 'image', 'keywords', 'steps', 'working_time',
|
||||||
'waiting_time', 'created_by', 'created_at', 'updated_at', 'source_url',
|
'waiting_time', 'created_by', 'created_at', 'updated_at', 'source_url',
|
||||||
'internal', 'show_ingredient_overview', 'nutrition', 'servings', 'file_path', 'servings_text', 'rating', 'last_cooked',
|
'internal', 'show_ingredient_overview', 'nutrition', 'properties', 'food_properties', 'servings', 'file_path', 'servings_text', 'rating',
|
||||||
|
'last_cooked',
|
||||||
'private', 'shared',
|
'private', 'shared',
|
||||||
)
|
)
|
||||||
read_only_fields = ['image', 'created_by', 'created_at']
|
read_only_fields = ['image', 'created_by', 'created_at', 'food_properties']
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
above_limit, msg = above_space_limit(self.context['request'].space)
|
above_limit, msg = above_space_limit(self.context['request'].space)
|
||||||
@@ -1089,13 +1196,19 @@ class InviteLinkSerializer(WritableNestedModelSerializer):
|
|||||||
|
|
||||||
if obj.email:
|
if obj.email:
|
||||||
try:
|
try:
|
||||||
if InviteLink.objects.filter(space=self.context['request'].space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
|
if InviteLink.objects.filter(space=self.context['request'].space,
|
||||||
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.context['request'].user.get_user_display_name())
|
created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
|
||||||
message += _(' to join their Tandoor Recipes space ') + escape(self.context['request'].space.name) + '.\n\n'
|
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(
|
||||||
message += _('Click the following link to activate your account: ') + self.context['request'].build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n'
|
self.context['request'].user.get_user_display_name())
|
||||||
message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n'
|
message += _(' to join their Tandoor Recipes space ') + escape(
|
||||||
|
self.context['request'].space.name) + '.\n\n'
|
||||||
|
message += _('Click the following link to activate your account: ') + self.context[
|
||||||
|
'request'].build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n'
|
||||||
|
message += _('If the link does not work use the following code to manually join the space: ') + str(
|
||||||
|
obj.uuid) + '\n\n'
|
||||||
message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n'
|
message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n'
|
||||||
message += _('Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/'
|
message += _(
|
||||||
|
'Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/'
|
||||||
|
|
||||||
send_mail(
|
send_mail(
|
||||||
_('Tandoor Recipes Invite'),
|
_('Tandoor Recipes Invite'),
|
||||||
@@ -1204,7 +1317,8 @@ class IngredientExportSerializer(WritableNestedModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Ingredient
|
model = Ingredient
|
||||||
fields = ('food', 'unit', 'amount', 'note', 'order', 'is_header', 'no_amount', 'always_use_plural_unit', 'always_use_plural_food')
|
fields = ('food', 'unit', 'amount', 'note', 'order', 'is_header', 'no_amount', 'always_use_plural_unit',
|
||||||
|
'always_use_plural_food')
|
||||||
|
|
||||||
|
|
||||||
class StepExportSerializer(WritableNestedModelSerializer):
|
class StepExportSerializer(WritableNestedModelSerializer):
|
||||||
|
|||||||
@@ -4,15 +4,17 @@ from functools import wraps
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.postgres.search import SearchVector
|
from django.contrib.postgres.search import SearchVector
|
||||||
|
from django.core.cache import caches
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django_scopes import scope, scopes_disabled
|
from django_scopes import scope, scopes_disabled
|
||||||
|
|
||||||
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
||||||
from cookbook.managers import DICTIONARY
|
from cookbook.managers import DICTIONARY
|
||||||
from cookbook.models import (Food, FoodInheritField, Ingredient, MealPlan, Recipe,
|
from cookbook.models import (Food, FoodInheritField, Ingredient, MealPlan, Recipe,
|
||||||
ShoppingListEntry, Step, UserPreference, SearchPreference, SearchFields)
|
ShoppingListEntry, Step, UserPreference, SearchPreference, SearchFields, Unit, PropertyType)
|
||||||
|
|
||||||
SQLITE = True
|
SQLITE = True
|
||||||
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||||
@@ -149,3 +151,15 @@ def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs
|
|||||||
print("MEAL_AUTO_ADD Created SLR")
|
print("MEAL_AUTO_ADD Created SLR")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Unit)
|
||||||
|
def clear_unit_cache(sender, instance=None, created=False, **kwargs):
|
||||||
|
if instance:
|
||||||
|
caches['default'].delete(CacheHelper(instance.space).BASE_UNITS_CACHE_KEY)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=PropertyType)
|
||||||
|
def clear_property_type_cache(sender, instance=None, created=False, **kwargs):
|
||||||
|
if instance:
|
||||||
|
caches['default'].delete(CacheHelper(instance.space).PROPERTY_TYPE_CACHE_KEY)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
{% endblock %}</title>
|
{% endblock %}</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta name="robots" content="noindex,nofollow"/>
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="{% static 'assets/favicon.svg' %}">
|
<link rel="shortcut icon" type="image/x-icon" href="{% static 'assets/favicon.svg' %}">
|
||||||
@@ -117,6 +118,10 @@
|
|||||||
<a class="nav-link" href="{% url 'view_books' %}"><i
|
<a class="nav-link" href="{% url 'view_books' %}"><i
|
||||||
class="fas fa-fw fa-book-open"></i> {% trans 'Books' %}</a>
|
class="fas fa-fw fa-book-open"></i> {% trans 'Books' %}</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% plugin_main_nav_templates as plugin_main_nav_templates %}
|
||||||
|
{% for pn in plugin_main_nav_templates %}
|
||||||
|
{% include pn %}
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
@@ -269,6 +274,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<a href="{% url 'list_property_type' %}" class="p-0 p-md-1">
|
||||||
|
<div class="card p-0 no-gutters border-0">
|
||||||
|
<div class="card-body text-center p-0 no-gutters">
|
||||||
|
<i class="fas fa-database fa-2x"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||||
|
{% trans 'Properties' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row m-0 mt-2 mt-md-0">
|
||||||
|
<div class="col-4">
|
||||||
|
<a href="{% url 'list_unit_conversion' %}" class="p-0 p-md-1">
|
||||||
|
<div class="card p-0 no-gutters border-0">
|
||||||
|
<div class="card-body text-center p-0 no-gutters">
|
||||||
|
<i class="fas fa-exchange-alt fa-2x"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||||
|
{% trans 'Unit Conversions' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -322,6 +354,12 @@
|
|||||||
<a class="dropdown-item" href="{% url 'view_space_overview' %}"><i
|
<a class="dropdown-item" href="{% url 'view_space_overview' %}"><i
|
||||||
class="fas fa-list"></i> {% trans 'Overview' %}</a>
|
class="fas fa-list"></i> {% trans 'Overview' %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% plugin_dropdown_nav_templates as plugin_dropdown_nav_templates %}
|
||||||
|
{% for pn in plugin_dropdown_nav_templates %}
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
{% include pn %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item" href="{% url 'docs_markdown' %}"><i
|
<a class="dropdown-item" href="{% url 'docs_markdown' %}"><i
|
||||||
class="fab fa-markdown fa-fw"></i> {% trans 'Markdown Guide' %}</a>
|
class="fab fa-markdown fa-fw"></i> {% trans 'Markdown Guide' %}</a>
|
||||||
@@ -348,6 +386,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
{% message_of_the_day request as message_of_the_day %}
|
{% message_of_the_day request as message_of_the_day %}
|
||||||
{% if message_of_the_day %}
|
{% if message_of_the_day %}
|
||||||
<div class="bg-info" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
|
<div class="bg-info" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from cookbook.helper.mdx_attributes import MarkdownFormatExtension
|
|||||||
from cookbook.helper.mdx_urlize import UrlizeExtension
|
from cookbook.helper.mdx_urlize import UrlizeExtension
|
||||||
from cookbook.models import Space, get_model_name
|
from cookbook.models import Space, get_model_name
|
||||||
from recipes import settings
|
from recipes import settings
|
||||||
from recipes.settings import STATIC_URL
|
from recipes.settings import STATIC_URL, PLUGINS
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@@ -132,6 +132,22 @@ def is_debug():
|
|||||||
def markdown_link():
|
def markdown_link():
|
||||||
return f"{_('You can use markdown to format this field. See the ')}<a target='_blank' href='{reverse('docs_markdown')}'>{_('docs here')}</a>"
|
return f"{_('You can use markdown to format this field. See the ')}<a target='_blank' href='{reverse('docs_markdown')}'>{_('docs here')}</a>"
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def plugin_dropdown_nav_templates():
|
||||||
|
templates = []
|
||||||
|
for p in PLUGINS:
|
||||||
|
if p['nav_dropdown']:
|
||||||
|
templates.append(p['nav_dropdown'])
|
||||||
|
return templates
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def plugin_main_nav_templates():
|
||||||
|
templates = []
|
||||||
|
for p in PLUGINS:
|
||||||
|
if p['nav_main']:
|
||||||
|
templates.append(p['nav_main'])
|
||||||
|
return templates
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def bookmarklet(request):
|
def bookmarklet(request):
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import json
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
|
from django.core.cache import caches
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django_scopes import scope, scopes_disabled
|
from django_scopes import scope, scopes_disabled
|
||||||
from pytest_factoryboy import LazyFixture, register
|
from pytest_factoryboy import LazyFixture, register
|
||||||
@@ -28,7 +29,6 @@ if (Food.node_order_by):
|
|||||||
else:
|
else:
|
||||||
node_location = 'last-child'
|
node_location = 'last-child'
|
||||||
|
|
||||||
|
|
||||||
register(FoodFactory, 'obj_1', space=LazyFixture('space_1'))
|
register(FoodFactory, 'obj_1', space=LazyFixture('space_1'))
|
||||||
register(FoodFactory, 'obj_2', space=LazyFixture('space_1'))
|
register(FoodFactory, 'obj_2', space=LazyFixture('space_1'))
|
||||||
register(FoodFactory, 'obj_3', space=LazyFixture('space_2'))
|
register(FoodFactory, 'obj_3', space=LazyFixture('space_2'))
|
||||||
@@ -554,6 +554,7 @@ def test_inherit(request, obj_tree_1, field, inherit, new_val, u1_s1):
|
|||||||
assert (getattr(obj_tree_1, field) == new_val) == inherit
|
assert (getattr(obj_tree_1, field) == new_val) == inherit
|
||||||
assert (getattr(child, field) == new_val) == inherit
|
assert (getattr(child, field) == new_val) == inherit
|
||||||
|
|
||||||
|
|
||||||
# TODO add test_inherit with child_inherit
|
# TODO add test_inherit with child_inherit
|
||||||
|
|
||||||
|
|
||||||
@@ -613,11 +614,9 @@ def test_reset_inherit_no_food_instances(obj_tree_1, space_1, field):
|
|||||||
parent.reset_inheritance(space=space_1)
|
parent.reset_inheritance(space=space_1)
|
||||||
|
|
||||||
|
|
||||||
def test_onhand(obj_1, u1_s1, u2_s1):
|
def test_onhand(obj_1, u1_s1, u2_s1, space_1):
|
||||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] is False
|
||||||
'food_onhand'] == False
|
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] is False
|
||||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
|
||||||
'food_onhand'] == False
|
|
||||||
|
|
||||||
u1_s1.patch(
|
u1_s1.patch(
|
||||||
reverse(
|
reverse(
|
||||||
@@ -627,13 +626,12 @@ def test_onhand(obj_1, u1_s1, u2_s1):
|
|||||||
{'food_onhand': True},
|
{'food_onhand': True},
|
||||||
content_type='application/json'
|
content_type='application/json'
|
||||||
)
|
)
|
||||||
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
assert json.loads(u1_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] is True
|
||||||
'food_onhand'] == True
|
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] is False
|
||||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
|
||||||
'food_onhand'] == False
|
|
||||||
|
|
||||||
user1 = auth.get_user(u1_s1)
|
user1 = auth.get_user(u1_s1)
|
||||||
user2 = auth.get_user(u2_s1)
|
user2 = auth.get_user(u2_s1)
|
||||||
user1.userpreference.shopping_share.add(user2)
|
user1.userpreference.shopping_share.add(user2)
|
||||||
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)[
|
caches['default'].set(f'shopping_shared_users_{space_1.id}_{user2.id}', None)
|
||||||
'food_onhand'] == True
|
|
||||||
|
assert json.loads(u2_s1.get(reverse(DETAIL_URL, args={obj_1.id})).content)['food_onhand'] is True
|
||||||
|
|||||||
116
cookbook/tests/api/test_api_property.py
Normal file
116
cookbook/tests/api/test_api_property.py
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.contrib import auth
|
||||||
|
from django.urls import reverse
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
from cookbook.models import Food, MealType, PropertyType, Property
|
||||||
|
|
||||||
|
LIST_URL = 'api:property-list'
|
||||||
|
DETAIL_URL = 'api:property-detail'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def obj_1(space_1, u1_s1):
|
||||||
|
pt = PropertyType.objects.get_or_create(name='test_1', space=space_1)[0]
|
||||||
|
return Property.objects.get_or_create(property_amount=100, property_type=pt, space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def obj_2(space_1, u1_s1):
|
||||||
|
pt = PropertyType.objects.get_or_create(name='test_2', space=space_1)[0]
|
||||||
|
return Property.objects.get_or_create(property_amount=100, property_type=pt, space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
])
|
||||||
|
def test_list_permission(arg, request):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
assert c.get(reverse(LIST_URL)).status_code == arg[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2):
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
|
||||||
|
|
||||||
|
obj_1.space = space_2
|
||||||
|
obj_1.save()
|
||||||
|
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
['g1_s2', 403],
|
||||||
|
['u1_s2', 404],
|
||||||
|
['a1_s2', 404],
|
||||||
|
])
|
||||||
|
def test_update(arg, request, obj_1):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
r = c.patch(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
),
|
||||||
|
{'property_amount': 200},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 200:
|
||||||
|
assert response['property_amount'] == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 201],
|
||||||
|
['a1_s1', 201],
|
||||||
|
])
|
||||||
|
def test_add(arg, request, u1_s2, space_1):
|
||||||
|
with scopes_disabled():
|
||||||
|
pt = PropertyType.objects.get_or_create(name='test_1', space=space_1)[0]
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
r = c.post(
|
||||||
|
reverse(LIST_URL),
|
||||||
|
{'property_amount': 100, 'property_type': {'id': pt.id, 'name': pt.name}},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 201:
|
||||||
|
assert response['property_amount'] == 100
|
||||||
|
r = c.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 200
|
||||||
|
r = u1_s2.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete(u1_s1, u1_s2, obj_1):
|
||||||
|
r = u1_s2.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
r = u1_s1.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert r.status_code == 204
|
||||||
|
with scopes_disabled():
|
||||||
|
assert MealType.objects.count() == 0
|
||||||
132
cookbook/tests/api/test_api_property_type.py
Normal file
132
cookbook/tests/api/test_api_property_type.py
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.contrib import auth
|
||||||
|
from django.urls import reverse
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
from cookbook.models import Food, MealType, PropertyType
|
||||||
|
|
||||||
|
LIST_URL = 'api:propertytype-list'
|
||||||
|
DETAIL_URL = 'api:propertytype-detail'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def obj_1(space_1, u1_s1):
|
||||||
|
return PropertyType.objects.get_or_create(name='test_1', space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def obj_2(space_1, u1_s1):
|
||||||
|
return PropertyType.objects.get_or_create(name='test_2', space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
])
|
||||||
|
def test_list_permission(arg, request):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
assert c.get(reverse(LIST_URL)).status_code == arg[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2):
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
|
||||||
|
|
||||||
|
obj_1.space = space_2
|
||||||
|
obj_1.save()
|
||||||
|
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
['g1_s2', 403],
|
||||||
|
['u1_s2', 404],
|
||||||
|
['a1_s2', 404],
|
||||||
|
])
|
||||||
|
def test_update(arg, request, obj_1):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
r = c.patch(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
),
|
||||||
|
{'name': 'new'},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 200:
|
||||||
|
assert response['name'] == 'new'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 201],
|
||||||
|
['a1_s1', 201],
|
||||||
|
])
|
||||||
|
def test_add(arg, request, u1_s2):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
r = c.post(
|
||||||
|
reverse(LIST_URL),
|
||||||
|
{'name': 'test'},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 201:
|
||||||
|
assert response['name'] == 'test'
|
||||||
|
r = c.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 200
|
||||||
|
r = u1_s2.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_duplicate(u1_s1, u1_s2, obj_1):
|
||||||
|
r = u1_s1.post(
|
||||||
|
reverse(LIST_URL),
|
||||||
|
{'name': obj_1.name},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == 201
|
||||||
|
assert response['id'] == obj_1.id
|
||||||
|
|
||||||
|
r = u1_s2.post(
|
||||||
|
reverse(LIST_URL),
|
||||||
|
{'name': obj_1.name},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == 201
|
||||||
|
assert response['id'] != obj_1.id
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete(u1_s1, u1_s2, obj_1):
|
||||||
|
r = u1_s2.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
r = u1_s1.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert r.status_code == 204
|
||||||
|
with scopes_disabled():
|
||||||
|
assert MealType.objects.count() == 0
|
||||||
163
cookbook/tests/api/test_api_unit_conversion.py
Normal file
163
cookbook/tests/api/test_api_unit_conversion.py
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.contrib import auth
|
||||||
|
from django.urls import reverse
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
from cookbook.models import Food, MealType, UnitConversion
|
||||||
|
from cookbook.tests.conftest import get_random_food, get_random_unit
|
||||||
|
|
||||||
|
LIST_URL = 'api:unitconversion-list'
|
||||||
|
DETAIL_URL = 'api:unitconversion-detail'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def obj_1(space_1, u1_s1):
|
||||||
|
return UnitConversion.objects.get_or_create(
|
||||||
|
food=get_random_food(space_1, u1_s1),
|
||||||
|
base_amount=100,
|
||||||
|
base_unit=get_random_unit(space_1, u1_s1),
|
||||||
|
converted_amount=100,
|
||||||
|
converted_unit=get_random_unit(space_1, u1_s1),
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
space=space_1
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def obj_2(space_1, u1_s1):
|
||||||
|
return UnitConversion.objects.get_or_create(
|
||||||
|
food=get_random_food(space_1, u1_s1),
|
||||||
|
base_amount=100,
|
||||||
|
base_unit=get_random_unit(space_1, u1_s1),
|
||||||
|
converted_amount=100,
|
||||||
|
converted_unit=get_random_unit(space_1, u1_s1),
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
space=space_1
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
])
|
||||||
|
def test_list_permission(arg, request):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
assert c.get(reverse(LIST_URL)).status_code == arg[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2):
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
|
||||||
|
|
||||||
|
obj_1.space = space_2
|
||||||
|
obj_1.save()
|
||||||
|
|
||||||
|
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 200],
|
||||||
|
['a1_s1', 200],
|
||||||
|
['g1_s2', 403],
|
||||||
|
['u1_s2', 404],
|
||||||
|
['a1_s2', 404],
|
||||||
|
])
|
||||||
|
def test_update(arg, request, obj_1):
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
r = c.patch(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
),
|
||||||
|
{'base_amount': 1000},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = json.loads(r.content)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 200:
|
||||||
|
assert response['base_amount'] == 1000
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("arg", [
|
||||||
|
['a_u', 403],
|
||||||
|
['g1_s1', 403],
|
||||||
|
['u1_s1', 201],
|
||||||
|
['a1_s1', 201],
|
||||||
|
])
|
||||||
|
def test_add(arg, request, u1_s2, space_1, u1_s1):
|
||||||
|
with scopes_disabled():
|
||||||
|
c = request.getfixturevalue(arg[0])
|
||||||
|
random_unit_1 = get_random_unit(space_1, u1_s1)
|
||||||
|
random_unit_2 = get_random_unit(space_1, u1_s1)
|
||||||
|
random_food_1 = get_random_unit(space_1, u1_s1)
|
||||||
|
r = c.post(
|
||||||
|
reverse(LIST_URL),
|
||||||
|
{
|
||||||
|
'food': {'id': random_food_1.id, 'name': random_food_1.name},
|
||||||
|
'base_amount': 100,
|
||||||
|
'base_unit': {'id': random_unit_1.id, 'name': random_unit_1.name},
|
||||||
|
'converted_amount': 100,
|
||||||
|
'converted_unit': {'id': random_unit_2.id, 'name': random_unit_2.name}
|
||||||
|
|
||||||
|
},
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
|
||||||
|
response = json.loads(r.content)
|
||||||
|
print(response)
|
||||||
|
assert r.status_code == arg[1]
|
||||||
|
if r.status_code == 201:
|
||||||
|
assert response['base_amount'] == 100
|
||||||
|
r = c.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 200
|
||||||
|
r = u1_s2.get(reverse(DETAIL_URL, args={response['id']}))
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
# TODO make name in space unique
|
||||||
|
# def test_add_duplicate(u1_s1, u1_s2, obj_1):
|
||||||
|
# r = u1_s1.post(
|
||||||
|
# reverse(LIST_URL),
|
||||||
|
# {'name': obj_1.name},
|
||||||
|
# content_type='application/json'
|
||||||
|
# )
|
||||||
|
# response = json.loads(r.content)
|
||||||
|
# assert r.status_code == 201
|
||||||
|
# assert response['id'] == obj_1.id
|
||||||
|
#
|
||||||
|
# r = u1_s2.post(
|
||||||
|
# reverse(LIST_URL),
|
||||||
|
# {'name': obj_1.name},
|
||||||
|
# content_type='application/json'
|
||||||
|
# )
|
||||||
|
# response = json.loads(r.content)
|
||||||
|
# assert r.status_code == 201
|
||||||
|
# assert response['id'] != obj_1.id
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete(u1_s1, u1_s2, obj_1):
|
||||||
|
r = u1_s2.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
r = u1_s1.delete(
|
||||||
|
reverse(
|
||||||
|
DETAIL_URL,
|
||||||
|
args={obj_1.id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert r.status_code == 204
|
||||||
|
with scopes_disabled():
|
||||||
|
assert MealType.objects.count() == 0
|
||||||
@@ -13,6 +13,8 @@ from cookbook.tests.factories import SpaceFactory, UserFactory
|
|||||||
|
|
||||||
register(SpaceFactory, 'space_1')
|
register(SpaceFactory, 'space_1')
|
||||||
register(SpaceFactory, 'space_2')
|
register(SpaceFactory, 'space_2')
|
||||||
|
|
||||||
|
|
||||||
# register(FoodFactory, space=LazyFixture('space_2'))
|
# register(FoodFactory, space=LazyFixture('space_2'))
|
||||||
# TODO refactor clients to be factories
|
# TODO refactor clients to be factories
|
||||||
|
|
||||||
@@ -169,7 +171,6 @@ def dict_compare(d1, d2, details=False):
|
|||||||
|
|
||||||
|
|
||||||
def transpose(text, number=2):
|
def transpose(text, number=2):
|
||||||
|
|
||||||
# select random token
|
# select random token
|
||||||
tokens = text.split()
|
tokens = text.split()
|
||||||
positions = list(i for i, e in enumerate(tokens) if len(e) > 1)
|
positions = list(i for i, e in enumerate(tokens) if len(e) > 1)
|
||||||
@@ -212,6 +213,14 @@ def ext_recipe_1_s1(space_1, u1_s1):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_food(space_1, u1_s1):
|
||||||
|
return Food.objects.get_or_create(name=str(uuid.uuid4()), space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_unit(space_1, u1_s1):
|
||||||
|
return Unit.objects.get_or_create(name=str(uuid.uuid4()), space=space_1)[0]
|
||||||
|
|
||||||
|
|
||||||
# ---------------------- USER FIXTURES -----------------------
|
# ---------------------- USER FIXTURES -----------------------
|
||||||
# maybe better with factories but this is very explict so ...
|
# maybe better with factories but this is very explict so ...
|
||||||
|
|
||||||
|
|||||||
129
cookbook/tests/other/test_food_property.py
Normal file
129
cookbook/tests/other/test_food_property.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
from django.contrib import auth
|
||||||
|
from django.core.cache import caches
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from cookbook.helper.cache_helper import CacheHelper
|
||||||
|
from cookbook.helper.property_helper import FoodPropertyHelper
|
||||||
|
from cookbook.models import Unit, Food, PropertyType, Property, Recipe, Step, UnitConversion, Property
|
||||||
|
|
||||||
|
|
||||||
|
def test_food_property(space_1, space_2, u1_s1):
|
||||||
|
with scopes_disabled():
|
||||||
|
unit_gram = Unit.objects.create(name='gram', base_unit='g', space=space_1)
|
||||||
|
unit_kg = Unit.objects.create(name='kg', base_unit='kg', space=space_1)
|
||||||
|
unit_pcs = Unit.objects.create(name='pcs', base_unit='', space=space_1)
|
||||||
|
unit_floz1 = Unit.objects.create(name='fl. oz 1', base_unit='imperial_fluid_ounce', space=space_1) # US and UK use different volume systems (US vs imperial)
|
||||||
|
unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=space_1)
|
||||||
|
unit_fantasy = Unit.objects.create(name='Fantasy Unit', base_unit='', space=space_1)
|
||||||
|
|
||||||
|
food_1 = Food.objects.create(name='food_1', space=space_1, properties_food_unit=unit_gram, properties_food_amount=100)
|
||||||
|
food_2 = Food.objects.create(name='food_2', space=space_1, properties_food_unit=unit_gram, properties_food_amount=100)
|
||||||
|
|
||||||
|
property_fat = PropertyType.objects.create(name='property_fat', space=space_1)
|
||||||
|
property_calories = PropertyType.objects.create(name='property_calories', space=space_1)
|
||||||
|
property_nuts = PropertyType.objects.create(name='property_nuts', space=space_1)
|
||||||
|
property_price = PropertyType.objects.create(name='property_price', space=space_1)
|
||||||
|
|
||||||
|
food_1_property_fat = Property.objects.create(property_amount=50, property_type=property_fat, space=space_1)
|
||||||
|
food_1_property_nuts = Property.objects.create(property_amount=1, property_type=property_nuts, space=space_1)
|
||||||
|
food_1_property_price = Property.objects.create(property_amount=7.50, property_type=property_price, space=space_1)
|
||||||
|
food_1.properties.add(food_1_property_fat, food_1_property_nuts, food_1_property_price)
|
||||||
|
|
||||||
|
food_2_property_fat = Property.objects.create(property_amount=25, property_type=property_fat, space=space_1)
|
||||||
|
food_2_property_nuts = Property.objects.create(property_amount=0, property_type=property_nuts, space=space_1)
|
||||||
|
food_2_property_price = Property.objects.create(property_amount=2.50, property_type=property_price, space=space_1)
|
||||||
|
food_2.properties.add(food_2_property_fat, food_2_property_nuts, food_2_property_price)
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION MULTI STEP IDENTICAL UNIT ---------------')
|
||||||
|
recipe_1 = Recipe.objects.create(name='recipe_1', waiting_time=0, working_time=0, space=space_1, created_by=auth.get_user(u1_s1))
|
||||||
|
|
||||||
|
step_1 = Step.objects.create(instruction='instruction_step_1', space=space_1)
|
||||||
|
step_1.ingredients.create(amount=500, unit=unit_gram, food=food_1, space=space_1)
|
||||||
|
step_1.ingredients.create(amount=1000, unit=unit_gram, food=food_2, space=space_1)
|
||||||
|
recipe_1.steps.add(step_1)
|
||||||
|
|
||||||
|
step_2 = Step.objects.create(instruction='instruction_step_1', space=space_1)
|
||||||
|
step_2.ingredients.create(amount=50, unit=unit_gram, food=food_1, space=space_1)
|
||||||
|
recipe_1.steps.add(step_2)
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_1)
|
||||||
|
|
||||||
|
assert property_values[property_fat.id]['name'] == property_fat.name
|
||||||
|
assert abs(property_values[property_fat.id]['total_value'] - Decimal(525)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_1.id]['value'] - Decimal(275)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_2.id]['value'] - Decimal(250)) < 0.0001
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION NO POSSIBLE CONVERSION ---------------')
|
||||||
|
recipe_2 = Recipe.objects.create(name='recipe_2', waiting_time=0, working_time=0, space=space_1, created_by=auth.get_user(u1_s1))
|
||||||
|
|
||||||
|
step_1 = Step.objects.create(instruction='instruction_step_1', space=space_1)
|
||||||
|
step_1.ingredients.create(amount=5, unit=unit_pcs, food=food_1, space=space_1)
|
||||||
|
step_1.ingredients.create(amount=10, unit=unit_pcs, food=food_2, space=space_1)
|
||||||
|
recipe_2.steps.add(step_1)
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_2)
|
||||||
|
|
||||||
|
assert property_values[property_fat.id]['name'] == property_fat.name
|
||||||
|
assert abs(property_values[property_fat.id]['total_value']) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_1.id]['value']) < 0.0001
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION UNIT CONVERSION ---------------')
|
||||||
|
uc1 = UnitConversion.objects.create(
|
||||||
|
base_amount=100,
|
||||||
|
base_unit=unit_gram,
|
||||||
|
converted_amount=1,
|
||||||
|
converted_unit=unit_pcs,
|
||||||
|
space=space_1,
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
)
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_2)
|
||||||
|
|
||||||
|
assert property_values[property_fat.id]['name'] == property_fat.name
|
||||||
|
assert abs(property_values[property_fat.id]['total_value'] - Decimal(500)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_1.id]['value'] - Decimal(250)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_2.id]['value'] - Decimal(250)) < 0.0001
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - PROPERTY CALCULATION UNIT CONVERSION MULTIPLE ---------------')
|
||||||
|
|
||||||
|
uc1.delete()
|
||||||
|
uc1 = UnitConversion.objects.create(
|
||||||
|
base_amount=0.1,
|
||||||
|
base_unit=unit_kg,
|
||||||
|
converted_amount=1,
|
||||||
|
converted_unit=unit_pcs,
|
||||||
|
space=space_1,
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
)
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_2)
|
||||||
|
|
||||||
|
assert property_values[property_fat.id]['name'] == property_fat.name
|
||||||
|
assert abs(property_values[property_fat.id]['total_value'] - Decimal(500)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_1.id]['value'] - Decimal(250)) < 0.0001
|
||||||
|
assert abs(property_values[property_fat.id]['food_values'][food_2.id]['value'] - Decimal(250)) < 0.0001
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - MISSING FOOD REFERENCE AMOUNT ---------------')
|
||||||
|
food_1.properties_food_unit = None
|
||||||
|
food_1.save()
|
||||||
|
food_2.properties_food_amount = 0
|
||||||
|
food_2.save()
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_1)
|
||||||
|
|
||||||
|
assert property_values[property_fat.id]['name'] == property_fat.name
|
||||||
|
assert property_values[property_fat.id]['total_value'] == 0
|
||||||
|
|
||||||
|
print('\n----------- TEST PROPERTY - SPACE SEPARATION ---------------')
|
||||||
|
|
||||||
|
property_fat.space = space_2
|
||||||
|
property_fat.save()
|
||||||
|
|
||||||
|
caches['default'].delete(CacheHelper(space_1).PROPERTY_TYPE_CACHE_KEY) # clear cache as objects won't change space in reality
|
||||||
|
|
||||||
|
property_values = FoodPropertyHelper(space_1).calculate_recipe_properties(recipe_2)
|
||||||
|
|
||||||
|
assert property_fat.id not in property_values
|
||||||
|
|
||||||
|
|
||||||
187
cookbook/tests/other/test_unit_conversion.py
Normal file
187
cookbook/tests/other/test_unit_conversion.py
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
from _decimal import Decimal
|
||||||
|
|
||||||
|
from django.contrib import auth
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
from cookbook.helper.unit_conversion_helper import UnitConversionHelper, ConversionException
|
||||||
|
from cookbook.models import Unit, Food, Ingredient, UnitConversion
|
||||||
|
|
||||||
|
|
||||||
|
def test_base_converter(space_1):
|
||||||
|
uch = UnitConversionHelper(space_1)
|
||||||
|
assert abs(uch.convert_from_to('g', 'kg', 1234) - Decimal(1.234)) < 0.0001
|
||||||
|
assert abs(uch.convert_from_to('kg', 'pound', 2) - Decimal(4.40924)) < 0.00001
|
||||||
|
assert abs(uch.convert_from_to('kg', 'g', 1) - Decimal(1000)) < 0.00001
|
||||||
|
assert abs(uch.convert_from_to('imperial_gallon', 'gallon', 1000) - Decimal(1200.95104)) < 0.00001
|
||||||
|
assert abs(uch.convert_from_to('tbsp', 'ml', 20) - Decimal(295.73549)) < 0.00001
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert uch.convert_from_to('kg', 'tbsp', 2) == 1234
|
||||||
|
assert False
|
||||||
|
except ConversionException:
|
||||||
|
assert True
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert uch.convert_from_to('kg', 'g2', 2) == 1234
|
||||||
|
assert False
|
||||||
|
except ConversionException:
|
||||||
|
assert True
|
||||||
|
|
||||||
|
|
||||||
|
def test_unit_conversions(space_1, space_2, u1_s1):
|
||||||
|
with scopes_disabled():
|
||||||
|
uch = UnitConversionHelper(space_1)
|
||||||
|
uch_space_2 = UnitConversionHelper(space_2)
|
||||||
|
|
||||||
|
unit_gram = Unit.objects.create(name='gram', base_unit='g', space=space_1)
|
||||||
|
unit_kg = Unit.objects.create(name='kg', base_unit='kg', space=space_1)
|
||||||
|
unit_pcs = Unit.objects.create(name='pcs', base_unit='', space=space_1)
|
||||||
|
unit_floz1 = Unit.objects.create(name='fl. oz 1', base_unit='imperial_fluid_ounce', space=space_1) # US and UK use different volume systems (US vs imperial)
|
||||||
|
unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=space_1)
|
||||||
|
unit_fantasy = Unit.objects.create(name='Fantasy Unit', base_unit='', space=space_1)
|
||||||
|
|
||||||
|
food_1 = Food.objects.create(name='Test Food 1', space=space_1)
|
||||||
|
food_2 = Food.objects.create(name='Test Food 2', space=space_1)
|
||||||
|
|
||||||
|
print('\n----------- TEST BASE CONVERSIONS - GRAM ---------------')
|
||||||
|
ingredient_food_1_gram = Ingredient.objects.create(
|
||||||
|
food=food_1,
|
||||||
|
unit=unit_gram,
|
||||||
|
amount=100,
|
||||||
|
space=space_1,
|
||||||
|
)
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_gram)
|
||||||
|
print(conversions)
|
||||||
|
assert len(conversions) == 2
|
||||||
|
assert next(x for x in conversions if x.unit == unit_kg) is not None
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_kg).amount - Decimal(0.1)) < 0.0001
|
||||||
|
|
||||||
|
print('\n----------- TEST BASE CONVERSIONS - VOLUMES ---------------')
|
||||||
|
|
||||||
|
ingredient_food_1_floz1 = Ingredient.objects.create(
|
||||||
|
food=food_1,
|
||||||
|
unit=unit_floz1,
|
||||||
|
amount=100,
|
||||||
|
space=space_1,
|
||||||
|
)
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_floz1)
|
||||||
|
assert len(conversions) == 2
|
||||||
|
assert next(x for x in conversions if x.unit == unit_floz2) is not None
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_floz2).amount - Decimal(96.07599404038842)) < 0.001 # TODO validate value
|
||||||
|
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
unit_pint = Unit.objects.create(name='pint', base_unit='pint', space=space_1)
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_floz1)
|
||||||
|
assert len(conversions) == 3
|
||||||
|
assert next(x for x in conversions if x.unit == unit_pint) is not None
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_pint).amount - Decimal(6.004749627524276)) < 0.001 # TODO validate value
|
||||||
|
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
print('\n----------- TEST BASE CUSTOM CONVERSION - TO CUSTOM CONVERSION ---------------')
|
||||||
|
UnitConversion.objects.create(
|
||||||
|
base_amount=1000,
|
||||||
|
base_unit=unit_gram,
|
||||||
|
converted_amount=1337,
|
||||||
|
converted_unit=unit_fantasy,
|
||||||
|
space=space_1,
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
)
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_gram)
|
||||||
|
|
||||||
|
assert len(conversions) == 3
|
||||||
|
assert next(x for x in conversions if x.unit == unit_fantasy) is not None
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_fantasy).amount - Decimal('133.700')) < 0.001 # TODO validate value
|
||||||
|
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
print('\n----------- TEST CUSTOM CONVERSION - NO PCS ---------------')
|
||||||
|
ingredient_food_1_pcs = Ingredient.objects.create(
|
||||||
|
food=food_1,
|
||||||
|
unit=unit_pcs,
|
||||||
|
amount=5,
|
||||||
|
space=space_1,
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient_food_2_pcs = Ingredient.objects.create(
|
||||||
|
food=food_2,
|
||||||
|
unit=unit_pcs,
|
||||||
|
amount=5,
|
||||||
|
space=space_1,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(uch.get_conversions(ingredient_food_1_pcs)) == 1
|
||||||
|
assert len(uch.get_conversions(ingredient_food_2_pcs)) == 1
|
||||||
|
print(uch.get_conversions(ingredient_food_1_pcs))
|
||||||
|
print(uch.get_conversions(ingredient_food_2_pcs))
|
||||||
|
|
||||||
|
print('\n----------- TEST CUSTOM CONVERSION - PCS TO MULTIPLE BASE ---------------')
|
||||||
|
uc1 = UnitConversion.objects.create(
|
||||||
|
base_amount=1,
|
||||||
|
base_unit=unit_pcs,
|
||||||
|
converted_amount=200,
|
||||||
|
converted_unit=unit_gram,
|
||||||
|
food=food_1,
|
||||||
|
space=space_1,
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
)
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_pcs)
|
||||||
|
assert len(conversions) == 3
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_gram).amount - Decimal(1000)) < 0.0001
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_kg).amount - Decimal(1)) < 0.0001
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
assert len(uch.get_conversions(ingredient_food_2_pcs)) == 1
|
||||||
|
print(uch.get_conversions(ingredient_food_2_pcs))
|
||||||
|
|
||||||
|
print('\n----------- TEST CUSTOM CONVERSION - CONVERT MULTI STEP ---------------')
|
||||||
|
|
||||||
|
# TODO add test for multi step conversion ... do I even do or want to support this ?
|
||||||
|
|
||||||
|
print('\n----------- TEST CUSTOM CONVERSION - REVERSE CONVERSION ---------------')
|
||||||
|
uc2 = UnitConversion.objects.create(
|
||||||
|
base_amount=200,
|
||||||
|
base_unit=unit_gram,
|
||||||
|
converted_amount=1,
|
||||||
|
converted_unit=unit_pcs,
|
||||||
|
food=food_2,
|
||||||
|
space=space_1,
|
||||||
|
created_by=auth.get_user(u1_s1),
|
||||||
|
)
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_1_pcs)
|
||||||
|
assert len(conversions) == 3
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_gram).amount - Decimal(1000)) < 0.0001
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_kg).amount - Decimal(1)) < 0.0001
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_2_pcs)
|
||||||
|
assert len(conversions) == 3
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_gram).amount - Decimal(1000)) < 0.0001
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_kg).amount - Decimal(1)) < 0.0001
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
print('\n----------- TEST SPACE SEPARATION ---------------')
|
||||||
|
uc2.space = space_2
|
||||||
|
uc2.save()
|
||||||
|
|
||||||
|
conversions = uch.get_conversions(ingredient_food_2_pcs)
|
||||||
|
assert len(conversions) == 1
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
conversions = uch_space_2.get_conversions(ingredient_food_1_gram)
|
||||||
|
assert len(conversions) == 1
|
||||||
|
assert not any(x for x in conversions if x.unit == unit_kg)
|
||||||
|
print(conversions)
|
||||||
|
|
||||||
|
unit_kg_space_2 = Unit.objects.create(name='kg', base_unit='kg', space=space_2)
|
||||||
|
conversions = uch_space_2.get_conversions(ingredient_food_1_gram)
|
||||||
|
assert len(conversions) == 2
|
||||||
|
assert not any(x for x in conversions if x.unit == unit_kg)
|
||||||
|
assert next(x for x in conversions if x.unit == unit_kg_space_2) is not None
|
||||||
|
assert abs(next(x for x in conversions if x.unit == unit_kg_space_2).amount - Decimal(0.1)) < 0.0001
|
||||||
|
print(conversions)
|
||||||
@@ -6,17 +6,23 @@ from rest_framework import permissions, routers
|
|||||||
from rest_framework.schemas import get_schema_view
|
from rest_framework.schemas import get_schema_view
|
||||||
|
|
||||||
from cookbook.helper import dal
|
from cookbook.helper import dal
|
||||||
from recipes.settings import DEBUG
|
from recipes.settings import DEBUG, PLUGINS
|
||||||
from recipes.version import VERSION_NUMBER
|
from recipes.version import VERSION_NUMBER
|
||||||
|
|
||||||
from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keyword, MealPlan, Recipe,
|
from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keyword, MealPlan, Recipe,
|
||||||
RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage,
|
RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, Sync, SyncLog, Unit, UserFile,
|
Supermarket, SupermarketCategory, Sync, SyncLog, Unit, UserFile,
|
||||||
get_model_name, UserSpace, Space)
|
get_model_name, UserSpace, Space, PropertyType, UnitConversion)
|
||||||
from .views import api, data, delete, edit, import_export, lists, new, telegram, views
|
from .views import api, data, delete, edit, import_export, lists, new, telegram, views
|
||||||
from .views.api import CustomAuthToken
|
from .views.api import CustomAuthToken, ImportOpenData
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
# extend DRF default router class to allow including additional routers
|
||||||
|
class DefaultRouter(routers.DefaultRouter):
|
||||||
|
def extend(self, r):
|
||||||
|
self.registry.extend(r.registry)
|
||||||
|
|
||||||
|
|
||||||
|
router = DefaultRouter()
|
||||||
router.register(r'automation', api.AutomationViewSet)
|
router.register(r'automation', api.AutomationViewSet)
|
||||||
router.register(r'bookmarklet-import', api.BookmarkletImportViewSet)
|
router.register(r'bookmarklet-import', api.BookmarkletImportViewSet)
|
||||||
router.register(r'cook-log', api.CookLogViewSet)
|
router.register(r'cook-log', api.CookLogViewSet)
|
||||||
@@ -34,6 +40,9 @@ router.register(r'meal-type', api.MealTypeViewSet)
|
|||||||
router.register(r'recipe', api.RecipeViewSet)
|
router.register(r'recipe', api.RecipeViewSet)
|
||||||
router.register(r'recipe-book', api.RecipeBookViewSet)
|
router.register(r'recipe-book', api.RecipeBookViewSet)
|
||||||
router.register(r'recipe-book-entry', api.RecipeBookEntryViewSet)
|
router.register(r'recipe-book-entry', api.RecipeBookEntryViewSet)
|
||||||
|
router.register(r'unit-conversion', api.UnitConversionViewSet)
|
||||||
|
router.register(r'food-property-type', api.PropertyTypeViewSet)
|
||||||
|
router.register(r'food-property', api.PropertyViewSet)
|
||||||
router.register(r'shopping-list', api.ShoppingListViewSet)
|
router.register(r'shopping-list', api.ShoppingListViewSet)
|
||||||
router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet)
|
router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet)
|
||||||
router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
|
router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
|
||||||
@@ -53,6 +62,13 @@ router.register(r'user-space', api.UserSpaceViewSet)
|
|||||||
router.register(r'view-log', api.ViewLogViewSet)
|
router.register(r'view-log', api.ViewLogViewSet)
|
||||||
router.register(r'access-token', api.AccessTokenViewSet)
|
router.register(r'access-token', api.AccessTokenViewSet)
|
||||||
|
|
||||||
|
for p in PLUGINS:
|
||||||
|
if c := locate(f'{p["module"]}.urls.{p["api_router_name"]}'):
|
||||||
|
try:
|
||||||
|
router.extend(c)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.index, name='index'),
|
path('', views.index, name='index'),
|
||||||
path('setup/', views.setup, name='view_setup'),
|
path('setup/', views.setup, name='view_setup'),
|
||||||
@@ -119,7 +135,6 @@ urlpatterns = [
|
|||||||
path('api/switch-active-space/<int:space_id>/', api.switch_active_space, name='api_switch_active_space'),
|
path('api/switch-active-space/<int:space_id>/', api.switch_active_space, name='api_switch_active_space'),
|
||||||
path('api/download-file/<int:file_id>/', api.download_file, name='api_download_file'),
|
path('api/download-file/<int:file_id>/', api.download_file, name='api_download_file'),
|
||||||
|
|
||||||
|
|
||||||
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'),
|
||||||
# TODO is this deprecated? not yet, some old forms remain, could likely be changed to generic API endpoints
|
# TODO is this deprecated? not yet, some old forms remain, could likely be changed to generic API endpoints
|
||||||
path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), # TODO is this deprecated?
|
path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), # TODO is this deprecated?
|
||||||
@@ -139,6 +154,7 @@ urlpatterns = [
|
|||||||
path('api/', include((router.urls, 'api'))),
|
path('api/', include((router.urls, 'api'))),
|
||||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
path('api-token-auth/', CustomAuthToken.as_view()),
|
path('api-token-auth/', CustomAuthToken.as_view()),
|
||||||
|
path('api-import-open-data/', ImportOpenData.as_view(), name='api_import_open_data'),
|
||||||
|
|
||||||
path('offline/', views.offline, name='view_offline'),
|
path('offline/', views.offline, name='view_offline'),
|
||||||
|
|
||||||
@@ -189,7 +205,7 @@ for m in generic_models:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step, CustomFilter]
|
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step, CustomFilter, UnitConversion, PropertyType]
|
||||||
for m in vue_models:
|
for m in vue_models:
|
||||||
py_name = get_model_name(m)
|
py_name = get_model_name(m)
|
||||||
url_name = py_name.replace('_', '-')
|
url_name = py_name.replace('_', '-')
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from annoying.functions import get_object_or_None
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.postgres.search import TrigramSimilarity
|
from django.contrib.postgres.search import TrigramSimilarity
|
||||||
|
from django.core.cache import caches
|
||||||
from django.core.exceptions import FieldError, ValidationError
|
from django.core.exceptions import FieldError, ValidationError
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When, Avg, Max
|
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When, Avg, Max
|
||||||
@@ -44,6 +45,7 @@ from rest_framework.parsers import MultiPartParser
|
|||||||
from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer
|
from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.throttling import AnonRateThrottle
|
from rest_framework.throttling import AnonRateThrottle
|
||||||
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import ViewSetMixin
|
from rest_framework.viewsets import ViewSetMixin
|
||||||
from treebeard.exceptions import InvalidMoveToDescendant, InvalidPosition, PathOverflow
|
from treebeard.exceptions import InvalidMoveToDescendant, InvalidPosition, PathOverflow
|
||||||
|
|
||||||
@@ -52,10 +54,13 @@ from cookbook.helper import recipe_url_import as helper
|
|||||||
from cookbook.helper.HelperFunctions import str2bool
|
from cookbook.helper.HelperFunctions import str2bool
|
||||||
from cookbook.helper.image_processing import handle_image
|
from cookbook.helper.image_processing import handle_image
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
|
from cookbook.helper.open_data_importer import OpenDataImporter
|
||||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
|
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
|
||||||
CustomIsOwnerReadOnly, CustomIsShared,
|
CustomIsOwnerReadOnly, CustomIsShared,
|
||||||
CustomIsSpaceOwner, CustomIsUser, group_required,
|
CustomIsSpaceOwner, CustomIsUser, group_required,
|
||||||
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission, CustomUserPermission, CustomTokenHasReadWriteScope, CustomTokenHasScope, has_group_permission)
|
is_space_owner, switch_user_active_space, above_space_limit,
|
||||||
|
CustomRecipePermission, CustomUserPermission,
|
||||||
|
CustomTokenHasReadWriteScope, CustomTokenHasScope, has_group_permission)
|
||||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
||||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup, clean_dict
|
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup, clean_dict
|
||||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||||
@@ -65,7 +70,7 @@ from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilte
|
|||||||
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
|
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog, UnitConversion, PropertyType, Property)
|
||||||
from cookbook.provider.dropbox import Dropbox
|
from cookbook.provider.dropbox import Dropbox
|
||||||
from cookbook.provider.local import Local
|
from cookbook.provider.local import Local
|
||||||
from cookbook.provider.nextcloud import Nextcloud
|
from cookbook.provider.nextcloud import Nextcloud
|
||||||
@@ -88,7 +93,8 @@ from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSeri
|
|||||||
SupermarketCategorySerializer, SupermarketSerializer,
|
SupermarketCategorySerializer, SupermarketSerializer,
|
||||||
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
||||||
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
||||||
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer, RecipeExportSerializer)
|
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer, FoodSimpleSerializer,
|
||||||
|
RecipeExportSerializer, UnitConversionSerializer, PropertyTypeSerializer, PropertySerializer)
|
||||||
from cookbook.views.import_export import get_integration
|
from cookbook.views.import_export import get_integration
|
||||||
from recipes import settings
|
from recipes import settings
|
||||||
|
|
||||||
@@ -166,14 +172,17 @@ class FuzzyFilterMixin(ViewSetMixin, ExtendedRecipeMixin):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = self.queryset.filter(space=self.request.space).order_by(Lower('name').asc())
|
self.queryset = self.queryset.filter(space=self.request.space).order_by(Lower('name').asc())
|
||||||
query = self.request.query_params.get('query', None)
|
query = self.request.query_params.get('query', None)
|
||||||
|
if self.request.user.is_authenticated:
|
||||||
fuzzy = self.request.user.searchpreference.lookup or any([self.model.__name__.lower() in x for x in
|
fuzzy = self.request.user.searchpreference.lookup or any([self.model.__name__.lower() in x for x in
|
||||||
self.request.user.searchpreference.trigram.values_list(
|
self.request.user.searchpreference.trigram.values_list(
|
||||||
'field', flat=True)])
|
'field', flat=True)])
|
||||||
|
else:
|
||||||
|
fuzzy = True
|
||||||
|
|
||||||
if query is not None and query not in ["''", '']:
|
if query is not None and query not in ["''", '']:
|
||||||
if fuzzy and (settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']):
|
if fuzzy and (settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||||
if any([self.model.__name__.lower() in x for x in
|
'django.db.backends.postgresql']):
|
||||||
self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
if self.request.user.is_authenticated and any([self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
||||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name__unaccent', query))
|
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name__unaccent', query))
|
||||||
else:
|
else:
|
||||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name', query))
|
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name', query))
|
||||||
@@ -181,13 +190,12 @@ class FuzzyFilterMixin(ViewSetMixin, ExtendedRecipeMixin):
|
|||||||
else:
|
else:
|
||||||
# TODO have this check unaccent search settings or other search preferences?
|
# TODO have this check unaccent search settings or other search preferences?
|
||||||
filter = Q(name__icontains=query)
|
filter = Q(name__icontains=query)
|
||||||
if any([self.model.__name__.lower() in x for x in
|
if self.request.user.is_authenticated:
|
||||||
self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
if any([self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
||||||
filter |= Q(name__unaccent__icontains=query)
|
filter |= Q(name__unaccent__icontains=query)
|
||||||
|
|
||||||
self.queryset = (
|
self.queryset = (
|
||||||
self.queryset
|
self.queryset.annotate(starts=Case(When(name__istartswith=query, then=(Value(100))),
|
||||||
.annotate(starts=Case(When(name__istartswith=query, then=(Value(100))),
|
|
||||||
default=Value(0))) # put exact matches at the top of the result set
|
default=Value(0))) # put exact matches at the top of the result set
|
||||||
.filter(filter).order_by('-starts', Lower('name').asc())
|
.filter(filter).order_by('-starts', Lower('name').asc())
|
||||||
)
|
)
|
||||||
@@ -243,6 +251,9 @@ class MergeMixin(ViewSetMixin):
|
|||||||
isTree = False
|
isTree = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if isinstance(source, Food):
|
||||||
|
source.properties.through.objects.all().delete()
|
||||||
|
|
||||||
for link in [field for field in source._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]:
|
for link in [field for field in source._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]:
|
||||||
linkManager = getattr(source, link.get_accessor_name())
|
linkManager = getattr(source, link.get_accessor_name())
|
||||||
related = linkManager.all()
|
related = linkManager.all()
|
||||||
@@ -272,6 +283,7 @@ class MergeMixin(ViewSetMixin):
|
|||||||
source.delete()
|
source.delete()
|
||||||
return Response(content, status=status.HTTP_200_OK)
|
return Response(content, status=status.HTTP_200_OK)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
content = {'error': True,
|
content = {'error': True,
|
||||||
'msg': _(f'An error occurred attempting to merge {source.name} with {target.name}')}
|
'msg': _(f'An error occurred attempting to merge {source.name} with {target.name}')}
|
||||||
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
||||||
@@ -522,8 +534,20 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
|
|||||||
pagination_class = DefaultPagination
|
pagination_class = DefaultPagination
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.request._shared_users = [x.id for x in list(self.request.user.get_shopping_share())] + [
|
shared_users = []
|
||||||
|
if c := caches['default'].get(
|
||||||
|
f'shopping_shared_users_{self.request.space.id}_{self.request.user.id}', None):
|
||||||
|
shared_users = c
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
shared_users = [x.id for x in list(self.request.user.get_shopping_share())] + [
|
||||||
self.request.user.id]
|
self.request.user.id]
|
||||||
|
caches['default'].set(
|
||||||
|
f'shopping_shared_users_{self.request.space.id}_{self.request.user.id}',
|
||||||
|
shared_users, timeout=5 * 60)
|
||||||
|
# TODO ugly hack that improves API performance significantly, should be done properly
|
||||||
|
except AttributeError: # Anonymous users (using share links) don't have shared users
|
||||||
|
pass
|
||||||
|
|
||||||
self.queryset = super().get_queryset()
|
self.queryset = super().get_queryset()
|
||||||
shopping_status = ShoppingListEntry.objects.filter(space=self.request.space, food=OuterRef('id'),
|
shopping_status = ShoppingListEntry.objects.filter(space=self.request.space, food=OuterRef('id'),
|
||||||
@@ -792,7 +816,32 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
|||||||
|
|
||||||
if self.detail: # if detail request and not list, private condition is verified by permission class
|
if self.detail: # if detail request and not list, private condition is verified by permission class
|
||||||
if not share: # filter for space only if not shared
|
if not share: # filter for space only if not shared
|
||||||
self.queryset = self.queryset.filter(space=self.request.space)
|
self.queryset = self.queryset.filter(space=self.request.space).prefetch_related(
|
||||||
|
'keywords',
|
||||||
|
'shared',
|
||||||
|
'properties',
|
||||||
|
'properties__property_type',
|
||||||
|
'steps',
|
||||||
|
'steps__ingredients',
|
||||||
|
'steps__ingredients__step_set',
|
||||||
|
'steps__ingredients__step_set__recipe_set',
|
||||||
|
'steps__ingredients__food',
|
||||||
|
'steps__ingredients__food__properties',
|
||||||
|
'steps__ingredients__food__properties__property_type',
|
||||||
|
'steps__ingredients__food__inherit_fields',
|
||||||
|
'steps__ingredients__food__supermarket_category',
|
||||||
|
'steps__ingredients__food__onhand_users',
|
||||||
|
'steps__ingredients__food__substitute',
|
||||||
|
'steps__ingredients__food__child_inherit_fields',
|
||||||
|
|
||||||
|
'steps__ingredients__unit',
|
||||||
|
'steps__ingredients__unit__unit_conversion_base_relation',
|
||||||
|
'steps__ingredients__unit__unit_conversion_base_relation__base_unit',
|
||||||
|
'steps__ingredients__unit__unit_conversion_converted_relation',
|
||||||
|
'steps__ingredients__unit__unit_conversion_converted_relation__converted_unit',
|
||||||
|
'cooklog_set',
|
||||||
|
).select_related('nutrition')
|
||||||
|
|
||||||
return super().get_queryset()
|
return super().get_queryset()
|
||||||
|
|
||||||
self.queryset = self.queryset.filter(space=self.request.space).filter(
|
self.queryset = self.queryset.filter(space=self.request.space).filter(
|
||||||
@@ -802,7 +851,7 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
|||||||
params = {x: self.request.GET.get(x) if len({**self.request.GET}[x]) == 1 else self.request.GET.getlist(x) for x
|
params = {x: self.request.GET.get(x) if len({**self.request.GET}[x]) == 1 else self.request.GET.getlist(x) for x
|
||||||
in list(self.request.GET)}
|
in list(self.request.GET)}
|
||||||
search = RecipeSearch(self.request, **params)
|
search = RecipeSearch(self.request, **params)
|
||||||
self.queryset = search.get_queryset(self.queryset).prefetch_related('cooklog_set')
|
self.queryset = search.get_queryset(self.queryset).prefetch_related('keywords', 'cooklog_set')
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
@@ -921,6 +970,41 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
|||||||
return Response(self.serializer_class(qs, many=True).data)
|
return Response(self.serializer_class(qs, many=True).data)
|
||||||
|
|
||||||
|
|
||||||
|
class UnitConversionViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = UnitConversion.objects
|
||||||
|
serializer_class = UnitConversionSerializer
|
||||||
|
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||||
|
query_params = [
|
||||||
|
QueryParam(name='food_id', description='ID of food to filter for', qtype='int'),
|
||||||
|
]
|
||||||
|
schema = QueryParamAutoSchema()
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
food_id = self.request.query_params.get('food_id', None)
|
||||||
|
if food_id is not None:
|
||||||
|
self.queryset = self.queryset.filter(food_id=food_id)
|
||||||
|
|
||||||
|
return self.queryset.filter(space=self.request.space)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTypeViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = PropertyType.objects
|
||||||
|
serializer_class = PropertyTypeSerializer
|
||||||
|
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.queryset.filter(space=self.request.space)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Property.objects
|
||||||
|
serializer_class = PropertySerializer
|
||||||
|
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.queryset.filter(space=self.request.space)
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
|
class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
|
||||||
queryset = ShoppingListRecipe.objects
|
queryset = ShoppingListRecipe.objects
|
||||||
serializer_class = ShoppingListRecipeSerializer
|
serializer_class = ShoppingListRecipeSerializer
|
||||||
@@ -1122,10 +1206,13 @@ class CustomAuthToken(ObtainAuthToken):
|
|||||||
context={'request': request})
|
context={'request': request})
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
user = serializer.validated_data['user']
|
user = serializer.validated_data['user']
|
||||||
if token := AccessToken.objects.filter(user=user, expires__gt=timezone.now(), scope__contains='read').filter(scope__contains='write').first():
|
if token := AccessToken.objects.filter(user=user, expires__gt=timezone.now(), scope__contains='read').filter(
|
||||||
|
scope__contains='write').first():
|
||||||
access_token = token
|
access_token = token
|
||||||
else:
|
else:
|
||||||
access_token = AccessToken.objects.create(user=user, token=f'tda_{str(uuid.uuid4()).replace("-", "_")}', expires=(timezone.now() + timezone.timedelta(days=365 * 5)), scope='read write app')
|
access_token = AccessToken.objects.create(user=user, token=f'tda_{str(uuid.uuid4()).replace("-", "_")}',
|
||||||
|
expires=(timezone.now() + timezone.timedelta(days=365 * 5)),
|
||||||
|
scope='read write app')
|
||||||
return Response({
|
return Response({
|
||||||
'id': access_token.id,
|
'id': access_token.id,
|
||||||
'token': access_token.token,
|
'token': access_token.token,
|
||||||
@@ -1153,7 +1240,8 @@ def recipe_from_source(request):
|
|||||||
serializer = RecipeFromSourceSerializer(data=request.data)
|
serializer = RecipeFromSourceSerializer(data=request.data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
|
|
||||||
if (b_pk := serializer.validated_data.get('bookmarklet', None)) and (bookmarklet := BookmarkletImport.objects.filter(pk=b_pk).first()):
|
if (b_pk := serializer.validated_data.get('bookmarklet', None)) and (
|
||||||
|
bookmarklet := BookmarkletImport.objects.filter(pk=b_pk).first()):
|
||||||
serializer.validated_data['url'] = bookmarklet.url
|
serializer.validated_data['url'] = bookmarklet.url
|
||||||
serializer.validated_data['data'] = bookmarklet.html
|
serializer.validated_data['data'] = bookmarklet.html
|
||||||
bookmarklet.delete()
|
bookmarklet.delete()
|
||||||
@@ -1175,13 +1263,22 @@ def recipe_from_source(request):
|
|||||||
# 'recipe_html': '',
|
# 'recipe_html': '',
|
||||||
'recipe_images': [],
|
'recipe_images': [],
|
||||||
}, status=status.HTTP_200_OK)
|
}, status=status.HTTP_200_OK)
|
||||||
if re.match('^(.)*/view/recipe/[0-9]+/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', url):
|
if re.match(
|
||||||
recipe_json = requests.get(url.replace('/view/recipe/', '/api/recipe/').replace(re.split('/view/recipe/[0-9]+', url)[1], '') + '?share=' + re.split('/view/recipe/[0-9]+', url)[1].replace('/', '')).json()
|
'^(.)*/view/recipe/[0-9]+/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$',
|
||||||
|
url):
|
||||||
|
recipe_json = requests.get(
|
||||||
|
url.replace('/view/recipe/', '/api/recipe/').replace(re.split('/view/recipe/[0-9]+', url)[1],
|
||||||
|
'') + '?share=' +
|
||||||
|
re.split('/view/recipe/[0-9]+', url)[1].replace('/', '')).json()
|
||||||
recipe_json = clean_dict(recipe_json, 'id')
|
recipe_json = clean_dict(recipe_json, 'id')
|
||||||
serialized_recipe = RecipeExportSerializer(data=recipe_json, context={'request': request})
|
serialized_recipe = RecipeExportSerializer(data=recipe_json, context={'request': request})
|
||||||
if serialized_recipe.is_valid():
|
if serialized_recipe.is_valid():
|
||||||
recipe = serialized_recipe.save()
|
recipe = serialized_recipe.save()
|
||||||
recipe.image = File(handle_image(request, File(io.BytesIO(requests.get(recipe_json['image']).content), name='image'), filetype=pathlib.Path(recipe_json['image']).suffix),
|
if validators.url(recipe_json['image'], public=True):
|
||||||
|
recipe.image = File(handle_image(request,
|
||||||
|
File(io.BytesIO(requests.get(recipe_json['image']).content),
|
||||||
|
name='image'),
|
||||||
|
filetype=pathlib.Path(recipe_json['image']).suffix),
|
||||||
name=f'{uuid.uuid4()}_{recipe.pk}{pathlib.Path(recipe_json["image"]).suffix}')
|
name=f'{uuid.uuid4()}_{recipe.pk}{pathlib.Path(recipe_json["image"]).suffix}')
|
||||||
recipe.save()
|
recipe.save()
|
||||||
return Response({
|
return Response({
|
||||||
@@ -1323,11 +1420,44 @@ def import_files(request):
|
|||||||
|
|
||||||
return Response({'import_id': il.pk}, status=status.HTTP_200_OK)
|
return Response({'import_id': il.pk}, status=status.HTTP_200_OK)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
return Response({'error': True, 'msg': _('Importing is not implemented for this provider')}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': True, 'msg': _('Importing is not implemented for this provider')},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
else:
|
else:
|
||||||
return Response({'error': True, 'msg': form.errors}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': True, 'msg': form.errors}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
class ImportOpenData(APIView):
|
||||||
|
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||||
|
|
||||||
|
def get(self, request, format=None):
|
||||||
|
response = requests.get('https://raw.githubusercontent.com/TandoorRecipes/open-tandoor-data/main/build/meta.json')
|
||||||
|
metadata = json.loads(response.content)
|
||||||
|
return Response(metadata)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
# TODO validate data
|
||||||
|
print(request.data)
|
||||||
|
selected_version = request.data['selected_version']
|
||||||
|
selected_datatypes = request.data['selected_datatypes']
|
||||||
|
update_existing = str2bool(request.data['update_existing'])
|
||||||
|
use_metric = str2bool(request.data['use_metric'])
|
||||||
|
|
||||||
|
response = requests.get(f'https://raw.githubusercontent.com/TandoorRecipes/open-tandoor-data/main/build/{selected_version}.json') # TODO catch 404, timeout, ...
|
||||||
|
data = json.loads(response.content)
|
||||||
|
|
||||||
|
response_obj = {}
|
||||||
|
|
||||||
|
data_importer = OpenDataImporter(request, data, update_existing=update_existing, use_metric=use_metric)
|
||||||
|
response_obj['unit'] = len(data_importer.import_units())
|
||||||
|
response_obj['category'] = len(data_importer.import_category())
|
||||||
|
response_obj['property'] = len(data_importer.import_property())
|
||||||
|
response_obj['store'] = len(data_importer.import_supermarket())
|
||||||
|
response_obj['food'] = len(data_importer.import_food())
|
||||||
|
response_obj['conversion'] = len(data_importer.import_conversion())
|
||||||
|
|
||||||
|
return Response(response_obj)
|
||||||
|
|
||||||
|
|
||||||
def get_recipe_provider(recipe):
|
def get_recipe_provider(recipe):
|
||||||
if recipe.storage.method == Storage.DROPBOX:
|
if recipe.storage.method == Storage.DROPBOX:
|
||||||
return Dropbox
|
return Dropbox
|
||||||
|
|||||||
@@ -228,3 +228,33 @@ def step(request):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@group_required('user')
|
||||||
|
def unit_conversion(request):
|
||||||
|
# model-name is the models.js name of the model, probably ALL-CAPS
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
'generic/model_template.html',
|
||||||
|
{
|
||||||
|
"title": _("Unit Conversions"),
|
||||||
|
"config": {
|
||||||
|
'model': "UNIT_CONVERSION", # *REQUIRED* name of the model in models.js
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@group_required('user')
|
||||||
|
def property_type(request):
|
||||||
|
# model-name is the models.js name of the model, probably ALL-CAPS
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
'generic/model_template.html',
|
||||||
|
{
|
||||||
|
"title": _("Property Types"),
|
||||||
|
"config": {
|
||||||
|
'model': "PROPERTY_TYPE", # *REQUIRED* name of the model in models.js
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import uuid
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import update_session_auth_hash
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.contrib.auth.password_validation import validate_password
|
from django.contrib.auth.password_validation import validate_password
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@@ -18,11 +15,9 @@ from django.urls import reverse, reverse_lazy
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from oauth2_provider.models import AccessToken
|
|
||||||
|
|
||||||
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, ShoppingPreferenceForm,
|
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, SpaceCreateForm, SpaceJoinForm, User,
|
||||||
SpaceCreateForm, SpaceJoinForm, User,
|
UserCreateForm, UserPreference)
|
||||||
UserCreateForm, UserNameForm, UserPreference, UserPreferenceForm)
|
|
||||||
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||||
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
||||||
Space, ViewLog, UserSpace)
|
Space, ViewLog, UserSpace)
|
||||||
|
|||||||
@@ -239,6 +239,9 @@ RecetteTek exports are `.rtk` files which can simply be uploaded to tandoor to i
|
|||||||
## Rezeptsuite.de
|
## Rezeptsuite.de
|
||||||
Rezeptsuite.de exports are `.xml` files which can simply be uploaded to tandoor to import all your recipes.
|
Rezeptsuite.de exports are `.xml` files which can simply be uploaded to tandoor to import all your recipes.
|
||||||
|
|
||||||
|
It appears that Reptsuite, depending on the client, might export a `.zip` file containing a `.cml` file.
|
||||||
|
If this happens just unzip the zip file and change `.cml` to `.xml` to import your recipes.
|
||||||
|
|
||||||
## Melarecipes
|
## Melarecipes
|
||||||
|
|
||||||
Melarecipes provides multiple export formats but only the `MelaRecipes` format can export the complete collection.
|
Melarecipes provides multiple export formats but only the `MelaRecipes` format can export the complete collection.
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ nav:
|
|||||||
- Templating: features/templating.md
|
- Templating: features/templating.md
|
||||||
- Shopping: features/shopping.md
|
- Shopping: features/shopping.md
|
||||||
- Authentication: features/authentication.md
|
- Authentication: features/authentication.md
|
||||||
|
- Automation: features/automation.md
|
||||||
- Storages and Sync: features/external_recipes.md
|
- Storages and Sync: features/external_recipes.md
|
||||||
- Import/Export: features/import_export.md
|
- Import/Export: features/import_export.md
|
||||||
- System:
|
- System:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/2.0/ref/settings/
|
|||||||
"""
|
"""
|
||||||
import ast
|
import ast
|
||||||
import json
|
import json
|
||||||
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@@ -80,6 +81,8 @@ DJANGO_TABLES2_PAGE_RANGE = 8
|
|||||||
HCAPTCHA_SITEKEY = os.getenv('HCAPTCHA_SITEKEY', '')
|
HCAPTCHA_SITEKEY = os.getenv('HCAPTCHA_SITEKEY', '')
|
||||||
HCAPTCHA_SECRET = os.getenv('HCAPTCHA_SECRET', '')
|
HCAPTCHA_SECRET = os.getenv('HCAPTCHA_SECRET', '')
|
||||||
|
|
||||||
|
FDA_API_KEY = os.getenv('FDA_API_KEY', 'DEMO_KEY')
|
||||||
|
|
||||||
SHARING_ABUSE = bool(int(os.getenv('SHARING_ABUSE', False)))
|
SHARING_ABUSE = bool(int(os.getenv('SHARING_ABUSE', False)))
|
||||||
SHARING_LIMIT = int(os.getenv('SHARING_LIMIT', 0))
|
SHARING_LIMIT = int(os.getenv('SHARING_LIMIT', 0))
|
||||||
|
|
||||||
@@ -144,6 +147,9 @@ try:
|
|||||||
'base_path': os.path.join(BASE_DIR, 'recipes', 'plugins', d),
|
'base_path': os.path.join(BASE_DIR, 'recipes', 'plugins', d),
|
||||||
'base_url': plugin_class.base_url,
|
'base_url': plugin_class.base_url,
|
||||||
'bundle_name': plugin_class.bundle_name if hasattr(plugin_class, 'bundle_name') else '',
|
'bundle_name': plugin_class.bundle_name if hasattr(plugin_class, 'bundle_name') else '',
|
||||||
|
'api_router_name': plugin_class.api_router_name if hasattr(plugin_class, 'api_router_name') else '',
|
||||||
|
'nav_main': plugin_class.nav_main if hasattr(plugin_class, 'nav_main') else '',
|
||||||
|
'nav_dropdown': plugin_class.nav_dropdown if hasattr(plugin_class, 'nav_dropdown') else '',
|
||||||
}
|
}
|
||||||
PLUGINS.append(plugin_config)
|
PLUGINS.append(plugin_config)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -412,7 +418,7 @@ for p in PLUGINS:
|
|||||||
if p['bundle_name'] != '':
|
if p['bundle_name'] != '':
|
||||||
WEBPACK_LOADER[p['bundle_name']] = {
|
WEBPACK_LOADER[p['bundle_name']] = {
|
||||||
'CACHE': not DEBUG,
|
'CACHE': not DEBUG,
|
||||||
'BUNDLE_DIR_NAME': f'{p["base_path"]}/vue/', # must end with slash
|
'BUNDLE_DIR_NAME': f'vue/', # must end with slash
|
||||||
'STATS_FILE': os.path.join(p["base_path"], 'vue', 'webpack-stats.json'),
|
'STATS_FILE': os.path.join(p["base_path"], 'vue', 'webpack-stats.json'),
|
||||||
'POLL_INTERVAL': 0.1,
|
'POLL_INTERVAL': 0.1,
|
||||||
'TIMEOUT': None,
|
'TIMEOUT': None,
|
||||||
@@ -445,6 +451,7 @@ LANGUAGES = [
|
|||||||
('hu', _('Hungarian')),
|
('hu', _('Hungarian')),
|
||||||
('it', _('Italian')),
|
('it', _('Italian')),
|
||||||
('lv', _('Latvian')),
|
('lv', _('Latvian')),
|
||||||
|
('nb', _('Norwegian ')),
|
||||||
('pl', _('Polish')),
|
('pl', _('Polish')),
|
||||||
('ru', _('Russian')),
|
('ru', _('Russian')),
|
||||||
('es', _('Spanish')),
|
('es', _('Spanish')),
|
||||||
@@ -514,3 +521,5 @@ EMAIL_USE_SSL = bool(int(os.getenv('EMAIL_USE_SSL', False)))
|
|||||||
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'webmaster@localhost')
|
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'webmaster@localhost')
|
||||||
ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv(
|
ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv(
|
||||||
'ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tandoor Recipes] ') # allauth sender prefix
|
'ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tandoor Recipes] ') # allauth sender prefix
|
||||||
|
|
||||||
|
mimetypes.add_type("text/javascript", ".js", True)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
Django==4.1.7
|
Django==4.1.9
|
||||||
cryptography==39.0.1
|
cryptography==41.0.0
|
||||||
django-annoying==0.10.6
|
django-annoying==0.10.6
|
||||||
django-autocomplete-light==3.9.4
|
django-autocomplete-light==3.9.4
|
||||||
django-cleanup==7.0.0
|
django-cleanup==7.0.0
|
||||||
@@ -17,7 +17,7 @@ Markdown==3.4.3
|
|||||||
Pillow==9.4.0
|
Pillow==9.4.0
|
||||||
psycopg2-binary==2.9.5
|
psycopg2-binary==2.9.5
|
||||||
python-dotenv==0.21.0
|
python-dotenv==0.21.0
|
||||||
requests==2.28.2
|
requests==2.31.0
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
webdavclient3==3.14.6
|
webdavclient3==3.14.6
|
||||||
whitenoise==6.2.0
|
whitenoise==6.2.0
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Image and misc properties -->
|
<!-- Image and misc -->
|
||||||
<div class="row pt-2">
|
<div class="row pt-2">
|
||||||
<div class="col-md-6" style="max-height: 50vh; min-height: 30vh">
|
<div class="col-md-6" style="max-height: 50vh; min-height: 30vh">
|
||||||
<input id="id_file_upload" ref="file_upload" type="file" hidden
|
<input id="id_file_upload" ref="file_upload" type="file" hidden
|
||||||
@@ -99,65 +99,53 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nutrition -->
|
|
||||||
<div class="row pt-2">
|
<div class="row pt-2">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="card border-grey">
|
<div class="card mt-2 mb-2">
|
||||||
<div class="card-header" style="display: table">
|
<div class="card-body pr-2 pl-2 pr-md-5 pl-md-5 pt-3 pb-3">
|
||||||
<div class="row">
|
<h6>{{ $t('Properties') }} <small class="text-muted"> {{$t('per_serving')}}</small></h6>
|
||||||
<div class="col-md-9 d-table">
|
|
||||||
<h5 class="d-table-cell align-middle">{{ $t("Nutrition") }}</h5>
|
<div class="alert alert-info" role="alert">
|
||||||
|
{{ $t('recipe_property_info')}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex mt-2" v-for="p in recipe.properties" v-bind:key="p.id">
|
||||||
|
<div class="flex-fill w-50">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="p.property_type = $event.val"
|
||||||
|
:initial_single_selection="p.property_type"
|
||||||
|
:label="'name'"
|
||||||
|
:model="Models.PROPERTY_TYPE"
|
||||||
|
:limit="25"
|
||||||
|
:multiple="false"
|
||||||
|
></generic-multiselect>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill w-50">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control" v-model="p.property_amount">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text" v-if="p.property_type !== null && p.property_type.unit !== ''">{{ p.property_type.unit }}</span>
|
||||||
|
<button class="btn btn-danger" @click="deleteProperty(p)"><i class="fa fa-trash fa-fw"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-row mt-2">
|
||||||
|
<div class="flex-column w-25 offset-4">
|
||||||
|
<button class="btn btn-success btn-block" @click="addProperty()"><i class="fa fa-plus"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
@click="addNutrition()"
|
|
||||||
v-if="recipe.nutrition === null"
|
|
||||||
v-b-tooltip.hover
|
|
||||||
v-bind:title="$t('Add_nutrition_recipe')"
|
|
||||||
class="btn btn-sm btn-success shadow-none float-right"
|
|
||||||
>
|
|
||||||
<i class="fas fa-plus-circle"></i>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
@click="removeNutrition()"
|
|
||||||
v-if="recipe.nutrition !== null"
|
|
||||||
v-b-tooltip.hover
|
|
||||||
v-bind:title="$t('Remove_nutrition_recipe')"
|
|
||||||
class="btn btn-sm btn-danger shadow-none float-right"
|
|
||||||
>
|
|
||||||
<i class="fas fa-trash-alt"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<b-collapse id="id_nutrition_collapse" class="mt-2" v-model="nutrition_visible">
|
<div class="row pt-2">
|
||||||
<div class="card-body" v-if="recipe.nutrition !== null">
|
<div class="col-md-12">
|
||||||
<b-alert show>
|
|
||||||
There is currently only very basic support for tracking nutritional information. A
|
|
||||||
<a href="https://github.com/vabene1111/recipes/issues/896" target="_blank"
|
|
||||||
rel="noreferrer nofollow">big update</a> is planned to improve on this in many
|
|
||||||
different areas.
|
|
||||||
</b-alert>
|
|
||||||
|
|
||||||
<label for="id_name"> {{ $t(energy()) }}</label>
|
|
||||||
|
|
||||||
<input class="form-control" id="id_calories" v-model="recipe.nutrition.calories"/>
|
|
||||||
|
|
||||||
<label for="id_name"> {{ $t("Carbohydrates") }}</label>
|
|
||||||
<input class="form-control" id="id_carbohydrates"
|
|
||||||
v-model="recipe.nutrition.carbohydrates"/>
|
|
||||||
|
|
||||||
<label for="id_name"> {{ $t("Fats") }}</label>
|
|
||||||
<input class="form-control" id="id_fats" v-model="recipe.nutrition.fats"/>
|
|
||||||
|
|
||||||
<label for="id_name"> {{ $t("Proteins") }}</label>
|
|
||||||
<input class="form-control" id="id_proteins" v-model="recipe.nutrition.proteins"/>
|
|
||||||
</div>
|
|
||||||
</b-collapse>
|
|
||||||
</div>
|
|
||||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||||
<b-button squared block v-b-toggle.additional_collapse class="text-left"
|
<b-button squared block v-b-toggle.additional_collapse class="text-left"
|
||||||
variant="outline-primary">{{ $t("additional_options") }}
|
variant="outline-primary">{{ $t("additional_options") }}
|
||||||
@@ -1121,6 +1109,14 @@ export default {
|
|||||||
let new_keyword = {label: tag, name: tag}
|
let new_keyword = {label: tag, name: tag}
|
||||||
this.recipe.keywords.push(new_keyword)
|
this.recipe.keywords.push(new_keyword)
|
||||||
},
|
},
|
||||||
|
addProperty: function () {
|
||||||
|
this.recipe.properties.push(
|
||||||
|
{'property_amount': 0, 'property_type': null}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
deleteProperty: function (recipe_property) {
|
||||||
|
this.recipe.properties = this.recipe.properties.filter(p => p.id !== recipe_property.id)
|
||||||
|
},
|
||||||
searchKeywords: function (query) {
|
searchKeywords: function (query) {
|
||||||
let apiFactory = new ApiApiFactory()
|
let apiFactory = new ApiApiFactory()
|
||||||
|
|
||||||
|
|||||||
@@ -1,158 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<template v-if="loading">
|
<recipe-view-component></recipe-view-component>
|
||||||
<loading-spinner></loading-spinner>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-if="!loading" style="padding-bottom: 60px">
|
|
||||||
<RecipeSwitcher ref="ref_recipe_switcher" @switch="quickSwitch($event)"/>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12" style="text-align: center">
|
|
||||||
<h3>{{ recipe.name }}</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row text-center">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
<recipe-rating :recipe="recipe"></recipe-rating>
|
|
||||||
<last-cooked :recipe="recipe" class="mt-2"></last-cooked>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-auto">
|
|
||||||
<div class="col-12" style="text-align: center">
|
|
||||||
<i>{{ recipe.description }}</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="text-align: center">
|
|
||||||
<keywords-component :recipe="recipe"></keywords-component>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
<div class="row align-items-center">
|
|
||||||
<div class="col col-md-3">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<i class="fas fa-fw fa-user-clock fa-2x text-primary"></i>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<span class="text-primary"><b>{{ $t("Preparation") }}</b></span><br/>
|
|
||||||
{{ working_time }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col col-md-3">
|
|
||||||
<div class="row d-flex">
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<i class="far fa-fw fa-clock fa-2x text-primary"></i>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<span class="text-primary"><b>{{ $t("Waiting") }}</b></span><br/>
|
|
||||||
{{ waiting_time }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col col-md-4 col-10 mt-2 mt-md-0">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<i class="fas fa-fw fa-pizza-slice fa-2x text-primary"></i>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<CustomInputSpinButton v-model.number="servings"/>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto mr-1">
|
|
||||||
<span class="text-primary">
|
|
||||||
<b>
|
|
||||||
<template v-if="recipe.servings_text === ''">{{ $t("Servings") }}</template>
|
|
||||||
<template v-else>{{ recipe.servings_text }}</template>
|
|
||||||
</b>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col col-md-2 col-2 mt-2 mt-md-0 text-right">
|
|
||||||
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"
|
|
||||||
:disabled_options="{print:false}"></recipe-context-menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2"
|
|
||||||
v-if="recipe && ingredient_count > 0 && (recipe.show_ingredient_overview || recipe.steps.length < 2)">
|
|
||||||
<ingredients-card
|
|
||||||
:recipe="recipe.id"
|
|
||||||
:steps="recipe.steps"
|
|
||||||
:ingredient_factor="ingredient_factor"
|
|
||||||
:servings="servings"
|
|
||||||
:header="true"
|
|
||||||
id="ingredient_container"
|
|
||||||
@checked-state-changed="updateIngredientCheckedState"
|
|
||||||
@change-servings="servings = $event"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<img class="img img-fluid rounded" :src="recipe.image" :alt="$t('Recipe_Image')"
|
|
||||||
v-if="recipe.image !== null" @load="onImgLoad"
|
|
||||||
:style="{ 'max-height': ingredient_height }"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-if="!recipe.internal">
|
|
||||||
<div v-if="recipe.file_path.includes('.pdf')">
|
|
||||||
<PdfViewer :recipe="recipe"></PdfViewer>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg') || recipe.file_path.includes('.gif')">
|
|
||||||
<ImageViewer :recipe="recipe"></ImageViewer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
|
|
||||||
<step-component
|
|
||||||
:recipe="recipe"
|
|
||||||
:step="s"
|
|
||||||
:ingredient_factor="ingredient_factor"
|
|
||||||
:index="index"
|
|
||||||
:start_time="start_time"
|
|
||||||
@update-start-time="updateStartTime"
|
|
||||||
@checked-state-changed="updateIngredientCheckedState"
|
|
||||||
></step-component>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="recipe.source_url !== null">
|
|
||||||
<h6 class="d-print-none"><i class="fas fa-file-import"></i> {{ $t("Imported_From") }}</h6>
|
|
||||||
<span class="text-muted mt-1"><a style="overflow-wrap: break-word;"
|
|
||||||
:href="recipe.source_url">{{ recipe.source_url }}</a></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row" style="margin-top: 2vh; ">
|
|
||||||
<div class="col-lg-6 offset-lg-3 col-12">
|
|
||||||
<Nutrition-component :recipe="recipe" id="nutrition_container"
|
|
||||||
:ingredient_factor="ingredient_factor"></Nutrition-component>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<add-recipe-to-book :recipe="recipe"></add-recipe-to-book>
|
|
||||||
|
|
||||||
<div class="row text-center d-print-none" style="margin-top: 3vh; margin-bottom: 3vh"
|
|
||||||
v-if="share_uid !== 'None' && !loading">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
<import-tandoor></import-tandoor> <br/>
|
|
||||||
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)" class="mt-3">{{ $t("Report Abuse") }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<bottom-navigation-bar></bottom-navigation-bar>
|
<bottom-navigation-bar></bottom-navigation-bar>
|
||||||
</div>
|
</div>
|
||||||
@@ -163,192 +11,28 @@ import Vue from "vue"
|
|||||||
import {BootstrapVue} from "bootstrap-vue"
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
|
||||||
import {apiLoadRecipe} from "@/utils/api"
|
import RecipeViewComponent from "@/components/RecipeViewComponent.vue";
|
||||||
|
|
||||||
import RecipeContextMenu from "@/components/RecipeContextMenu"
|
|
||||||
import {ResolveUrlMixin, ToastMixin, calculateHourMinuteSplit} from "@/utils/utils"
|
|
||||||
|
|
||||||
import PdfViewer from "@/components/PdfViewer"
|
|
||||||
import ImageViewer from "@/components/ImageViewer"
|
|
||||||
|
|
||||||
import moment from "moment"
|
|
||||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
|
||||||
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook"
|
|
||||||
import RecipeRating from "@/components/RecipeRating"
|
|
||||||
import LastCooked from "@/components/LastCooked"
|
|
||||||
import IngredientsCard from "@/components/IngredientsCard"
|
|
||||||
import StepComponent from "@/components/StepComponent"
|
|
||||||
import KeywordsComponent from "@/components/KeywordsComponent"
|
|
||||||
import NutritionComponent from "@/components/NutritionComponent"
|
|
||||||
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
|
|
||||||
import CustomInputSpinButton from "@/components/CustomInputSpinButton"
|
|
||||||
import {ApiApiFactory} from "@/utils/openapi/api";
|
|
||||||
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
|
|
||||||
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
|
|
||||||
|
|
||||||
Vue.prototype.moment = moment
|
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "RecipeView",
|
name: "RecipeView",
|
||||||
mixins: [ResolveUrlMixin, ToastMixin],
|
mixins: [],
|
||||||
components: {
|
components: {
|
||||||
ImportTandoor,
|
RecipeViewComponent
|
||||||
LastCooked,
|
|
||||||
RecipeRating,
|
|
||||||
PdfViewer,
|
|
||||||
ImageViewer,
|
|
||||||
IngredientsCard,
|
|
||||||
StepComponent,
|
|
||||||
RecipeContextMenu,
|
|
||||||
NutritionComponent,
|
|
||||||
KeywordsComponent,
|
|
||||||
LoadingSpinner,
|
|
||||||
AddRecipeToBook,
|
|
||||||
RecipeSwitcher,
|
|
||||||
CustomInputSpinButton,
|
|
||||||
BottomNavigationBar,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
ingredient_factor: function () {
|
|
||||||
return this.servings / this.recipe.servings
|
|
||||||
},
|
|
||||||
ingredient_count() {
|
|
||||||
return this.recipe?.steps.map((x) => x.ingredients).flat().length
|
|
||||||
},
|
|
||||||
working_time: function () {
|
|
||||||
return calculateHourMinuteSplit(this.recipe.working_time)
|
|
||||||
},
|
|
||||||
waiting_time: function () {
|
|
||||||
return calculateHourMinuteSplit(this.recipe.waiting_time)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
computed: {},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {}
|
||||||
loading: true,
|
|
||||||
recipe: undefined,
|
|
||||||
rootrecipe: undefined,
|
|
||||||
servings: 1,
|
|
||||||
servings_cache: {},
|
|
||||||
start_time: "",
|
|
||||||
share_uid: window.SHARE_UID,
|
|
||||||
wake_lock: null,
|
|
||||||
ingredient_height: '250',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
servings(newVal, oldVal) {
|
|
||||||
this.servings_cache[this.recipe.id] = this.servings
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadRecipe(window.RECIPE_ID)
|
|
||||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
this.requestWakeLock()
|
|
||||||
window.addEventListener('resize', this.handleResize);
|
|
||||||
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
this.destroyWakeLock()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
requestWakeLock: async function () {
|
|
||||||
if ('wakeLock' in navigator) {
|
|
||||||
try {
|
|
||||||
this.wake_lock = await navigator.wakeLock.request('screen')
|
|
||||||
document.addEventListener('visibilitychange', this.visibilityChange)
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleResize: function () {
|
|
||||||
if (document.getElementById('nutrition_container') !== null) {
|
|
||||||
this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight
|
|
||||||
} else {
|
|
||||||
this.ingredient_height = document.getElementById('ingredient_container').clientHeight
|
|
||||||
}
|
|
||||||
},
|
|
||||||
destroyWakeLock: function () {
|
|
||||||
if (this.wake_lock != null) {
|
|
||||||
this.wake_lock.release()
|
|
||||||
.then(() => {
|
|
||||||
this.wake_lock = null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.removeEventListener('visibilitychange', this.visibilityChange)
|
|
||||||
},
|
|
||||||
visibilityChange: async function () {
|
|
||||||
if (this.wake_lock != null && document.visibilityState === 'visible') {
|
|
||||||
await this.requestWakeLock()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadRecipe: function (recipe_id) {
|
|
||||||
apiLoadRecipe(recipe_id).then((recipe) => {
|
|
||||||
let total_time = 0
|
|
||||||
for (let step of recipe.steps) {
|
|
||||||
for (let ingredient of step.ingredients) {
|
|
||||||
this.$set(ingredient, "checked", false)
|
|
||||||
}
|
|
||||||
|
|
||||||
step.time_offset = total_time
|
|
||||||
total_time += step.time
|
|
||||||
}
|
|
||||||
|
|
||||||
// set start time only if there are any steps with timers (otherwise no timers are rendered)
|
|
||||||
if (total_time > 0) {
|
|
||||||
this.start_time = moment().format("yyyy-MM-DDTHH:mm")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (recipe.image === null) this.printReady()
|
|
||||||
|
|
||||||
this.recipe = this.rootrecipe = recipe
|
|
||||||
this.servings = this.servings_cache[this.rootrecipe.id] = recipe.servings
|
|
||||||
this.loading = false
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.handleResize()
|
|
||||||
}, 100)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateStartTime: function (e) {
|
|
||||||
this.start_time = e
|
|
||||||
},
|
|
||||||
updateIngredientCheckedState: function (e) {
|
|
||||||
for (let step of this.recipe.steps) {
|
|
||||||
for (let ingredient of step.ingredients) {
|
|
||||||
if (ingredient.id === e.id) {
|
|
||||||
this.$set(ingredient, "checked", !ingredient.checked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
quickSwitch: function (e) {
|
|
||||||
if (e === -1) {
|
|
||||||
this.recipe = this.rootrecipe
|
|
||||||
this.servings = this.servings_cache[this.rootrecipe?.id ?? 1]
|
|
||||||
} else {
|
|
||||||
this.recipe = e
|
|
||||||
this.servings = this.servings_cache?.[e.id] ?? e.servings
|
|
||||||
}
|
|
||||||
},
|
|
||||||
printReady: function () {
|
|
||||||
const template = document.createElement("template");
|
|
||||||
template.id = "printReady";
|
|
||||||
document.body.appendChild(template);
|
|
||||||
},
|
|
||||||
onImgLoad: function () {
|
|
||||||
this.printReady()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
methods: {},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#app > div > div {
|
|
||||||
break-inside: avoid;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -164,6 +164,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h4>{{ $t('Open_Data_Import') }}</h4>
|
||||||
|
<open-data-import-component></open-data-import-component>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col col-12">
|
<div class="col col-12">
|
||||||
<h4 class="mt-2"><i class="fas fa-trash"></i> {{ $t('Delete') }}</h4>
|
<h4 class="mt-2"><i class="fas fa-trash"></i> {{ $t('Delete') }}</h4>
|
||||||
@@ -198,6 +207,7 @@ import GenericMultiselect from "@/components/GenericMultiselect";
|
|||||||
import GenericModalForm from "@/components/Modals/GenericModalForm";
|
import GenericModalForm from "@/components/Modals/GenericModalForm";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import VueClipboard from 'vue-clipboard2'
|
import VueClipboard from 'vue-clipboard2'
|
||||||
|
import OpenDataImportComponent from "@/components/OpenDataImportComponent.vue";
|
||||||
|
|
||||||
Vue.use(VueClipboard)
|
Vue.use(VueClipboard)
|
||||||
|
|
||||||
@@ -206,7 +216,7 @@ Vue.use(BootstrapVue)
|
|||||||
export default {
|
export default {
|
||||||
name: "SpaceManageView",
|
name: "SpaceManageView",
|
||||||
mixins: [ResolveUrlMixin, ToastMixin, ApiMixin],
|
mixins: [ResolveUrlMixin, ToastMixin, ApiMixin],
|
||||||
components: {GenericMultiselect, GenericModalForm},
|
components: {GenericMultiselect, GenericModalForm, OpenDataImportComponent},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ACTIVE_SPACE_ID: window.ACTIVE_SPACE_ID,
|
ACTIVE_SPACE_ID: window.ACTIVE_SPACE_ID,
|
||||||
|
|||||||
@@ -1,104 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div class="row" v-if="food">
|
|
||||||
<div class="col-12">
|
<beta-warning></beta-warning>
|
||||||
<h2>{{ food.name }}</h2>
|
|
||||||
</div>
|
<div v-if="metadata !== undefined">
|
||||||
|
{{ $t('Data_Import_Info') }}
|
||||||
|
|
||||||
|
|
||||||
|
<select class="form-control" v-model="selected_version">
|
||||||
|
<option v-for="v in metadata.versions" v-bind:key="v">{{ v }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<b-checkbox v-model="update_existing" class="mt-1">{{ $t('Update_Existing_Data') }}</b-checkbox>
|
||||||
|
<b-checkbox v-model="use_metric" class="mt-1">{{ $t('Use_Metric') }}</b-checkbox>
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="selected_version !== undefined" class="mt-3">
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th>{{ $t('Datatype') }}</th>
|
||||||
|
<th>{{ $t('Number of Objects') }}</th>
|
||||||
|
<th>{{ $t('Imported') }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="d in metadata.datatypes" v-bind:key="d">
|
||||||
|
<td>{{ $t(d.charAt(0).toUpperCase() + d.slice(1)) }}</td>
|
||||||
|
<td>{{ metadata[selected_version][d] }}</td>
|
||||||
|
<td>
|
||||||
|
<template v-if="import_count !== undefined">{{ import_count[d] }}</template>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button class="btn btn-success" @click="doImport">{{ $t('Import') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<b-form v-if="food">
|
|
||||||
<b-form-group :label="$t('Name')" description="">
|
|
||||||
<b-form-input v-model="food.name"></b-form-input>
|
|
||||||
</b-form-group>
|
|
||||||
<b-form-group :label="$t('Plural')" description="">
|
|
||||||
<b-form-input v-model="food.plural_name"></b-form-input>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
|
|
||||||
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.recipe = $event.val;"
|
|
||||||
:model="Models.RECIPE"
|
|
||||||
:initial_selection="food.recipe"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:placeholder="$t('Recipe')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :description="$t('OnHand_help')">
|
|
||||||
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :description="$t('ignore_shopping_help')">
|
|
||||||
<b-form-checkbox v-model="food.ignore_shopping">{{ $t('Ignore_Shopping') }}</b-form-checkbox>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.supermarket_category = $event.val;"
|
|
||||||
:model="Models.SHOPPING_CATEGORY"
|
|
||||||
:initial_selection="food.supermarket_category"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:placeholder="$t('Shopping_Category')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
<!-- todo add conditions if false disable dont hide -->
|
|
||||||
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.substitute = $event.val;"
|
|
||||||
:model="Models.FOOD"
|
|
||||||
:initial_selection="food.substitute"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:placeholder="$t('Substitutes')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :description="$t('substitute_siblings_help')">
|
|
||||||
<b-form-checkbox v-model="food.substitute_siblings">{{ $t('substitute_siblings') }}</b-form-checkbox>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.inherit_fields = $event.val;"
|
|
||||||
:model="Models.FOOD_INHERIT_FIELDS"
|
|
||||||
:initial_selection="food.inherit_fields"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:placeholder="$t('InheritFields')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-group :label="$t('ChildInheritFields')" :description="$t('ChildInheritFields_help')">
|
|
||||||
<generic-multiselect
|
|
||||||
@change="food.child_inherit_fields = $event.val;"
|
|
||||||
:model="Models.FOOD_INHERIT_FIELDS"
|
|
||||||
:initial_selection="food.child_inherit_fields"
|
|
||||||
label="name"
|
|
||||||
:multiple="false"
|
|
||||||
:placeholder="$t('ChildInheritFields')"
|
|
||||||
></generic-multiselect>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<!-- TODO change to a button -->
|
|
||||||
<b-form-group :description="$t('reset_children_help')">
|
|
||||||
<b-form-checkbox v-model="food.reset_inherit">{{ $t('reset_children') }}</b-form-checkbox>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
|
|
||||||
</b-form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -107,10 +45,9 @@ import Vue from "vue"
|
|||||||
import {BootstrapVue} from "bootstrap-vue"
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
|
|
||||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
import {ApiApiFactory} from "@/utils/openapi/api";
|
import {ApiMixin, resolveDjangoUrl, StandardToasts} from "@/utils/utils";
|
||||||
import RecipeCard from "@/components/RecipeCard.vue";
|
import axios from "axios";
|
||||||
import GenericMultiselect from "@/components/GenericMultiselect.vue";
|
import BetaWarning from "@/components/BetaWarning.vue";
|
||||||
import {ApiMixin, StandardToasts} from "@/utils/utils";
|
|
||||||
|
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
@@ -119,33 +56,39 @@ Vue.use(BootstrapVue)
|
|||||||
export default {
|
export default {
|
||||||
name: "TestView",
|
name: "TestView",
|
||||||
mixins: [ApiMixin],
|
mixins: [ApiMixin],
|
||||||
components: {
|
components: {BetaWarning},
|
||||||
GenericMultiselect
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
food: undefined,
|
metadata: undefined,
|
||||||
|
selected_version: undefined,
|
||||||
|
update_existing: true,
|
||||||
|
use_metric: true,
|
||||||
|
import_count: undefined,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
let apiClient = new ApiApiFactory()
|
|
||||||
apiClient.retrieveFood('1').then((r) => {
|
|
||||||
this.food = r.data
|
|
||||||
})
|
|
||||||
|
|
||||||
|
axios.get(resolveDjangoUrl('api_import_open_data')).then(r => {
|
||||||
|
this.metadata = r.data
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateFood: function () {
|
doImport: function () {
|
||||||
let apiClient = new ApiApiFactory()
|
axios.post(resolveDjangoUrl('api_import_open_data'), {
|
||||||
apiClient.updateFood(this.food.id, this.food).then((r) => {
|
'selected_version': this.selected_version,
|
||||||
this.food = r.data
|
'selected_datatypes': this.metadata.datatypes,
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
'update_existing': this.update_existing,
|
||||||
|
'use_metric': this.use_metric,
|
||||||
|
}).then(r => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
||||||
|
this.import_count = r.data
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
155
vue/src/apps/TestView/TestViewBackup.vue
Normal file
155
vue/src/apps/TestView/TestViewBackup.vue
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<div class="row" v-if="food">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2>{{ food.name }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<b-form v-if="food">
|
||||||
|
<b-form-group :label="$t('Name')" description="">
|
||||||
|
<b-form-input v-model="food.name"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-group :label="$t('Plural')" description="">
|
||||||
|
<b-form-input v-model="food.plural_name"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.recipe = $event.val;"
|
||||||
|
:model="Models.RECIPE"
|
||||||
|
:initial_selection="food.recipe"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('Recipe')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('OnHand_help')">
|
||||||
|
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('ignore_shopping_help')">
|
||||||
|
<b-form-checkbox v-model="food.ignore_shopping">{{ $t('Ignore_Shopping') }}</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.supermarket_category = $event.val;"
|
||||||
|
:model="Models.SHOPPING_CATEGORY"
|
||||||
|
:initial_selection="food.supermarket_category"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('Shopping_Category')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<!-- todo add conditions if false disable dont hide -->
|
||||||
|
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.substitute = $event.val;"
|
||||||
|
:model="Models.FOOD"
|
||||||
|
:initial_selection="food.substitute"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('Substitutes')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('substitute_siblings_help')">
|
||||||
|
<b-form-checkbox v-model="food.substitute_siblings">{{ $t('substitute_siblings') }}</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.inherit_fields = $event.val;"
|
||||||
|
:model="Models.FOOD_INHERIT_FIELDS"
|
||||||
|
:initial_selection="food.inherit_fields"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('InheritFields')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('ChildInheritFields')" :description="$t('ChildInheritFields_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.child_inherit_fields = $event.val;"
|
||||||
|
:model="Models.FOOD_INHERIT_FIELDS"
|
||||||
|
:initial_selection="food.child_inherit_fields"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('ChildInheritFields')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- TODO change to a button -->
|
||||||
|
<b-form-group :description="$t('reset_children_help')">
|
||||||
|
<b-form-checkbox v-model="food.reset_inherit">{{ $t('reset_children') }}</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
|
||||||
|
</b-form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from "vue"
|
||||||
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
|
|
||||||
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
import {ApiApiFactory} from "@/utils/openapi/api";
|
||||||
|
import RecipeCard from "@/components/RecipeCard.vue";
|
||||||
|
import GenericMultiselect from "@/components/GenericMultiselect.vue";
|
||||||
|
import {ApiMixin, StandardToasts} from "@/utils/utils";
|
||||||
|
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TestView",
|
||||||
|
mixins: [ApiMixin],
|
||||||
|
components: {
|
||||||
|
GenericMultiselect
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
food: undefined,
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
apiClient.retrieveFood('1').then((r) => {
|
||||||
|
this.food = r.data
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateFood: function () {
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
apiClient.updateFood(this.food.id, this.food).then((r) => {
|
||||||
|
this.food = r.data
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- bottom button nav -->
|
<!-- bottom button nav -->
|
||||||
<div class="fixed-bottom p-1 pt-2 pl-2 pr-2 border-top text-center d-lg-none" style="background: white">
|
<div class="fixed-bottom p-1 pt-2 pl-2 pr-2 border-top text-center d-lg-none d-print-none" style="background: white">
|
||||||
<div class="d-flex flex-row justify-content-around">
|
<div class="d-flex flex-row justify-content-around">
|
||||||
<div class="flex-column" v-if="show_button_1">
|
<div class="flex-column" v-if="show_button_1">
|
||||||
<slot name="button_1">
|
<slot name="button_1">
|
||||||
|
|||||||
412
vue/src/components/FoodEditor.vue
Normal file
412
vue/src/components/FoodEditor.vue
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<b-modal :id="id" size="xl" @hidden="cancelAction" :body-class="`pr-3 pl-3`">
|
||||||
|
|
||||||
|
<template v-slot:modal-title>
|
||||||
|
<div class="row" v-if="food">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2>{{ food.name }} <small class="text-muted" v-if="food.plural_name">{{
|
||||||
|
food.plural_name
|
||||||
|
}}</small>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<b-tabs content-class="mt-3" v-if="food">
|
||||||
|
<b-tab title="General" active>
|
||||||
|
<b-form>
|
||||||
|
<b-form-group :label="$t('Name')" description="">
|
||||||
|
<b-form-input v-model="food.name"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-group :label="$t('Plural')" description="">
|
||||||
|
<b-form-input v-model="food.plural_name"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- Food properties -->
|
||||||
|
|
||||||
|
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Properties Food Amount')" description=""> <!-- TODO localize -->
|
||||||
|
<b-form-input v-model="food.properties_food_amount"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Properties Food Unit')" description=""> <!-- TODO localize -->
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.properties_food_unit = $event.val;"
|
||||||
|
:model="Models.UNIT"
|
||||||
|
:initial_single_selection="food.properties_food_unit"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('Unit')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> {{ $t('Property Amount') }}</th> <!-- TODO localize -->
|
||||||
|
<th> {{ $t('Property Type') }}</th> <!-- TODO localize -->
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="fp in food.properties" v-bind:key="fp.id">
|
||||||
|
<td><input v-model="fp.property_amount" type="number"> <span
|
||||||
|
v-if="fp.property_type">{{ fp.property_type.unit }}</span></td>
|
||||||
|
<td>
|
||||||
|
<generic-multiselect
|
||||||
|
@change="fp.property_type = $event.val"
|
||||||
|
:initial_single_selection="fp.property_type"
|
||||||
|
label="name" :model="Models.PROPERTY_TYPE"
|
||||||
|
:multiple="false"/>
|
||||||
|
</td>
|
||||||
|
<td> / <span>{{ food.properties_food_amount }} <span
|
||||||
|
v-if="food.properties_food_unit !== null">{{
|
||||||
|
food.properties_food_unit.name
|
||||||
|
}}</span></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
|
||||||
|
class="fas fa-trash-alt"></i></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<b-button-group>
|
||||||
|
<b-btn class="btn btn-success shadow-none" @click="addProperty()"><i
|
||||||
|
class="fa fa-plus"></i>
|
||||||
|
</b-btn>
|
||||||
|
<b-btn class="btn btn-secondary shadow-none" @click="addAllProperties()"><i
|
||||||
|
class="fa fa-plus"> <i class="ml-1 fas fa-list"></i></i>
|
||||||
|
</b-btn>
|
||||||
|
</b-button-group>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.supermarket_category = $event.val;"
|
||||||
|
:model="Models.SHOPPING_CATEGORY"
|
||||||
|
:initial_single_selection="food.supermarket_category"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:allow_create="true"
|
||||||
|
:placeholder="$t('Shopping_Category')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
|
||||||
|
</b-form>
|
||||||
|
</b-tab>
|
||||||
|
<b-tab title="Conversions" @click="loadUnitConversions" v-if="this.food.id !== undefined">
|
||||||
|
|
||||||
|
<b-row v-for="uc in unit_conversions" :key="uc">
|
||||||
|
<b-col>
|
||||||
|
<span v-if="uc.id">
|
||||||
|
<b-btn class="btn btn-sm" variant="danger" @click="deleteUnitConversion(uc)"><i class="fas fa-trash-alt"></i></b-btn>
|
||||||
|
{{ uc.base_amount }}
|
||||||
|
{{ uc.base_unit.name }}
|
||||||
|
=
|
||||||
|
{{ uc.converted_amount }}
|
||||||
|
{{ uc.converted_unit.name }}
|
||||||
|
</span>
|
||||||
|
<b-form class="mt-1">
|
||||||
|
<b-input-group>
|
||||||
|
<b-input v-model="uc.base_amount" @change="uc.changed = true"></b-input>
|
||||||
|
<b-input-group-append>
|
||||||
|
<generic-multiselect
|
||||||
|
@change="uc.base_unit = $event.val; uc.changed = true"
|
||||||
|
:initial_single_selection="uc.base_unit"
|
||||||
|
label="name" :model="Models.UNIT"
|
||||||
|
:multiple="false"/>
|
||||||
|
</b-input-group-append>
|
||||||
|
|
||||||
|
</b-input-group>
|
||||||
|
|
||||||
|
<b-input-group>
|
||||||
|
<b-input v-model="uc.converted_amount" @change="uc.changed = true"></b-input>
|
||||||
|
<b-input-group-append>
|
||||||
|
<generic-multiselect
|
||||||
|
@change="uc.converted_unit = $event.val; uc.changed = true"
|
||||||
|
:initial_single_selection="uc.converted_unit"
|
||||||
|
label="name" :model="Models.UNIT"
|
||||||
|
:multiple="false"/>
|
||||||
|
</b-input-group-append>
|
||||||
|
</b-input-group>
|
||||||
|
|
||||||
|
</b-form>
|
||||||
|
</b-col>
|
||||||
|
<hr style="height: 1px"/>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-center">
|
||||||
|
<b-btn variant="success" @click="addUnitConversion"><i class="fa fa-plus"></i></b-btn>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
</b-tab>
|
||||||
|
<b-tab title="More">
|
||||||
|
<b-form>
|
||||||
|
|
||||||
|
|
||||||
|
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.recipe = $event.val;"
|
||||||
|
:model="Models.RECIPE"
|
||||||
|
:initial_single_selection="food.recipe"
|
||||||
|
label="name"
|
||||||
|
:multiple="false"
|
||||||
|
:placeholder="$t('Recipe')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('OnHand_help')">
|
||||||
|
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('ignore_shopping_help')">
|
||||||
|
<b-form-checkbox v-model="food.ignore_shopping">{{
|
||||||
|
$t('Ignore_Shopping')
|
||||||
|
}}
|
||||||
|
</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<!-- todo add conditions if false disable dont hide -->
|
||||||
|
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.substitute = $event.val;"
|
||||||
|
:model="Models.FOOD"
|
||||||
|
:initial_selection="food.substitute"
|
||||||
|
label="name"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('Substitutes')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :description="$t('substitute_siblings_help')">
|
||||||
|
<b-form-checkbox v-model="food.substitute_siblings">{{
|
||||||
|
$t('substitute_siblings')
|
||||||
|
}}
|
||||||
|
</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.inherit_fields = $event.val;"
|
||||||
|
:model="Models.FOOD_INHERIT_FIELDS"
|
||||||
|
:initial_selection="food.inherit_fields"
|
||||||
|
label="name"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('InheritFields')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<b-form-group :label="$t('ChildInheritFields')"
|
||||||
|
:description="$t('ChildInheritFields_help')">
|
||||||
|
<generic-multiselect
|
||||||
|
@change="food.child_inherit_fields = $event.val;"
|
||||||
|
:model="Models.FOOD_INHERIT_FIELDS"
|
||||||
|
:initial_sselection="food.child_inherit_fields"
|
||||||
|
label="name"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="$t('ChildInheritFields')"
|
||||||
|
></generic-multiselect>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- TODO change to a button -->
|
||||||
|
<b-form-group :description="$t('reset_children_help')">
|
||||||
|
<b-form-checkbox v-model="food.reset_inherit">{{
|
||||||
|
$t('reset_children')
|
||||||
|
}}
|
||||||
|
</b-form-checkbox>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
|
||||||
|
</b-form>
|
||||||
|
</b-tab>
|
||||||
|
</b-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-slot:modal-footer>
|
||||||
|
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
|
||||||
|
</template>
|
||||||
|
</b-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from "vue"
|
||||||
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
|
|
||||||
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
import {ApiApiFactory} from "@/utils/openapi/api";
|
||||||
|
import GenericMultiselect from "@/components/GenericMultiselect.vue";
|
||||||
|
import {ApiMixin, formFunctions, getForm, StandardToasts} from "@/utils/utils";
|
||||||
|
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "FoodEditor",
|
||||||
|
mixins: [ApiMixin],
|
||||||
|
components: {
|
||||||
|
GenericMultiselect
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
id: {type: String, default: 'id_food_edit_modal_modal'},
|
||||||
|
show: {required: true, type: Boolean, default: false},
|
||||||
|
item1: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
show: function () {
|
||||||
|
if (this.show) {
|
||||||
|
this.$bvModal.show(this.id)
|
||||||
|
} else {
|
||||||
|
this.$bvModal.hide(this.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
food: undefined,
|
||||||
|
unit_conversions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$bvModal.show(this.id)
|
||||||
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
let pf
|
||||||
|
if (this.item1.id !== undefined) {
|
||||||
|
pf = apiClient.retrieveFood(this.item1.id).then((r) => {
|
||||||
|
this.food = r.data
|
||||||
|
this.food.properties_food_unit = {name: 'g'}
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.food = {
|
||||||
|
name: "",
|
||||||
|
plural_name: "",
|
||||||
|
description: "",
|
||||||
|
shopping: false,
|
||||||
|
recipe: null,
|
||||||
|
properties: [],
|
||||||
|
properties_food_amount: 100,
|
||||||
|
properties_food_unit: {name: 'g'},
|
||||||
|
food_onhand: false,
|
||||||
|
supermarket_category: null,
|
||||||
|
parent: null,
|
||||||
|
numchild: 0,
|
||||||
|
inherit_fields: [],
|
||||||
|
ignore_shopping: false,
|
||||||
|
substitute: [],
|
||||||
|
substitute_siblings: false,
|
||||||
|
substitute_children: false,
|
||||||
|
substitute_onhand: false,
|
||||||
|
child_inherit_fields: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateFood: function () {
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
if (this.food.id !== undefined) {
|
||||||
|
apiClient.updateFood(this.food.id, this.food).then((r) => {
|
||||||
|
this.food = r.data
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
apiClient.createFood(this.food).then((r) => {
|
||||||
|
this.food = r.data
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unit_conversions.forEach(uc => {
|
||||||
|
if (uc.changed === true) {
|
||||||
|
if (uc.id === undefined) {
|
||||||
|
apiClient.createUnitConversion(uc).then(r => {
|
||||||
|
uc = r.data
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err, true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
apiClient.updateUnitConversion(uc.id, uc).then(r => {
|
||||||
|
uc = r.data
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addProperty: function () {
|
||||||
|
this.food.properties.push({property_type: null, property_amount: 0})
|
||||||
|
},
|
||||||
|
addAllProperties: function () {
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
apiClient.listPropertyTypes().then(r => {
|
||||||
|
r.data.forEach(x => {
|
||||||
|
this.food.properties.push({property_type: x, property_amount: 0})
|
||||||
|
})
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteProperty: function (p) {
|
||||||
|
this.food.properties = this.food.properties.filter(x => x !== p)
|
||||||
|
},
|
||||||
|
cancelAction: function () {
|
||||||
|
this.$emit("hidden", "")
|
||||||
|
},
|
||||||
|
loadUnitConversions: function () {
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
apiClient.listUnitConversions(this.food.id).then(r => {
|
||||||
|
this.unit_conversions = r.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addUnitConversion: function () {
|
||||||
|
this.unit_conversions.push(
|
||||||
|
{
|
||||||
|
food: this.food,
|
||||||
|
base_amount: 1,
|
||||||
|
base_unit: null,
|
||||||
|
converted_amount: 0,
|
||||||
|
converted_unit: null,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
deleteUnitConversion: function (uc) {
|
||||||
|
this.unit_conversions = this.unit_conversions.filter(u => u !== uc)
|
||||||
|
let apiClient = new ApiApiFactory()
|
||||||
|
apiClient.destroyUnitConversion(uc.id).then(r => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<span class="pl-1" v-if="recipe.last_cooked !== null">
|
<span class="pl-1" v-if="recipe.last_cooked !== undefined && recipe.last_cooked !== null">
|
||||||
<b-badge pill variant="primary" class="font-weight-normal"><i class="fas fa-utensils"></i> {{
|
<b-badge pill variant="primary" class="font-weight-normal"><i class="fas fa-utensils"></i> {{
|
||||||
formatDate(recipe.last_cooked)
|
formatDate(recipe.last_cooked)
|
||||||
}}</b-badge>
|
}}</b-badge>
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-modal :id="'modal_' + id" @hidden="cancelAction">
|
<template v-if="form_component !== undefined">
|
||||||
|
<component :is="form_component" :id="'modal_' + id" :show="show" @hidden="cancelAction" :item1="item1"></component>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<b-modal :id="'modal_' + id" @hidden="cancelAction" size="lg">
|
||||||
<template v-slot:modal-title>
|
<template v-slot:modal-title>
|
||||||
<h4 class="d-inline">{{ form.title }}</h4>
|
<h4 class="d-inline">{{ form.title }}</h4>
|
||||||
<help-badge v-if="form.show_help" @show="show_help = true" @hide="show_help = false" :component="`GenericModal${form.title}`"/>
|
<help-badge v-if="form.show_help" @show="show_help = true" @hide="show_help = false" :component="`GenericModal${form.title}`"/>
|
||||||
@@ -9,7 +13,7 @@
|
|||||||
<p v-if="visibleCondition(f, 'instruction')">{{ f.label }}</p>
|
<p v-if="visibleCondition(f, 'instruction')">{{ f.label }}</p>
|
||||||
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help"/>
|
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help"/>
|
||||||
<checkbox-input class="mb-3" v-if="visibleCondition(f, 'checkbox')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help"/>
|
<checkbox-input class="mb-3" v-if="visibleCondition(f, 'checkbox')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help"/>
|
||||||
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" />
|
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled"/>
|
||||||
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder"/>
|
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder"/>
|
||||||
<emoji-input v-if="visibleCondition(f, 'emoji')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
<emoji-input v-if="visibleCondition(f, 'emoji')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
||||||
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue"/>
|
||||||
@@ -29,6 +33,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</b-modal>
|
</b-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -54,7 +60,18 @@ import NumberInput from "@/components/Modals/NumberInput.vue";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "GenericModalForm",
|
name: "GenericModalForm",
|
||||||
components: { FileInput, CheckboxInput, LookupInput, TextInput, EmojiInput, ChoiceInput, SmallText, HelpBadge,DateInput, NumberInput },
|
components: {
|
||||||
|
FileInput,
|
||||||
|
CheckboxInput,
|
||||||
|
LookupInput,
|
||||||
|
TextInput,
|
||||||
|
EmojiInput,
|
||||||
|
ChoiceInput,
|
||||||
|
SmallText,
|
||||||
|
HelpBadge,
|
||||||
|
DateInput,
|
||||||
|
NumberInput
|
||||||
|
},
|
||||||
mixins: [ApiMixin, ToastMixin],
|
mixins: [ApiMixin, ToastMixin],
|
||||||
props: {
|
props: {
|
||||||
model: {required: true, type: Object},
|
model: {required: true, type: Object},
|
||||||
@@ -77,6 +94,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
show: {required: true, type: Boolean, default: false},
|
show: {required: true, type: Boolean, default: false},
|
||||||
|
models: {required: false, type: Function, default: null}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -92,6 +110,10 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.id = Math.random()
|
this.id = Math.random()
|
||||||
this.$root.$on("change", this.storeValue) // bootstrap modal placed at document so have to listen at root of component
|
this.$root.$on("change", this.storeValue) // bootstrap modal placed at document so have to listen at root of component
|
||||||
|
|
||||||
|
if (this.models !== null) {
|
||||||
|
this.Models = this.models // override models definition file with prop
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
advancedForm() {
|
advancedForm() {
|
||||||
@@ -111,6 +133,15 @@ export default {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
form_component() {
|
||||||
|
// TODO this leads webpack to create one .js file for each component in this folder because at runtime any one of them could be requested
|
||||||
|
// TODO this is not necessarily bad but maybe there are better options to do this
|
||||||
|
if (this.form.component !== undefined) {
|
||||||
|
return () => import(/* webpackChunkName: "header-component" */ `@/components/${this.form.component}`)
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
show: function () {
|
show: function () {
|
||||||
@@ -153,6 +184,7 @@ export default {
|
|||||||
if (this.dirty) {
|
if (this.dirty) {
|
||||||
this.dirty = false
|
this.dirty = false
|
||||||
this.$emit("finish-action", "cancel")
|
this.$emit("finish-action", "cancel")
|
||||||
|
this.$emit("hidden")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
storeValue: function (field, value) {
|
storeValue: function (field, value) {
|
||||||
@@ -250,7 +282,10 @@ export default {
|
|||||||
target: this.form_data.target.id,
|
target: this.form_data.target.id,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$emit("finish-action", { target: this.form_data.target.id, target_object: this.form_data.target }) //TODO temporary workaround to not change other apis
|
this.$emit("finish-action", {
|
||||||
|
target: this.form_data.target.id,
|
||||||
|
target_object: this.form_data.target
|
||||||
|
}) //TODO temporary workaround to not change other apis
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_MERGE)
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_MERGE)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-form-group v-bind:label="label" class="mb-3">
|
<b-form-group v-bind:label="label" class="mb-3">
|
||||||
<b-form-input v-model="new_value" type="text" :placeholder="placeholder"></b-form-input>
|
<b-form-input v-model="new_value" type="text" :placeholder="placeholder" :disabled="disabled"></b-form-input>
|
||||||
<em v-if="help" class="small text-muted">{{ help }}</em>
|
<em v-if="help" class="small text-muted">{{ help }}</em>
|
||||||
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
@@ -18,6 +18,7 @@ export default {
|
|||||||
placeholder: { type: String, default: "You Should Add Placeholder Text" },
|
placeholder: { type: String, default: "You Should Add Placeholder Text" },
|
||||||
help: { type: String, default: undefined },
|
help: { type: String, default: undefined },
|
||||||
subtitle: { type: String, default: undefined },
|
subtitle: { type: String, default: undefined },
|
||||||
|
disabled: { type: Boolean, default: false }
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
94
vue/src/components/OpenDataImportComponent.vue
Normal file
94
vue/src/components/OpenDataImportComponent.vue
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<beta-warning></beta-warning>
|
||||||
|
|
||||||
|
<div v-if="metadata !== undefined">
|
||||||
|
{{ $t('Data_Import_Info') }}
|
||||||
|
<a href="https://github.com/TandoorRecipes/open-tandoor-data" target="_blank" rel="noreferrer nofollow">{{$t('Learn_More')}}</a>
|
||||||
|
|
||||||
|
|
||||||
|
<select class="form-control" v-model="selected_version">
|
||||||
|
<option v-for="v in metadata.versions" v-bind:key="v">{{ v }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<b-checkbox v-model="update_existing" class="mt-1">{{ $t('Update_Existing_Data') }}</b-checkbox>
|
||||||
|
<b-checkbox v-model="use_metric" class="mt-1">{{ $t('Use_Metric') }}</b-checkbox>
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="selected_version !== undefined" class="mt-3">
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th>{{ $t('Datatype') }}</th>
|
||||||
|
<th>{{ $t('Number of Objects') }}</th>
|
||||||
|
<th>{{ $t('Imported') }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="d in metadata.datatypes" v-bind:key="d">
|
||||||
|
<td>{{ $t(d.charAt(0).toUpperCase() + d.slice(1)) }}</td>
|
||||||
|
<td>{{ metadata[selected_version][d] }}</td>
|
||||||
|
<td>
|
||||||
|
<template v-if="import_count !== undefined">{{ import_count[d] }}</template>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button class="btn btn-success" @click="doImport">{{ $t('Import') }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from "vue"
|
||||||
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
|
|
||||||
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
import {ApiMixin, resolveDjangoUrl, StandardToasts} from "@/utils/utils";
|
||||||
|
import axios from "axios";
|
||||||
|
import BetaWarning from "@/components/BetaWarning.vue";
|
||||||
|
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "OpenDataImportComponent",
|
||||||
|
mixins: [ApiMixin],
|
||||||
|
components: {BetaWarning},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
metadata: undefined,
|
||||||
|
selected_version: undefined,
|
||||||
|
update_existing: true,
|
||||||
|
use_metric: true,
|
||||||
|
import_count: undefined,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
|
|
||||||
|
axios.get(resolveDjangoUrl('api_import_open_data')).then(r => {
|
||||||
|
this.metadata = r.data
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doImport: function () {
|
||||||
|
axios.post(resolveDjangoUrl('api_import_open_data'), {
|
||||||
|
'selected_version': this.selected_version,
|
||||||
|
'selected_datatypes': this.metadata.datatypes,
|
||||||
|
'update_existing': this.update_existing,
|
||||||
|
'use_metric': this.use_metric,
|
||||||
|
}).then(r => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
||||||
|
this.import_count = r.data
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
195
vue/src/components/PropertyViewComponent.vue
Normal file
195
vue/src/components/PropertyViewComponent.vue
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card p-4 pb-2" v-if="recipe !== undefined">
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
|
||||||
|
</b-col>
|
||||||
|
<b-col class="text-right">
|
||||||
|
<span v-if="!show_total">{{ $t('per_serving') }} </span>
|
||||||
|
<span v-if="show_total">{{ $t('total') }} </span>
|
||||||
|
|
||||||
|
<a href="#" @click="show_total = !show_total">
|
||||||
|
<i class="fas fa-toggle-on" v-if="!show_total"></i>
|
||||||
|
<i class="fas fa-toggle-off" v-if="show_total"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div v-if="hasRecipeProperties && hasFoodProperties">
|
||||||
|
<span v-if="!show_recipe_properties">{{ $t('Food') }} </span>
|
||||||
|
<span v-if="show_recipe_properties">{{ $t('Recipe') }} </span>
|
||||||
|
|
||||||
|
<a href="#" @click="show_recipe_properties = !show_recipe_properties">
|
||||||
|
<i class="fas fa-toggle-on" v-if="!show_recipe_properties"></i>
|
||||||
|
<i class="fas fa-toggle-off" v-if="show_recipe_properties"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="table table-bordered table-sm">
|
||||||
|
|
||||||
|
<tr v-for="p in property_list" v-bind:key="`id_${p.id}`">
|
||||||
|
<td>
|
||||||
|
|
||||||
|
{{ p.icon }} {{ p.name }}
|
||||||
|
</td>
|
||||||
|
<td class="text-right">{{ get_amount(p.property_amount) }}</td>
|
||||||
|
<td class=""> {{ p.unit }}</td>
|
||||||
|
|
||||||
|
<td class="align-middle text-center" v-if="!show_recipe_properties">
|
||||||
|
<a href="#" @click="selected_property = p">
|
||||||
|
<i v-if="p.missing_value" class="text-warning fas fa-exclamation-triangle"></i>
|
||||||
|
<i v-if="!p.missing_value" class="text-muted fas fa-info-circle"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<b-modal id="id_modal_property_overview" :title="selected_property.name" v-model="show_modal" v-if="selected_property !== undefined"
|
||||||
|
@hidden="selected_property = undefined">
|
||||||
|
<template v-if="selected_property !== undefined">
|
||||||
|
{{ selected_property.description }}
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tr v-for="f in selected_property.food_values"
|
||||||
|
v-bind:key="`id_${selected_property.id}_food_${f.id}`">
|
||||||
|
<td><a href="#" @click="openFoodEditModal(f)">{{ f.food }}</a></td>
|
||||||
|
<td>{{ f.value }} {{ selected_property.unit }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</b-modal>
|
||||||
|
|
||||||
|
<generic-modal-form
|
||||||
|
:model="Models.FOOD"
|
||||||
|
:action="Actions.UPDATE"
|
||||||
|
:item1="selected_food"
|
||||||
|
:show="show_food_edit_modal"
|
||||||
|
@hidden="foodEditorHidden"
|
||||||
|
>
|
||||||
|
</generic-modal-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ApiMixin, StandardToasts} from "@/utils/utils";
|
||||||
|
import GenericModalForm from "@/components/Modals/GenericModalForm.vue";
|
||||||
|
import {ApiApiFactory} from "@/utils/openapi/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PropertyViewComponent",
|
||||||
|
mixins: [ApiMixin],
|
||||||
|
components: {GenericModalForm},
|
||||||
|
props: {
|
||||||
|
recipe: Object,
|
||||||
|
servings: Number,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selected_property: undefined,
|
||||||
|
selected_food: undefined,
|
||||||
|
show_food_edit_modal: false,
|
||||||
|
show_total: false,
|
||||||
|
show_recipe_properties: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show_modal: function () {
|
||||||
|
return this.selected_property !== undefined
|
||||||
|
},
|
||||||
|
hasRecipeProperties: function () {
|
||||||
|
return this.recipe.properties.length !== 0
|
||||||
|
},
|
||||||
|
hasFoodProperties: function () {
|
||||||
|
let has_food_properties = false
|
||||||
|
for (const [key, fp] of Object.entries(this.recipe.food_properties)) {
|
||||||
|
if (fp.total_value !== 0) {
|
||||||
|
has_food_properties = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return has_food_properties
|
||||||
|
},
|
||||||
|
property_list: function () {
|
||||||
|
let pt_list = []
|
||||||
|
if (this.show_recipe_properties) {
|
||||||
|
this.recipe.properties.forEach(rp => {
|
||||||
|
pt_list.push(
|
||||||
|
{
|
||||||
|
'id': rp.property_type.id,
|
||||||
|
'name': rp.property_type.name,
|
||||||
|
'description': rp.property_type.description,
|
||||||
|
'icon': rp.property_type.icon,
|
||||||
|
'food_values': [],
|
||||||
|
'property_amount': rp.property_amount,
|
||||||
|
'missing_value': false,
|
||||||
|
'unit': rp.property_type.unit,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
for (const [key, fp] of Object.entries(this.recipe.food_properties)) {
|
||||||
|
pt_list.push(
|
||||||
|
{
|
||||||
|
'id': fp.id,
|
||||||
|
'name': fp.name,
|
||||||
|
'description': fp.description,
|
||||||
|
'icon': fp.icon,
|
||||||
|
'food_values': fp.food_values,
|
||||||
|
'property_amount': fp.total_value,
|
||||||
|
'missing_value': fp.missing_value,
|
||||||
|
'unit': fp.unit,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pt_list
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.hasRecipeProperties && !this.hasFoodProperties) {
|
||||||
|
this.show_recipe_properties = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
get_amount: function (amount) {
|
||||||
|
if (this.show_total) {
|
||||||
|
return (amount * (this.servings / this.recipe.servings)).toLocaleString(window.CUSTOM_LOCALE, {
|
||||||
|
'maximumFractionDigits': 2,
|
||||||
|
'minimumFractionDigits': 2
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return (amount / this.recipe.servings).toLocaleString(window.CUSTOM_LOCALE, {
|
||||||
|
'maximumFractionDigits': 2,
|
||||||
|
'minimumFractionDigits': 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openFoodEditModal: function (food) {
|
||||||
|
console.log(food)
|
||||||
|
let apiClient = ApiApiFactory()
|
||||||
|
apiClient.retrieveFood(food.id).then(r => {
|
||||||
|
this.selected_food = r.data;
|
||||||
|
this.show_food_edit_modal = true
|
||||||
|
}).catch(err => {
|
||||||
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
foodEditorHidden: function () {
|
||||||
|
this.show_food_edit_modal = false;
|
||||||
|
this.$emit("foodUpdated", "")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -35,12 +35,12 @@
|
|||||||
|
|
||||||
<div class="card-img-overlay d-flex flex-column justify-content-left float-left text-left pt-2" style="width:40%"
|
<div class="card-img-overlay d-flex flex-column justify-content-left float-left text-left pt-2" style="width:40%"
|
||||||
v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
|
v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
|
||||||
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0">
|
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0 && recipe.working_time !== undefined">
|
||||||
<i
|
<i
|
||||||
class="fa fa-clock"></i> {{ working_time }}
|
class="fa fa-clock"></i> {{ working_time }}
|
||||||
</b-badge>
|
</b-badge>
|
||||||
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"
|
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"
|
||||||
v-if="recipe.waiting_time !== 0">
|
v-if="recipe.waiting_time !== 0 && recipe.waiting_time !== undefined">
|
||||||
<i class="fa fa-pause"></i> {{ waiting_time }}
|
<i class="fa fa-pause"></i> {{ waiting_time }}
|
||||||
</b-badge>
|
</b-badge>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<div class="justify-content-end">
|
<div class="justify-content-end">
|
||||||
<recipe-context-menu :recipe="recipe" class="justify-content-end float-right align-items-end pr-0"
|
<recipe-context-menu :recipe="recipe" class="justify-content-end float-right align-items-end pr-0"
|
||||||
:disabled_options="context_disabled_options"
|
:disabled_options="context_disabled_options"
|
||||||
v-if="recipe !== null"></recipe-context-menu>
|
v-if="recipe !== null && show_context_menu"></recipe-context-menu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<b-badge pill variant="info" v-if="!recipe.internal">{{ $t("External") }}</b-badge>
|
<b-badge pill variant="info" v-if="recipe.internal !== undefined && !recipe.internal">{{ $t("External") }}</b-badge>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</b-card-text>
|
</b-card-text>
|
||||||
|
|||||||
351
vue/src/components/RecipeViewComponent.vue
Normal file
351
vue/src/components/RecipeViewComponent.vue
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<template v-if="loading">
|
||||||
|
<loading-spinner></loading-spinner>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-if="!loading" style="padding-bottom: 60px">
|
||||||
|
<RecipeSwitcher ref="ref_recipe_switcher" @switch="quickSwitch($event)"/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12" style="text-align: center">
|
||||||
|
<h3>{{ recipe.name }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row text-center">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
<recipe-rating :recipe="recipe"></recipe-rating>
|
||||||
|
<last-cooked :recipe="recipe" class="mt-2"></last-cooked>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-auto">
|
||||||
|
<div class="col-12" style="text-align: center">
|
||||||
|
<i>{{ recipe.description }}</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="text-align: center">
|
||||||
|
<keywords-component :recipe="recipe"></keywords-component>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<div class="row align-items-center">
|
||||||
|
<div class="col col-md-3">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<i class="fas fa-fw fa-user-clock fa-2x text-primary"></i>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<span class="text-primary"><b>{{ $t("Preparation") }}</b></span><br/>
|
||||||
|
{{ working_time }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-3">
|
||||||
|
<div class="row d-flex">
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<i class="far fa-fw fa-clock fa-2x text-primary"></i>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<span class="text-primary"><b>{{ $t("Waiting") }}</b></span><br/>
|
||||||
|
{{ waiting_time }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-4 col-10 mt-2 mt-md-0">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<i class="fas fa-fw fa-pizza-slice fa-2x text-primary"></i>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<CustomInputSpinButton v-model.number="servings"/>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto mr-1">
|
||||||
|
<span class="text-primary">
|
||||||
|
<b>
|
||||||
|
<template v-if="recipe.servings_text === ''">{{ $t("Servings") }}</template>
|
||||||
|
<template v-else>{{ recipe.servings_text }}</template>
|
||||||
|
</b>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-2 col-2 mt-2 mt-md-0 text-right">
|
||||||
|
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"
|
||||||
|
:disabled_options="{print:false}"></recipe-context-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2"
|
||||||
|
v-if="recipe && ingredient_count > 0 && (recipe.show_ingredient_overview || recipe.steps.length < 2)">
|
||||||
|
<ingredients-card
|
||||||
|
:recipe="recipe.id"
|
||||||
|
:steps="recipe.steps"
|
||||||
|
:ingredient_factor="ingredient_factor"
|
||||||
|
:servings="servings"
|
||||||
|
:header="true"
|
||||||
|
id="ingredient_container"
|
||||||
|
@checked-state-changed="updateIngredientCheckedState"
|
||||||
|
@change-servings="servings = $event"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<img class="img img-fluid rounded" :src="recipe.image" :alt="$t('Recipe_Image')"
|
||||||
|
v-if="recipe.image !== null" @load="onImgLoad"
|
||||||
|
:style="{ 'max-height': ingredient_height }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-if="!recipe.internal">
|
||||||
|
<div v-if="recipe.file_path.includes('.pdf')">
|
||||||
|
<PdfViewer :recipe="recipe"></PdfViewer>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg') || recipe.file_path.includes('.gif')">
|
||||||
|
<ImageViewer :recipe="recipe"></ImageViewer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
|
||||||
|
<step-component
|
||||||
|
:recipe="recipe"
|
||||||
|
:step="s"
|
||||||
|
:ingredient_factor="ingredient_factor"
|
||||||
|
:index="index"
|
||||||
|
:start_time="start_time"
|
||||||
|
@update-start-time="updateStartTime"
|
||||||
|
@checked-state-changed="updateIngredientCheckedState"
|
||||||
|
></step-component>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="recipe.source_url !== null">
|
||||||
|
<h6 class="d-print-none"><i class="fas fa-file-import"></i> {{ $t("Imported_From") }}</h6>
|
||||||
|
<span class="text-muted mt-1"><a style="overflow-wrap: break-word;"
|
||||||
|
:href="recipe.source_url">{{ recipe.source_url }}</a></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top: 2vh; ">
|
||||||
|
<div class="col-lg-6 offset-lg-3 col-12">
|
||||||
|
<property-view-component :recipe="recipe" :servings="servings" @foodUpdated="loadRecipe(recipe.id)"></property-view-component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<add-recipe-to-book :recipe="recipe"></add-recipe-to-book>
|
||||||
|
|
||||||
|
<div class="row text-center d-print-none" style="margin-top: 3vh; margin-bottom: 3vh"
|
||||||
|
v-if="share_uid !== 'None' && !loading">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
<import-tandoor></import-tandoor> <br/>
|
||||||
|
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)" class="mt-3">{{ $t("Report Abuse") }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from "vue"
|
||||||
|
import {BootstrapVue} from "bootstrap-vue"
|
||||||
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
|
||||||
|
import {apiLoadRecipe} from "@/utils/api"
|
||||||
|
|
||||||
|
import RecipeContextMenu from "@/components/RecipeContextMenu"
|
||||||
|
import {ResolveUrlMixin, ToastMixin, calculateHourMinuteSplit} from "@/utils/utils"
|
||||||
|
|
||||||
|
import PdfViewer from "@/components/PdfViewer"
|
||||||
|
import ImageViewer from "@/components/ImageViewer"
|
||||||
|
|
||||||
|
import moment from "moment"
|
||||||
|
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||||
|
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook"
|
||||||
|
import RecipeRating from "@/components/RecipeRating"
|
||||||
|
import LastCooked from "@/components/LastCooked"
|
||||||
|
import IngredientsCard from "@/components/IngredientsCard"
|
||||||
|
import StepComponent from "@/components/StepComponent"
|
||||||
|
import KeywordsComponent from "@/components/KeywordsComponent"
|
||||||
|
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
|
||||||
|
import CustomInputSpinButton from "@/components/CustomInputSpinButton"
|
||||||
|
import {ApiApiFactory} from "@/utils/openapi/api";
|
||||||
|
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
|
||||||
|
import PropertyViewComponent from "@/components/PropertyViewComponent.vue";
|
||||||
|
|
||||||
|
Vue.prototype.moment = moment
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RecipeView",
|
||||||
|
mixins: [ResolveUrlMixin, ToastMixin],
|
||||||
|
components: {
|
||||||
|
ImportTandoor,
|
||||||
|
LastCooked,
|
||||||
|
RecipeRating,
|
||||||
|
PdfViewer,
|
||||||
|
ImageViewer,
|
||||||
|
IngredientsCard,
|
||||||
|
StepComponent,
|
||||||
|
RecipeContextMenu,
|
||||||
|
KeywordsComponent,
|
||||||
|
LoadingSpinner,
|
||||||
|
AddRecipeToBook,
|
||||||
|
RecipeSwitcher,
|
||||||
|
CustomInputSpinButton,
|
||||||
|
PropertyViewComponent,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
ingredient_factor: function () {
|
||||||
|
return this.servings / this.recipe.servings
|
||||||
|
},
|
||||||
|
ingredient_count() {
|
||||||
|
return this.recipe?.steps.map((x) => x.ingredients).flat().length
|
||||||
|
},
|
||||||
|
working_time: function () {
|
||||||
|
return calculateHourMinuteSplit(this.recipe.working_time)
|
||||||
|
},
|
||||||
|
waiting_time: function () {
|
||||||
|
return calculateHourMinuteSplit(this.recipe.waiting_time)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
recipe: undefined,
|
||||||
|
rootrecipe: undefined,
|
||||||
|
servings: 1,
|
||||||
|
servings_cache: {},
|
||||||
|
start_time: "",
|
||||||
|
share_uid: window.SHARE_UID,
|
||||||
|
wake_lock: null,
|
||||||
|
ingredient_height: '250',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
servings(newVal, oldVal) {
|
||||||
|
this.servings_cache[this.recipe.id] = this.servings
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.loadRecipe(window.RECIPE_ID)
|
||||||
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
|
this.requestWakeLock()
|
||||||
|
window.addEventListener('resize', this.handleResize);
|
||||||
|
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.destroyWakeLock()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
requestWakeLock: async function () {
|
||||||
|
if ('wakeLock' in navigator) {
|
||||||
|
try {
|
||||||
|
this.wake_lock = await navigator.wakeLock.request('screen')
|
||||||
|
document.addEventListener('visibilitychange', this.visibilityChange)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleResize: function () {
|
||||||
|
if (document.getElementById('nutrition_container') !== null) {
|
||||||
|
this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight
|
||||||
|
} else {
|
||||||
|
this.ingredient_height = document.getElementById('ingredient_container').clientHeight
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroyWakeLock: function () {
|
||||||
|
if (this.wake_lock != null) {
|
||||||
|
this.wake_lock.release()
|
||||||
|
.then(() => {
|
||||||
|
this.wake_lock = null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.removeEventListener('visibilitychange', this.visibilityChange)
|
||||||
|
},
|
||||||
|
visibilityChange: async function () {
|
||||||
|
if (this.wake_lock != null && document.visibilityState === 'visible') {
|
||||||
|
await this.requestWakeLock()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadRecipe: function (recipe_id) {
|
||||||
|
apiLoadRecipe(recipe_id).then((recipe) => {
|
||||||
|
let total_time = 0
|
||||||
|
for (let step of recipe.steps) {
|
||||||
|
for (let ingredient of step.ingredients) {
|
||||||
|
this.$set(ingredient, "checked", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
step.time_offset = total_time
|
||||||
|
total_time += step.time
|
||||||
|
}
|
||||||
|
|
||||||
|
// set start time only if there are any steps with timers (otherwise no timers are rendered)
|
||||||
|
if (total_time > 0) {
|
||||||
|
this.start_time = moment().format("yyyy-MM-DDTHH:mm")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (recipe.image === null) this.printReady()
|
||||||
|
|
||||||
|
this.recipe = this.rootrecipe = recipe
|
||||||
|
this.servings = this.servings_cache[this.rootrecipe.id] = recipe.servings
|
||||||
|
this.loading = false
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.handleResize()
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateStartTime: function (e) {
|
||||||
|
this.start_time = e
|
||||||
|
},
|
||||||
|
updateIngredientCheckedState: function (e) {
|
||||||
|
for (let step of this.recipe.steps) {
|
||||||
|
for (let ingredient of step.ingredients) {
|
||||||
|
if (ingredient.id === e.id) {
|
||||||
|
this.$set(ingredient, "checked", !ingredient.checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
quickSwitch: function (e) {
|
||||||
|
if (e === -1) {
|
||||||
|
this.recipe = this.rootrecipe
|
||||||
|
this.servings = this.servings_cache[this.rootrecipe?.id ?? 1]
|
||||||
|
} else {
|
||||||
|
this.recipe = e
|
||||||
|
this.servings = this.servings_cache?.[e.id] ?? e.servings
|
||||||
|
}
|
||||||
|
},
|
||||||
|
printReady: function () {
|
||||||
|
const template = document.createElement("template");
|
||||||
|
template.id = "printReady";
|
||||||
|
document.body.appendChild(template);
|
||||||
|
},
|
||||||
|
onImgLoad: function () {
|
||||||
|
this.printReady()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app > div > div {
|
||||||
|
break-inside: avoid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -31,22 +31,22 @@
|
|||||||
"Step_start_time": "",
|
"Step_start_time": "",
|
||||||
"Sort_by_new": "",
|
"Sort_by_new": "",
|
||||||
"Table_of_Contents": "",
|
"Table_of_Contents": "",
|
||||||
"Recipes_per_page": "",
|
"Recipes_per_page": "Receptů na stránku",
|
||||||
"Show_as_header": "",
|
"Show_as_header": "",
|
||||||
"Hide_as_header": "",
|
"Hide_as_header": "",
|
||||||
"Add_nutrition_recipe": "",
|
"Add_nutrition_recipe": "Přidat nutriční hodnoty",
|
||||||
"Remove_nutrition_recipe": "",
|
"Remove_nutrition_recipe": "Smazat nutriční hodnoty",
|
||||||
"Copy_template_reference": "",
|
"Copy_template_reference": "",
|
||||||
"Save_and_View": "",
|
"Save_and_View": "Uložit & Zobrazit",
|
||||||
"Manage_Books": "",
|
"Manage_Books": "",
|
||||||
"Meal_Plan": "",
|
"Meal_Plan": "Jídelníček",
|
||||||
"Select_Book": "",
|
"Select_Book": "",
|
||||||
"Select_File": "",
|
"Select_File": "Vybrat soubor",
|
||||||
"Recipe_Image": "",
|
"Recipe_Image": "",
|
||||||
"Import_finished": "",
|
"Import_finished": "Import dokončen",
|
||||||
"View_Recipes": "",
|
"View_Recipes": "Zobrazit recepty",
|
||||||
"Log_Cooking": "",
|
"Log_Cooking": "",
|
||||||
"New_Recipe": "",
|
"New_Recipe": "Nový recept",
|
||||||
"Url_Import": "",
|
"Url_Import": "",
|
||||||
"Reset_Search": "",
|
"Reset_Search": "",
|
||||||
"Recently_Viewed": "",
|
"Recently_Viewed": "",
|
||||||
@@ -54,21 +54,21 @@
|
|||||||
"New_Keyword": "",
|
"New_Keyword": "",
|
||||||
"Delete_Keyword": "",
|
"Delete_Keyword": "",
|
||||||
"Edit_Keyword": "",
|
"Edit_Keyword": "",
|
||||||
"Edit_Recipe": "",
|
"Edit_Recipe": "Upravit recept",
|
||||||
"Move_Keyword": "",
|
"Move_Keyword": "",
|
||||||
"Merge_Keyword": "",
|
"Merge_Keyword": "",
|
||||||
"Hide_Keywords": "",
|
"Hide_Keywords": "",
|
||||||
"Hide_Recipes": "",
|
"Hide_Recipes": "",
|
||||||
"Move_Up": "",
|
"Move_Up": "Nahoru",
|
||||||
"Move_Down": "",
|
"Move_Down": "Dolů",
|
||||||
"Step_Name": "",
|
"Step_Name": "Název kroku",
|
||||||
"Step_Type": "",
|
"Step_Type": "",
|
||||||
"Make_Header": "",
|
"Make_Header": "",
|
||||||
"Make_Ingredient": "",
|
"Make_Ingredient": "",
|
||||||
"Amount": "",
|
"Amount": "Množství",
|
||||||
"Enable_Amount": "",
|
"Enable_Amount": "Zobrazit množství",
|
||||||
"Disable_Amount": "",
|
"Disable_Amount": "Skrýt množství",
|
||||||
"Ingredient Editor": "",
|
"Ingredient Editor": "Editace ingrediencí",
|
||||||
"Description_Replace": "",
|
"Description_Replace": "",
|
||||||
"Instruction_Replace": "",
|
"Instruction_Replace": "",
|
||||||
"Auto_Sort": "",
|
"Auto_Sort": "",
|
||||||
@@ -79,8 +79,8 @@
|
|||||||
"Add_Step": "",
|
"Add_Step": "",
|
||||||
"Keywords": "",
|
"Keywords": "",
|
||||||
"Books": "",
|
"Books": "",
|
||||||
"Proteins": "",
|
"Proteins": "Proteiny",
|
||||||
"Fats": "",
|
"Fats": "Tuky",
|
||||||
"Carbohydrates": "",
|
"Carbohydrates": "",
|
||||||
"Calories": "",
|
"Calories": "",
|
||||||
"Energy": "",
|
"Energy": "",
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
"Foods": "",
|
"Foods": "",
|
||||||
"Account": "",
|
"Account": "",
|
||||||
"Cosmetic": "",
|
"Cosmetic": "",
|
||||||
"API": "",
|
"API": "API",
|
||||||
"enable_expert": "",
|
"enable_expert": "",
|
||||||
"expert_mode": "",
|
"expert_mode": "",
|
||||||
"simple_mode": "",
|
"simple_mode": "",
|
||||||
@@ -353,8 +353,8 @@
|
|||||||
"Custom Filter": "",
|
"Custom Filter": "",
|
||||||
"shared_with": "",
|
"shared_with": "",
|
||||||
"sort_by": "",
|
"sort_by": "",
|
||||||
"asc": "",
|
"asc": "Vzestupně",
|
||||||
"desc": "",
|
"desc": "Sestupně",
|
||||||
"date_viewed": "",
|
"date_viewed": "",
|
||||||
"last_cooked": "",
|
"last_cooked": "",
|
||||||
"times_cooked": "",
|
"times_cooked": "",
|
||||||
@@ -362,29 +362,29 @@
|
|||||||
"show_sortby": "",
|
"show_sortby": "",
|
||||||
"search_rank": "",
|
"search_rank": "",
|
||||||
"make_now": "",
|
"make_now": "",
|
||||||
"recipe_filter": "",
|
"recipe_filter": "Filtrovat recepty",
|
||||||
"book_filter_help": "",
|
"book_filter_help": "",
|
||||||
"review_shopping": "",
|
"review_shopping": "",
|
||||||
"view_recipe": "",
|
"view_recipe": "Zobrazit recept",
|
||||||
"copy_to_new": "",
|
"copy_to_new": "",
|
||||||
"recipe_name": "",
|
"recipe_name": "Název receptu",
|
||||||
"paste_ingredients_placeholder": "",
|
"paste_ingredients_placeholder": "",
|
||||||
"paste_ingredients": "",
|
"paste_ingredients": "",
|
||||||
"ingredient_list": "",
|
"ingredient_list": "",
|
||||||
"explain": "",
|
"explain": "",
|
||||||
"filter": "",
|
"filter": "Filtr",
|
||||||
"Website": "",
|
"Website": "Web",
|
||||||
"App": "",
|
"App": "Aplikace",
|
||||||
"Message": "",
|
"Message": "",
|
||||||
"Bookmarklet": "",
|
"Bookmarklet": "",
|
||||||
"Sticky_Nav": "",
|
"Sticky_Nav": "",
|
||||||
"Sticky_Nav_Help": "",
|
"Sticky_Nav_Help": "",
|
||||||
"Nav_Color": "",
|
"Nav_Color": "",
|
||||||
"Nav_Color_Help": "",
|
"Nav_Color_Help": "",
|
||||||
"Use_Kj": "",
|
"Use_Kj": "Používat kJ místo kcal",
|
||||||
"Comments_setting": "",
|
"Comments_setting": "Zobrazit komentáře",
|
||||||
"click_image_import": "",
|
"click_image_import": "Vyberte obrázek, který chcete přiřadit k tomuto receptu",
|
||||||
"no_more_images_found": "",
|
"no_more_images_found": "Žádné další obrázky na zadaném odkazu.",
|
||||||
"import_duplicates": "",
|
"import_duplicates": "",
|
||||||
"paste_json": "",
|
"paste_json": "",
|
||||||
"Click_To_Edit": "",
|
"Click_To_Edit": "",
|
||||||
@@ -407,9 +407,9 @@
|
|||||||
"InheritFields_help": "",
|
"InheritFields_help": "",
|
||||||
"show_ingredient_overview": "",
|
"show_ingredient_overview": "",
|
||||||
"Ingredient Overview": "",
|
"Ingredient Overview": "",
|
||||||
"last_viewed": "",
|
"last_viewed": "Naposledy zobrazeno",
|
||||||
"created_on": "",
|
"created_on": "Vytvořeno",
|
||||||
"updatedon": "",
|
"updatedon": "Upraveno",
|
||||||
"Imported_From": "",
|
"Imported_From": "",
|
||||||
"advanced_search_settings": "",
|
"advanced_search_settings": "",
|
||||||
"nothing_planned_today": "",
|
"nothing_planned_today": "",
|
||||||
@@ -418,13 +418,13 @@
|
|||||||
"Pinned": "",
|
"Pinned": "",
|
||||||
"Imported": "",
|
"Imported": "",
|
||||||
"Quick actions": "",
|
"Quick actions": "",
|
||||||
"Ratings": "",
|
"Ratings": "Hodnocení",
|
||||||
"Internal": "",
|
"Internal": "",
|
||||||
"Units": "",
|
"Units": "Jednotky",
|
||||||
"Manage_Emails": "",
|
"Manage_Emails": "",
|
||||||
"Change_Password": "",
|
"Change_Password": "Změna hesla",
|
||||||
"Social_Authentication": "",
|
"Social_Authentication": "",
|
||||||
"Random Recipes": "",
|
"Random Recipes": "Náhodné recepty",
|
||||||
"parameter_count": "",
|
"parameter_count": "",
|
||||||
"select_keyword": "",
|
"select_keyword": "",
|
||||||
"add_keyword": "",
|
"add_keyword": "",
|
||||||
@@ -436,10 +436,10 @@
|
|||||||
"empty_list": "",
|
"empty_list": "",
|
||||||
"Select": "",
|
"Select": "",
|
||||||
"Supermarkets": "",
|
"Supermarkets": "",
|
||||||
"User": "",
|
"User": "Uživatel",
|
||||||
"Username": "",
|
"Username": "Uživatelské jméno",
|
||||||
"First_name": "",
|
"First_name": "Jméno",
|
||||||
"Last_name": "",
|
"Last_name": "Příjmení",
|
||||||
"Keyword": "",
|
"Keyword": "",
|
||||||
"Advanced": "",
|
"Advanced": "",
|
||||||
"Page": "",
|
"Page": "",
|
||||||
@@ -452,15 +452,15 @@
|
|||||||
"Create Food": "",
|
"Create Food": "",
|
||||||
"create_food_desc": "",
|
"create_food_desc": "",
|
||||||
"additional_options": "",
|
"additional_options": "",
|
||||||
"Importer_Help": "",
|
"Importer_Help": "Nápověda k importu z této aplikace:",
|
||||||
"Documentation": "",
|
"Documentation": "Dokumentace",
|
||||||
"Select_App_To_Import": "",
|
"Select_App_To_Import": "Vyberte aplikaci, ze které chcete importovat",
|
||||||
"Import_Supported": "",
|
"Import_Supported": "Import podporován",
|
||||||
"Export_Supported": "",
|
"Export_Supported": "Export podporován",
|
||||||
"Import_Not_Yet_Supported": "",
|
"Import_Not_Yet_Supported": "Import není zatím podporován",
|
||||||
"Export_Not_Yet_Supported": "",
|
"Export_Not_Yet_Supported": "Export není zatím podporován",
|
||||||
"Import_Result_Info": "",
|
"Import_Result_Info": "{imported} z {total} receptů naimportováno",
|
||||||
"Recipes_In_Import": "",
|
"Recipes_In_Import": "Receptů v importním souboru",
|
||||||
"Toggle": "",
|
"Toggle": "",
|
||||||
"Import_Error": "",
|
"Import_Error": "",
|
||||||
"Warning_Delete_Supermarket_Category": "",
|
"Warning_Delete_Supermarket_Category": "",
|
||||||
@@ -477,6 +477,6 @@
|
|||||||
"Use_Plural_Food_Always": "",
|
"Use_Plural_Food_Always": "",
|
||||||
"Use_Plural_Food_Simple": "",
|
"Use_Plural_Food_Simple": "",
|
||||||
"plural_usage_info": "",
|
"plural_usage_info": "",
|
||||||
"Create Recipe": "",
|
"Create Recipe": "Vytvořit recept",
|
||||||
"Import Recipe": ""
|
"Import Recipe": "Importovat recept"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -481,5 +481,22 @@
|
|||||||
"Amount": "Menge",
|
"Amount": "Menge",
|
||||||
"Original_Text": "Originaler Text",
|
"Original_Text": "Originaler Text",
|
||||||
"Import Recipe": "Rezept importieren",
|
"Import Recipe": "Rezept importieren",
|
||||||
"Create Recipe": "Rezept erstellen"
|
"Create Recipe": "Rezept erstellen",
|
||||||
|
"recipe_property_info": "Sie können auch Eigenschaften zu Lebensmitteln hinzufügen, um sie automatisch auf der Grundlage Ihres Rezepts zu berechnen!",
|
||||||
|
"per_serving": "pro Portion",
|
||||||
|
"open_data_help_text": "Das Tandoor Open Data Projekt bietet von der Gemeinschaft bereitgestellte Daten für Tandoor. Dieses Feld wird beim Importieren automatisch ausgefüllt und ermöglicht künftige Aktualisierungen.",
|
||||||
|
"Open_Data_Import": "Datenimport öffnen",
|
||||||
|
"Update_Existing_Data": "Vorhandene Daten aktualisieren",
|
||||||
|
"Data_Import_Info": "Verbessern Sie Ihren Space, indem Sie eine von der Community kuratierte Liste von Lebensmitteln, Einheiten und mehr importieren, um Ihre Rezeptsammlung zu verbessern.",
|
||||||
|
"Learn_More": "Mehr erfahren",
|
||||||
|
"Use_Metric": "Metrische Einheiten verwenden",
|
||||||
|
"converted_unit": "Umgerechnete Einheit",
|
||||||
|
"converted_amount": "Umgerechneter Betrag",
|
||||||
|
"base_unit": "Basiseinheit",
|
||||||
|
"base_amount": "Grundbetrag",
|
||||||
|
"Datatype": "Datentyp",
|
||||||
|
"Number of Objects": "Anzahl von Objekten",
|
||||||
|
"Property": "Eigenschaft",
|
||||||
|
"Conversion": "Umrechnung",
|
||||||
|
"Properties": "Eigenschaften"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"success_moving_resource": "Successfully moved a resource!",
|
"success_moving_resource": "Successfully moved a resource!",
|
||||||
"success_merging_resource": "Successfully merged a resource!",
|
"success_merging_resource": "Successfully merged a resource!",
|
||||||
"file_upload_disabled": "File upload is not enabled for your space.",
|
"file_upload_disabled": "File upload is not enabled for your space.",
|
||||||
|
"recipe_property_info": "You can also add properties to foods to calculate them automatically based on your recipe!",
|
||||||
"warning_space_delete": "You can delete your space including all recipes, shopping lists, meal plans and whatever else you have created. This cannot be undone! Are you sure you want to do this ?",
|
"warning_space_delete": "You can delete your space including all recipes, shopping lists, meal plans and whatever else you have created. This cannot be undone! Are you sure you want to do this ?",
|
||||||
"food_inherit_info": "Fields on food that should be inherited by default.",
|
"food_inherit_info": "Fields on food that should be inherited by default.",
|
||||||
"facet_count_info": "Show recipe counts on search filters.",
|
"facet_count_info": "Show recipe counts on search filters.",
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
"Add_nutrition_recipe": "Add nutrition to recipe",
|
"Add_nutrition_recipe": "Add nutrition to recipe",
|
||||||
"Remove_nutrition_recipe": "Delete nutrition from recipe",
|
"Remove_nutrition_recipe": "Delete nutrition from recipe",
|
||||||
"Copy_template_reference": "Copy template reference",
|
"Copy_template_reference": "Copy template reference",
|
||||||
|
"per_serving": "per servings",
|
||||||
"Save_and_View": "Save & View",
|
"Save_and_View": "Save & View",
|
||||||
"Manage_Books": "Manage Books",
|
"Manage_Books": "Manage Books",
|
||||||
"Meal_Plan": "Meal Plan",
|
"Meal_Plan": "Meal Plan",
|
||||||
@@ -76,6 +78,19 @@
|
|||||||
"Private_Recipe": "Private Recipe",
|
"Private_Recipe": "Private Recipe",
|
||||||
"Private_Recipe_Help": "Recipe is only shown to you and people its shared with.",
|
"Private_Recipe_Help": "Recipe is only shown to you and people its shared with.",
|
||||||
"reusable_help_text": "Should the invite link be usable for more than one user.",
|
"reusable_help_text": "Should the invite link be usable for more than one user.",
|
||||||
|
"open_data_help_text": "The Tandoor Open Data project provides community contributed data for Tandoor. This field is filled automatically when importing it and allows updates in the future.",
|
||||||
|
"Open_Data_Slug": "Open Data Slug",
|
||||||
|
"Open_Data_Import": "Open Data Import",
|
||||||
|
"Data_Import_Info": "Enhance your Space by importing a community curated list of foods, units and more to improve your recipe collection.",
|
||||||
|
"Update_Existing_Data": "Update Existing Data",
|
||||||
|
"Use_Metric": "Use Metric Units",
|
||||||
|
"Learn_More": "Learn More",
|
||||||
|
"converted_unit": "Converted Unit",
|
||||||
|
"converted_amount": "Converted Amount",
|
||||||
|
"base_unit": "Base Unit",
|
||||||
|
"base_amount": "Base Amount",
|
||||||
|
"Datatype": "Datatype",
|
||||||
|
"Number of Objects": "Number of Objects",
|
||||||
"Add_Step": "Add Step",
|
"Add_Step": "Add Step",
|
||||||
"Keywords": "Keywords",
|
"Keywords": "Keywords",
|
||||||
"Books": "Books",
|
"Books": "Books",
|
||||||
@@ -161,6 +176,8 @@
|
|||||||
"merge_title": "Merge {type}",
|
"merge_title": "Merge {type}",
|
||||||
"move_title": "Move {type}",
|
"move_title": "Move {type}",
|
||||||
"Food": "Food",
|
"Food": "Food",
|
||||||
|
"Property": "Property",
|
||||||
|
"Conversion": "Conversion",
|
||||||
"Original_Text": "Original Text",
|
"Original_Text": "Original Text",
|
||||||
"Recipe_Book": "Recipe Book",
|
"Recipe_Book": "Recipe Book",
|
||||||
"del_confirmation_tree": "Are you sure that you want to delete {source} and all of it's children?",
|
"del_confirmation_tree": "Are you sure that you want to delete {source} and all of it's children?",
|
||||||
@@ -168,6 +185,7 @@
|
|||||||
"create_title": "New {type}",
|
"create_title": "New {type}",
|
||||||
"edit_title": "Edit {type}",
|
"edit_title": "Edit {type}",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
"Properties": "Properties",
|
||||||
"Type": "Type",
|
"Type": "Type",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
"Recipe": "Recipe",
|
"Recipe": "Recipe",
|
||||||
@@ -462,6 +480,7 @@
|
|||||||
"Import_Result_Info": "{imported} of {total} recipes were imported",
|
"Import_Result_Info": "{imported} of {total} recipes were imported",
|
||||||
"Recipes_In_Import": "Recipes in your import file",
|
"Recipes_In_Import": "Recipes in your import file",
|
||||||
"Toggle": "Toggle",
|
"Toggle": "Toggle",
|
||||||
|
"total": "total",
|
||||||
"Import_Error": "An Error occurred during your import. Please expand the Details at the bottom of the page to view it.",
|
"Import_Error": "An Error occurred during your import. Please expand the Details at the bottom of the page to view it.",
|
||||||
"Warning_Delete_Supermarket_Category": "Deleting a supermarket category will also delete all relations to foods. Are you sure?",
|
"Warning_Delete_Supermarket_Category": "Deleting a supermarket category will also delete all relations to foods. Are you sure?",
|
||||||
"New_Supermarket": "Create new supermarket",
|
"New_Supermarket": "Create new supermarket",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"Carbohydrates": "Carbohydratos",
|
"Carbohydrates": "Carbohydratos",
|
||||||
"Calories": "Calorias",
|
"Calories": "Calorias",
|
||||||
"Energy": "Energia",
|
"Energy": "Energia",
|
||||||
"Nutrition": "Nutricion",
|
"Nutrition": "Nutrición",
|
||||||
"Date": "Fecha",
|
"Date": "Fecha",
|
||||||
"Share": "Compartir",
|
"Share": "Compartir",
|
||||||
"Automation": "Automatización",
|
"Automation": "Automatización",
|
||||||
@@ -452,5 +452,6 @@
|
|||||||
"Auto_Sort": "Ordenar Automáticamente",
|
"Auto_Sort": "Ordenar Automáticamente",
|
||||||
"Auto_Sort_Help": "Mueva todos los ingredientes al paso que mejor se adapte.",
|
"Auto_Sort_Help": "Mueva todos los ingredientes al paso que mejor se adapte.",
|
||||||
"Unpin": "Desanclar",
|
"Unpin": "Desanclar",
|
||||||
"Amount": "Cantidad"
|
"Amount": "Cantidad",
|
||||||
|
"PinnedConfirmation": "{recipe} ha sido fijada."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,83 +68,83 @@
|
|||||||
"Amount": "Mengde",
|
"Amount": "Mengde",
|
||||||
"Enable_Amount": "Aktiver mengde",
|
"Enable_Amount": "Aktiver mengde",
|
||||||
"Disable_Amount": "Deaktiver mengde",
|
"Disable_Amount": "Deaktiver mengde",
|
||||||
"Ingredient Editor": "",
|
"Ingredient Editor": "Ingrediens Behandler",
|
||||||
"Description_Replace": "",
|
"Description_Replace": "Erstatt beskrivelse",
|
||||||
"Instruction_Replace": "",
|
"Instruction_Replace": "Erstatt instruksjoner",
|
||||||
"Auto_Sort": "",
|
"Auto_Sort": "Sorter Automatisk",
|
||||||
"Auto_Sort_Help": "",
|
"Auto_Sort_Help": "Flytt alle ingredienser til det mest passende steget.",
|
||||||
"Private_Recipe": "",
|
"Private_Recipe": "Privat Oppskrift",
|
||||||
"Private_Recipe_Help": "",
|
"Private_Recipe_Help": "Oppskriften er bare vist til deg og dem du har delt den med.",
|
||||||
"reusable_help_text": "",
|
"reusable_help_text": "Burde invitasjonslenken være brukbar for flere enn én bruker.",
|
||||||
"Add_Step": "",
|
"Add_Step": "Legg til steg",
|
||||||
"Keywords": "",
|
"Keywords": "Nøkkelord",
|
||||||
"Books": "Bøker",
|
"Books": "Bøker",
|
||||||
"Proteins": "",
|
"Proteins": "Protein",
|
||||||
"Fats": "",
|
"Fats": "Fett",
|
||||||
"Carbohydrates": "Karbohydrater",
|
"Carbohydrates": "Karbohydrater",
|
||||||
"Calories": "",
|
"Calories": "Kalorier",
|
||||||
"Energy": "",
|
"Energy": "Energi",
|
||||||
"Nutrition": "",
|
"Nutrition": "Næring",
|
||||||
"Date": "",
|
"Date": "Dato",
|
||||||
"Share": "",
|
"Share": "Del",
|
||||||
"Automation": "",
|
"Automation": "Automatiser",
|
||||||
"Parameter": "",
|
"Parameter": "Parameter",
|
||||||
"Export": "",
|
"Export": "Eksporter",
|
||||||
"Copy": "",
|
"Copy": "Kopier",
|
||||||
"Rating": "Karakter",
|
"Rating": "Vurdering",
|
||||||
"Close": "Lukk",
|
"Close": "Lukk",
|
||||||
"Cancel": "",
|
"Cancel": "Avbryt",
|
||||||
"Link": "Lenke",
|
"Link": "Lenke",
|
||||||
"Add": "",
|
"Add": "Legg til",
|
||||||
"New": "",
|
"New": "Ny",
|
||||||
"Note": "",
|
"Note": "Merk",
|
||||||
"Success": "",
|
"Success": "Vellykket",
|
||||||
"Failure": "",
|
"Failure": "Feil",
|
||||||
"Protected": "",
|
"Protected": "Beskyttet",
|
||||||
"Ingredients": "Ingredienser",
|
"Ingredients": "Ingredienser",
|
||||||
"Supermarket": "Butikk",
|
"Supermarket": "Butikk",
|
||||||
"Categories": "",
|
"Categories": "Kategorier",
|
||||||
"Category": "",
|
"Category": "Kategori",
|
||||||
"Selected": "",
|
"Selected": "Valgte",
|
||||||
"min": "",
|
"min": "min",
|
||||||
"Servings": "",
|
"Servings": "Porsjoner",
|
||||||
"Waiting": "",
|
"Waiting": "Venter",
|
||||||
"Preparation": "",
|
"Preparation": "Forberedelse",
|
||||||
"External": "",
|
"External": "Ekstern",
|
||||||
"Size": "",
|
"Size": "Størrelse",
|
||||||
"Files": "",
|
"Files": "Filer",
|
||||||
"File": "",
|
"File": "Fil",
|
||||||
"Edit": "",
|
"Edit": "Rediger",
|
||||||
"Image": "",
|
"Image": "Bilde",
|
||||||
"Delete": "",
|
"Delete": "Slett",
|
||||||
"Open": "",
|
"Open": "Åpne",
|
||||||
"Ok": "",
|
"Ok": "Ok",
|
||||||
"Save": "",
|
"Save": "Lagre",
|
||||||
"Step": "",
|
"Step": "Steg",
|
||||||
"Search": "",
|
"Search": "Søk",
|
||||||
"Import": "",
|
"Import": "Importer",
|
||||||
"Print": "",
|
"Print": "Skriv ut",
|
||||||
"Settings": "Innstillinger",
|
"Settings": "Innstillinger",
|
||||||
"or": "",
|
"or": "eller",
|
||||||
"and": "",
|
"and": "og",
|
||||||
"Information": "",
|
"Information": "Informasjon",
|
||||||
"Download": "",
|
"Download": "Last ned",
|
||||||
"Create": "Opprett",
|
"Create": "Opprett",
|
||||||
"Search Settings": "",
|
"Search Settings": "Søk Instillinger",
|
||||||
"View": "",
|
"View": "Visning",
|
||||||
"Recipes": "",
|
"Recipes": "Oppskrift",
|
||||||
"Move": "",
|
"Move": "Flytt",
|
||||||
"Merge": "",
|
"Merge": "Slå sammen",
|
||||||
"Parent": "",
|
"Parent": "Forelder",
|
||||||
"Copy Link": "",
|
"Copy Link": "Kopier lenke",
|
||||||
"Copy Token": "",
|
"Copy Token": "Kopier Token",
|
||||||
"delete_confirmation": "",
|
"delete_confirmation": "Er du sikker på at du vill slette {source}?",
|
||||||
"move_confirmation": "",
|
"move_confirmation": "Flytt<i>{child}</i> til forelder <i>{parent}</i>",
|
||||||
"merge_confirmation": "",
|
"merge_confirmation": "Erstatt<i>{source}</i> med <i>{target}</i>",
|
||||||
"create_rule": "",
|
"create_rule": "og opprett automasjon",
|
||||||
"move_selection": "",
|
"move_selection": "Velg en forelder {type} å flytte {source} til.",
|
||||||
"merge_selection": "",
|
"merge_selection": "Erstatt alle tilfeller av {source} med den valgte {type}.",
|
||||||
"Root": "",
|
"Root": "Rot",
|
||||||
"Ignore_Shopping": "",
|
"Ignore_Shopping": "",
|
||||||
"Shopping_Category": "",
|
"Shopping_Category": "",
|
||||||
"Shopping_Categories": "",
|
"Shopping_Categories": "",
|
||||||
@@ -284,33 +284,33 @@
|
|||||||
"Hide_Keyword": "",
|
"Hide_Keyword": "",
|
||||||
"Hour": "",
|
"Hour": "",
|
||||||
"Hours": "",
|
"Hours": "",
|
||||||
"Day": "",
|
"Day": "Dag",
|
||||||
"Days": "",
|
"Days": "Dager",
|
||||||
"Second": "",
|
"Second": "",
|
||||||
"Seconds": "",
|
"Seconds": "",
|
||||||
"Clear": "",
|
"Clear": "",
|
||||||
"Users": "",
|
"Users": "",
|
||||||
"Invites": "",
|
"Invites": "",
|
||||||
"err_move_self": "",
|
"err_move_self": "",
|
||||||
"nothing": "",
|
"nothing": "Ingenting å gjøre",
|
||||||
"err_merge_self": "",
|
"err_merge_self": "Kan ikke slå sammen linje med seg selv",
|
||||||
"show_sql": "",
|
"show_sql": "Vis SQL",
|
||||||
"filter_to_supermarket_desc": "",
|
"filter_to_supermarket_desc": "Som standard, filtrerer handlelisten til å kun inkludere kategorier for den valgte butikken.",
|
||||||
"CategoryName": "",
|
"CategoryName": "Kategori navn",
|
||||||
"SupermarketName": "",
|
"SupermarketName": "Butikk Navn",
|
||||||
"CategoryInstruction": "",
|
"CategoryInstruction": "Dra kategorier for å endre på rekkefølgen de vises i handlelisten.",
|
||||||
"shopping_recent_days_desc": "",
|
"shopping_recent_days_desc": "",
|
||||||
"shopping_recent_days": "",
|
"shopping_recent_days": "",
|
||||||
"download_pdf": "",
|
"download_pdf": "Last ned PDF",
|
||||||
"download_csv": "",
|
"download_csv": "Last ned CSV",
|
||||||
"csv_delim_help": "",
|
"csv_delim_help": "",
|
||||||
"csv_delim_label": "",
|
"csv_delim_label": "",
|
||||||
"SuccessClipboard": "",
|
"SuccessClipboard": "",
|
||||||
"copy_to_clipboard": "",
|
"copy_to_clipboard": "Kopier til utklippstavle",
|
||||||
"csv_prefix_help": "",
|
"csv_prefix_help": "Prefiks for å legge til når du kopierer listen til utklippstavlen.",
|
||||||
"csv_prefix_label": "",
|
"csv_prefix_label": "Liste prefiks",
|
||||||
"copy_markdown_table": "",
|
"copy_markdown_table": "Kopier som Markdown tabell",
|
||||||
"in_shopping": "",
|
"in_shopping": "I handleliste",
|
||||||
"DelayUntil": "",
|
"DelayUntil": "",
|
||||||
"Pin": "",
|
"Pin": "",
|
||||||
"Unpin": "",
|
"Unpin": "",
|
||||||
@@ -332,37 +332,37 @@
|
|||||||
"food_recipe_help": "",
|
"food_recipe_help": "",
|
||||||
"Foods": "",
|
"Foods": "",
|
||||||
"Account": "",
|
"Account": "",
|
||||||
"Cosmetic": "",
|
"Cosmetic": "Kosmetisk",
|
||||||
"API": "",
|
"API": "API",
|
||||||
"enable_expert": "",
|
"enable_expert": "Aktiver Ekspert Modus",
|
||||||
"expert_mode": "",
|
"expert_mode": "Ekspert Modus",
|
||||||
"simple_mode": "",
|
"simple_mode": "Enkel Modus",
|
||||||
"advanced": "",
|
"advanced": "Avansert",
|
||||||
"fields": "",
|
"fields": "Felt",
|
||||||
"show_keywords": "",
|
"show_keywords": "Vis Nøkkelord",
|
||||||
"show_foods": "",
|
"show_foods": "Vis Mat",
|
||||||
"show_books": "",
|
"show_books": "Vis bøker",
|
||||||
"show_rating": "",
|
"show_rating": "Vis vurdering",
|
||||||
"show_units": "",
|
"show_units": "Vis enheter",
|
||||||
"show_filters": "",
|
"show_filters": "Vis filtre",
|
||||||
"not": "",
|
"not": "ikke",
|
||||||
"save_filter": "",
|
"save_filter": "Lagre filtre",
|
||||||
"filter_name": "",
|
"filter_name": "Filtrer Navn",
|
||||||
"left_handed": "",
|
"left_handed": "Venstrehendt Modus",
|
||||||
"left_handed_help": "",
|
"left_handed_help": "Vil optimalisere bukergrensesnittet for bruk med venstre hånden.",
|
||||||
"Custom Filter": "",
|
"Custom Filter": "Egendefinert Filter",
|
||||||
"shared_with": "",
|
"shared_with": "Delt med",
|
||||||
"sort_by": "",
|
"sort_by": "Sorter etter",
|
||||||
"asc": "",
|
"asc": "Stigende",
|
||||||
"desc": "",
|
"desc": "Fallende",
|
||||||
"date_viewed": "",
|
"date_viewed": "Sist sett",
|
||||||
"last_cooked": "",
|
"last_cooked": "Sist tilberedt",
|
||||||
"times_cooked": "",
|
"times_cooked": "Antall ganger tilberedt",
|
||||||
"date_created": "",
|
"date_created": "Dato laget",
|
||||||
"show_sortby": "",
|
"show_sortby": "Vis sorter etter",
|
||||||
"search_rank": "",
|
"search_rank": "Søk etter vurdering",
|
||||||
"make_now": "",
|
"make_now": "Lag nå",
|
||||||
"recipe_filter": "",
|
"recipe_filter": "Oppskrift filter",
|
||||||
"book_filter_help": "",
|
"book_filter_help": "",
|
||||||
"review_shopping": "",
|
"review_shopping": "",
|
||||||
"view_recipe": "",
|
"view_recipe": "",
|
||||||
@@ -373,9 +373,9 @@
|
|||||||
"ingredient_list": "",
|
"ingredient_list": "",
|
||||||
"explain": "",
|
"explain": "",
|
||||||
"filter": "",
|
"filter": "",
|
||||||
"Website": "",
|
"Website": "Nettside",
|
||||||
"App": "",
|
"App": "App",
|
||||||
"Message": "",
|
"Message": "Melding",
|
||||||
"Bookmarklet": "",
|
"Bookmarklet": "",
|
||||||
"Sticky_Nav": "",
|
"Sticky_Nav": "",
|
||||||
"Sticky_Nav_Help": "",
|
"Sticky_Nav_Help": "",
|
||||||
@@ -420,11 +420,11 @@
|
|||||||
"Quick actions": "",
|
"Quick actions": "",
|
||||||
"Ratings": "",
|
"Ratings": "",
|
||||||
"Internal": "",
|
"Internal": "",
|
||||||
"Units": "",
|
"Units": "Enhet",
|
||||||
"Manage_Emails": "",
|
"Manage_Emails": "Administrer e-poster",
|
||||||
"Change_Password": "",
|
"Change_Password": "Endre passord",
|
||||||
"Social_Authentication": "",
|
"Social_Authentication": "",
|
||||||
"Random Recipes": "",
|
"Random Recipes": "Tilfeldige oppskrifter",
|
||||||
"parameter_count": "",
|
"parameter_count": "",
|
||||||
"select_keyword": "",
|
"select_keyword": "",
|
||||||
"add_keyword": "",
|
"add_keyword": "",
|
||||||
@@ -435,13 +435,13 @@
|
|||||||
"remove_selection": "",
|
"remove_selection": "",
|
||||||
"empty_list": "",
|
"empty_list": "",
|
||||||
"Select": "Velg",
|
"Select": "Velg",
|
||||||
"Supermarkets": "",
|
"Supermarkets": "Butikker",
|
||||||
"User": "",
|
"User": "Bruker",
|
||||||
"Username": "",
|
"Username": "Brukernavn",
|
||||||
"First_name": "",
|
"First_name": "Fornavn",
|
||||||
"Last_name": "",
|
"Last_name": "Etternavn",
|
||||||
"Keyword": "Nøkkelord",
|
"Keyword": "Nøkkelord",
|
||||||
"Advanced": "",
|
"Advanced": "Avansert",
|
||||||
"Page": "",
|
"Page": "",
|
||||||
"Single": "",
|
"Single": "",
|
||||||
"Multiple": "",
|
"Multiple": "",
|
||||||
@@ -478,5 +478,19 @@
|
|||||||
"Use_Plural_Food_Simple": "",
|
"Use_Plural_Food_Simple": "",
|
||||||
"plural_usage_info": "",
|
"plural_usage_info": "",
|
||||||
"Create Recipe": "",
|
"Create Recipe": "",
|
||||||
"Import Recipe": ""
|
"Import Recipe": "",
|
||||||
|
"per_serving": "Per porsjon",
|
||||||
|
"open_data_help_text": "Tandoor Open Data prosjektet gir fra fellesskapet til Tandoor. Dette feltet fylles ut automatisk når det importeres og tillater oppdateringer i fremtiden.",
|
||||||
|
"Open_Data_Slug": "Åpne data Slug",
|
||||||
|
"Open_Data_Import": "Åpne Data Import",
|
||||||
|
"recipe_property_info": "Du kan også legge til egenskaper til mat for å kalkulere dem automatisk basert på oppskriften!",
|
||||||
|
"Update_Existing_Data": "Oppdater eksisterende data",
|
||||||
|
"Use_Metric": "Bruk metriske enheter",
|
||||||
|
"Learn_More": "Lær mer",
|
||||||
|
"converted_unit": "Konverter enhet",
|
||||||
|
"converted_amount": "Konverter mengde",
|
||||||
|
"base_unit": "Baseenhet",
|
||||||
|
"base_amount": "Basemengde",
|
||||||
|
"Datatype": "Data-type",
|
||||||
|
"Number of Objects": "Antall objekter"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -480,5 +480,24 @@
|
|||||||
"Description_Replace": "Zmień opis",
|
"Description_Replace": "Zmień opis",
|
||||||
"Instruction_Replace": "Zmień instrukcję",
|
"Instruction_Replace": "Zmień instrukcję",
|
||||||
"Import Recipe": "Importuj przepis",
|
"Import Recipe": "Importuj przepis",
|
||||||
"Create Recipe": "Utwórz przepis"
|
"Create Recipe": "Utwórz przepis",
|
||||||
|
"recipe_property_info": "Możesz także dodawać właściwości do żywności, aby przeliczać ją automatycznie na podstawie Twojego przepisu!",
|
||||||
|
"per_serving": "na porcje",
|
||||||
|
"open_data_help_text": "Projekt Tandoor Open Data dostarcza danych przesłanych przez społeczność dla Tandoor. To pole jest wypełniane automatycznie podczas importu i umożliwia aktualizacje w przyszłości.",
|
||||||
|
"Open_Data_Slug": "Open Data Slug",
|
||||||
|
"Open_Data_Import": "Open Data Import",
|
||||||
|
"Data_Import_Info": "Wzbogać swoją Przestrzeń, importując wyselekcjonowaną przez społeczność listę żywności, jednostek i nie tylko, aby ulepszyć swoją kolekcję przepisów.",
|
||||||
|
"Update_Existing_Data": "Zaktualizuj istniejące dane",
|
||||||
|
"Use_Metric": "Użyj jednostek metrycznych",
|
||||||
|
"Learn_More": "Dowiedz się więcej",
|
||||||
|
"converted_unit": "Przeliczona jednostka",
|
||||||
|
"converted_amount": "Przeliczona ilość",
|
||||||
|
"base_unit": "Jednostka podstawowa",
|
||||||
|
"base_amount": "Ilość bazowa",
|
||||||
|
"Datatype": "Typ danych",
|
||||||
|
"Number of Objects": "Ilość obiektów",
|
||||||
|
"Property": "Właściwość",
|
||||||
|
"Conversion": "Konwersja",
|
||||||
|
"Properties": "Właściwości",
|
||||||
|
"total": "łącznie"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"warning_feature_beta": "Данный функционал находится в сдадии BETA (тестируется). Возможны баги и серьезные изменения функционала в будующем.",
|
"warning_feature_beta": "Данный функционал находится в стадии BETA (тестируется). Возможны баги и серьезные изменения функционала в будущем.",
|
||||||
"err_fetching_resource": "Ошибка при загрузке продукта!",
|
"err_fetching_resource": "Ошибка при загрузке продукта!",
|
||||||
"err_creating_resource": "Ошибка при создании продукта!",
|
"err_creating_resource": "Ошибка при создании продукта!",
|
||||||
"err_updating_resource": "Ошибка при редактировании продукта!",
|
"err_updating_resource": "Ошибка при редактировании продукта!",
|
||||||
"err_deleting_resource": "Ошибка при удалении продукта!",
|
"err_deleting_resource": "Ошибка при удалении продукта!",
|
||||||
"success_fetching_resource": "Продукт успешно загружен!",
|
"success_fetching_resource": "Продукт успешно загружен!",
|
||||||
"success_creating_resource": "Продукт успешно загружен!",
|
"success_creating_resource": "Продукт успешно создан!",
|
||||||
"success_updating_resource": "Продукт успешно обновлен!",
|
"success_updating_resource": "Продукт успешно обновлен!",
|
||||||
"success_deleting_resource": "Продукт успешно удален!",
|
"success_deleting_resource": "Продукт успешно удален!",
|
||||||
"file_upload_disabled": "Выгрузка файла не активирована в настройках.",
|
"file_upload_disabled": "Выгрузка файла не активирована в настройках.",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"confirm_delete": "Вы уверены, что хотите удалить этот объект?",
|
"confirm_delete": "Вы уверены, что хотите удалить этот объект?",
|
||||||
"import_running": "Идет загрузка, пожалуйста ждите!",
|
"import_running": "Идет загрузка, пожалуйста ждите!",
|
||||||
"all_fields_optional": "Все поля не обязательны для заполнения.",
|
"all_fields_optional": "Все поля не обязательны для заполнения.",
|
||||||
"convert_internal": "Конвретировать рецепт во внутренний формат",
|
"convert_internal": "Конвертировать рецепт во внутренний формат",
|
||||||
"show_only_internal": "Показывать только рецепты во внутреннем формате",
|
"show_only_internal": "Показывать только рецепты во внутреннем формате",
|
||||||
"show_split_screen": "Двухколоночный вид",
|
"show_split_screen": "Двухколоночный вид",
|
||||||
"Log_Recipe_Cooking": "Журнал приготовления",
|
"Log_Recipe_Cooking": "Журнал приготовления",
|
||||||
@@ -211,13 +211,13 @@
|
|||||||
"FoodNotOnHand": "{food} отсутствует в наличии.",
|
"FoodNotOnHand": "{food} отсутствует в наличии.",
|
||||||
"Undefined": "Неизвестно",
|
"Undefined": "Неизвестно",
|
||||||
"AddFoodToShopping": "Добавить {food} в ваш список покупок",
|
"AddFoodToShopping": "Добавить {food} в ваш список покупок",
|
||||||
"success_moving_resource": "Успешное перемещение ресурса!",
|
"success_moving_resource": "Успешное перемещение продукта!",
|
||||||
"success_merging_resource": "Ресурс успешно присоединен!",
|
"success_merging_resource": "Продукт успешно присоединен!",
|
||||||
"Shopping_Categories": "Категории покупок",
|
"Shopping_Categories": "Категории покупок",
|
||||||
"Search Settings": "Искать настройки",
|
"Search Settings": "Искать настройки",
|
||||||
"err_merging_resource": "Произошла ошибка при перемещении ресурса!",
|
"err_merging_resource": "Произошла ошибка при перемещении продукта!",
|
||||||
"Remove_nutrition_recipe": "Уберите питательные вещества из рецепта",
|
"Remove_nutrition_recipe": "Уберите питательные вещества из рецепта",
|
||||||
"err_moving_resource": "Произошла ошибка при перемещении ресурса!",
|
"err_moving_resource": "Произошла ошибка при перемещении продукта!",
|
||||||
"NotInShopping": "{food} отсутствует в вашем списке покупок.",
|
"NotInShopping": "{food} отсутствует в вашем списке покупок.",
|
||||||
"RemoveFoodFromShopping": "Удалить {food} из вашего списка покупок",
|
"RemoveFoodFromShopping": "Удалить {food} из вашего списка покупок",
|
||||||
"ShowDelayed": "Показать отложенные элементы",
|
"ShowDelayed": "Показать отложенные элементы",
|
||||||
@@ -345,6 +345,6 @@
|
|||||||
"GroupBy": "Сгруппировать по",
|
"GroupBy": "Сгруппировать по",
|
||||||
"facet_count_info": "Показывать количество рецептов в фильтрах поиска.",
|
"facet_count_info": "Показывать количество рецептов в фильтрах поиска.",
|
||||||
"food_inherit_info": "Поля для продуктов питания, которые должны наследоваться по умолчанию.",
|
"food_inherit_info": "Поля для продуктов питания, которые должны наследоваться по умолчанию.",
|
||||||
"warning_space_delete": "Вы можете удалить свое пространство, включая все рецепты, списки покупок, планы питания и все остальное, что вы создали. Этого нельзя отменить! Ты уверен, что хочешь это сделать?",
|
"warning_space_delete": "Вы можете удалить свое пространство, включая все рецепты, списки покупок, планы питания и все остальное, что вы создали. Этого нельзя отменить! Вы уверены, что хотите это сделать?",
|
||||||
"Description_Replace": "Изменить описание"
|
"Description_Replace": "Изменить описание"
|
||||||
}
|
}
|
||||||
|
|||||||
0
vue/src/stores/GenericApiStore.js
Normal file
0
vue/src/stores/GenericApiStore.js
Normal file
@@ -91,11 +91,13 @@ export class Models {
|
|||||||
"substitute_children",
|
"substitute_children",
|
||||||
"reset_inherit",
|
"reset_inherit",
|
||||||
"child_inherit_fields",
|
"child_inherit_fields",
|
||||||
|
"open_data_slug",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
form: {
|
form: {
|
||||||
show_help: true,
|
show_help: true,
|
||||||
|
component: "FoodEditor",
|
||||||
name: {
|
name: {
|
||||||
form_field: true,
|
form_field: true,
|
||||||
type: "text",
|
type: "text",
|
||||||
@@ -126,6 +128,14 @@ export class Models {
|
|||||||
label: "Recipe", // form.label always translated in utils.getForm()
|
label: "Recipe", // form.label always translated in utils.getForm()
|
||||||
help_text: "food_recipe_help", // form.help_text always translated
|
help_text: "food_recipe_help", // form.help_text always translated
|
||||||
},
|
},
|
||||||
|
open_data_slug: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "open_data_slug",
|
||||||
|
disabled: true,
|
||||||
|
label: "Open_Data_Slug",
|
||||||
|
help_text: "open_data_help_text",
|
||||||
|
},
|
||||||
onhand: {
|
onhand: {
|
||||||
form_field: true,
|
form_field: true,
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
@@ -269,8 +279,9 @@ export class Models {
|
|||||||
apiName: "Unit",
|
apiName: "Unit",
|
||||||
paginated: true,
|
paginated: true,
|
||||||
create: {
|
create: {
|
||||||
params: [["name", "plural_name", "description",]],
|
params: [["name", "plural_name", "description", "open_data_slug",]],
|
||||||
form: {
|
form: {
|
||||||
|
show_help: true,
|
||||||
name: {
|
name: {
|
||||||
form_field: true,
|
form_field: true,
|
||||||
type: "text",
|
type: "text",
|
||||||
@@ -292,6 +303,14 @@ export class Models {
|
|||||||
label: "Description",
|
label: "Description",
|
||||||
placeholder: "",
|
placeholder: "",
|
||||||
},
|
},
|
||||||
|
open_data_slug: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "open_data_slug",
|
||||||
|
disabled: true,
|
||||||
|
label: "Open_Data_Slug",
|
||||||
|
help_text: "open_data_help_text",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
merge: true,
|
merge: true,
|
||||||
@@ -418,6 +437,7 @@ export class Models {
|
|||||||
create: {
|
create: {
|
||||||
params: [["name", "description", "category_to_supermarket"]],
|
params: [["name", "description", "category_to_supermarket"]],
|
||||||
form: {
|
form: {
|
||||||
|
show_help: true,
|
||||||
name: {
|
name: {
|
||||||
form_field: true,
|
form_field: true,
|
||||||
type: "text",
|
type: "text",
|
||||||
@@ -442,6 +462,14 @@ export class Models {
|
|||||||
label: "Categories", // form.label always translated in utils.getForm()
|
label: "Categories", // form.label always translated in utils.getForm()
|
||||||
placeholder: "",
|
placeholder: "",
|
||||||
},
|
},
|
||||||
|
open_data_slug: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "open_data_slug",
|
||||||
|
disabled: true,
|
||||||
|
label: "Open_Data_Slug",
|
||||||
|
help_text: "open_data_help_text",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
function: "SupermarketWithCategories",
|
function: "SupermarketWithCategories",
|
||||||
@@ -562,6 +590,129 @@ export class Models {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UNIT_CONVERSION = {
|
||||||
|
name: "Unit Conversion",
|
||||||
|
apiName: "UnitConversion",
|
||||||
|
paginated: false,
|
||||||
|
list: {
|
||||||
|
header_component: {
|
||||||
|
name: "BetaWarning",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
params: [['food', 'base_amount', 'base_unit', 'converted_amount', 'converted_unit', 'open_data_slug']],
|
||||||
|
form: {
|
||||||
|
show_help: true,
|
||||||
|
// TODO add proper help texts for everything
|
||||||
|
food: {
|
||||||
|
form_field: true,
|
||||||
|
type: "lookup",
|
||||||
|
field: "food",
|
||||||
|
list: "FOOD",
|
||||||
|
list_label: "name",
|
||||||
|
label: "Food",
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
base_amount: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "base_amount",
|
||||||
|
label: "base_amount",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
base_unit: {
|
||||||
|
form_field: true,
|
||||||
|
type: "lookup",
|
||||||
|
field: "base_unit",
|
||||||
|
list: "UNIT",
|
||||||
|
list_label: "name",
|
||||||
|
label: "base_unit",
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
converted_amount: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "converted_amount",
|
||||||
|
label: "converted_amount",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
converted_unit: {
|
||||||
|
form_field: true,
|
||||||
|
type: "lookup",
|
||||||
|
field: "converted_unit",
|
||||||
|
list: "UNIT",
|
||||||
|
list_label: "name",
|
||||||
|
label: "converted_unit",
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
open_data_slug: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "open_data_slug",
|
||||||
|
disabled: true,
|
||||||
|
label: "Open_Data_Slug",
|
||||||
|
help_text: "open_data_help_text",
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
static PROPERTY_TYPE = {
|
||||||
|
name: "Property Type",
|
||||||
|
apiName: "PropertyType",
|
||||||
|
paginated: false,
|
||||||
|
list: {
|
||||||
|
header_component: {
|
||||||
|
name: "BetaWarning",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
params: [['name', 'icon', 'unit', 'description']],
|
||||||
|
form: {
|
||||||
|
show_help: true,
|
||||||
|
name: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "name",
|
||||||
|
label: "Name",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
form_field: true,
|
||||||
|
type: "emoji",
|
||||||
|
field: "icon",
|
||||||
|
label: "Icon",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "unit",
|
||||||
|
label: "Unit",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "description",
|
||||||
|
label: "Description",
|
||||||
|
placeholder: "",
|
||||||
|
},
|
||||||
|
open_data_slug: {
|
||||||
|
form_field: true,
|
||||||
|
type: "text",
|
||||||
|
field: "open_data_slug",
|
||||||
|
disabled: true,
|
||||||
|
label: "Open_Data_Slug",
|
||||||
|
help_text: "open_data_help_text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
static RECIPE = {
|
static RECIPE = {
|
||||||
name: "Recipe",
|
name: "Recipe",
|
||||||
apiName: "Recipe",
|
apiName: "Recipe",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ export class StandardToasts {
|
|||||||
static FAIL_MOVE = "FAIL_MOVE"
|
static FAIL_MOVE = "FAIL_MOVE"
|
||||||
static FAIL_MERGE = "FAIL_MERGE"
|
static FAIL_MERGE = "FAIL_MERGE"
|
||||||
|
|
||||||
static makeStandardToast(context, toast, err) {
|
static makeStandardToast(context, toast, err = undefined, always_show_errors = false) {
|
||||||
let title = ''
|
let title = ''
|
||||||
let msg = ''
|
let msg = ''
|
||||||
let variant = ''
|
let variant = ''
|
||||||
@@ -124,7 +124,7 @@ export class StandardToasts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let DEBUG = localStorage.getItem("DEBUG") === "True" || false
|
let DEBUG = localStorage.getItem("DEBUG") === "True" || always_show_errors
|
||||||
|
|
||||||
if (err !== undefined && 'response' in err && 'headers' in err.response) {
|
if (err !== undefined && 'response' in err && 'headers' in err.response) {
|
||||||
if (DEBUG && err.response.headers['content-type'] === 'application/json' && err.response.status < 500) {
|
if (DEBUG && err.response.headers['content-type'] === 'application/json' && err.response.status < 500) {
|
||||||
@@ -368,6 +368,9 @@ export const ApiMixin = {
|
|||||||
let func = setup.function
|
let func = setup.function
|
||||||
let parameters = buildParams(options, setup)
|
let parameters = buildParams(options, setup)
|
||||||
let apiClient = new ApiApiFactory()
|
let apiClient = new ApiApiFactory()
|
||||||
|
if (model.apiClient !== undefined) {
|
||||||
|
apiClient = model.apiClient
|
||||||
|
}
|
||||||
return apiClient[func](...parameters)
|
return apiClient[func](...parameters)
|
||||||
},
|
},
|
||||||
genericGetAPI: function (url, options) {
|
genericGetAPI: function (url, options) {
|
||||||
|
|||||||
28857
vue/yarn.lock
28857
vue/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user