Merge branch 'develop' into HomeAssistantConnector

This commit is contained in:
Mikhail Epifanov 2024-01-17 22:45:02 +01:00 committed by Mikhail Epifanov
commit 5f9d59317b
No known key found for this signature in database
16 changed files with 284 additions and 190 deletions

View File

@ -11,8 +11,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-09 18:01+0100\n"
"PO-Revision-Date: 2023-07-31 14:19+0000\n"
"Last-Translator: Mára Štěpánek <stepanekm7@gmail.com>\n"
"PO-Revision-Date: 2024-01-09 12:07+0000\n"
"Last-Translator: Jan Kubošek <kuboja@outlook.cz>\n"
"Language-Team: Czech <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/cs/>\n"
"Language: cs\n"
@ -190,7 +190,7 @@ msgid ""
"Leave empty for dropbox and enter only base url for nextcloud "
"(<code>/remote.php/webdav/</code> is added automatically)"
msgstr ""
"Pro dropbox ponechejte nevyplňené pole. Pro nextcloud použijte pouze "
"Pro dropbox ponechejte nevyplné pole. Pro nextcloud použijte pouze "
"základní url (<code>/remote.php/webdav/</code> bude přidán automaticky)."
#: .\cookbook\forms.py:263
@ -529,7 +529,7 @@ msgstr "Dávková úprava receptu"
#: .\cookbook\templates\batch\edit.html:20
msgid "Add the specified keywords to all recipes containing a word"
msgstr "Přidat štítek ke všem receptům, které obsahují specifické slovo."
msgstr "Přidat štítek ke všem receptům, které obsahují specifické slovo"
#: .\cookbook\templates\batch\monitor.html:6 .\cookbook\views\edit.py:66
msgid "Sync"

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.7 on 2024-01-14 23:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0207_space_logo_color_128_space_logo_color_144_and_more'),
]
operations = [
migrations.AddField(
model_name='space',
name='app_name',
field=models.CharField(blank=True, max_length=40, null=True),
),
migrations.AddField(
model_name='userpreference',
name='max_owned_spaces',
field=models.IntegerField(default=100),
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2.7 on 2024-01-17 21:12
# Generated by Django 4.2.7 on 2024-01-17 21:49
import cookbook.models
from django.conf import settings
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0207_space_logo_color_128_space_logo_color_144_and_more'),
('cookbook', '0208_space_app_name_userpreference_max_owned_spaces'),
]
operations = [

View File

@ -24,7 +24,7 @@ from PIL import Image
from treebeard.mp_tree import MP_Node, MP_NodeManager
from recipes.settings import (COMMENT_PREF_DEFAULT, FRACTION_PREF_DEFAULT, KJ_PREF_DEFAULT,
SORT_TREE_BY_NAME, STICKY_NAV_PREF_DEFAULT)
SORT_TREE_BY_NAME, STICKY_NAV_PREF_DEFAULT, MAX_OWNED_SPACES_PREF_DEFAULT)
def get_user_display_name(self):
@ -288,7 +288,7 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
nav_logo = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_nav_logo')
nav_bg_color = models.CharField(max_length=8, default='', blank=True, )
nav_text_color = models.CharField(max_length=16, choices=NAV_TEXT_COLORS, default=BLANK)
app_name = models.CharField(max_length=40, null=True, blank=True, )
logo_color_32 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_32')
logo_color_128 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_128')
logo_color_144 = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_logo_color_144')
@ -435,7 +435,7 @@ class UserPreference(models.Model, PermissionModelMixin):
nav_text_color = models.CharField(max_length=16, choices=NAV_TEXT_COLORS, default=DARK)
nav_show_logo = models.BooleanField(default=True)
nav_sticky = models.BooleanField(default=STICKY_NAV_PREF_DEFAULT)
max_owned_spaces = models.IntegerField(default=MAX_OWNED_SPACES_PREF_DEFAULT)
default_unit = models.CharField(max_length=32, default='g')
use_fractions = models.BooleanField(default=FRACTION_PREF_DEFAULT)
use_kj = models.BooleanField(default=KJ_PREF_DEFAULT)
@ -460,6 +460,15 @@ class UserPreference(models.Model, PermissionModelMixin):
created_at = models.DateTimeField(auto_now_add=True)
objects = ScopedManager(space='space')
def save(self, *args, **kwargs):
if not self.pk:
self.max_owned_spaces = MAX_OWNED_SPACES_PREF_DEFAULT
self.comments = COMMENT_PREF_DEFAULT
self.nav_sticky = STICKY_NAV_PREF_DEFAULT
self.use_kj = KJ_PREF_DEFAULT
self.use_fractions = FRACTION_PREF_DEFAULT
return super().save(*args, **kwargs)
def __str__(self):
return str(self.user)

View File

@ -686,8 +686,7 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
properties = validated_data.pop('properties', None)
obj, created = Food.objects.get_or_create(
name=name, plural_name=plural_name, space=space, properties_food_unit=properties_food_unit,
obj, created = Food.objects.get_or_create(name=name, plural_name=plural_name, space=space, properties_food_unit=properties_food_unit,
defaults=validated_data)
if properties and len(properties) > 0:
@ -1276,8 +1275,7 @@ class InviteLinkSerializer(WritableNestedModelSerializer):
if obj.email:
try:
if InviteLink.objects.filter(
space=self.context['request'].space,
if InviteLink.objects.filter(space=self.context['request'].space,
created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(
self.context['request'].user.get_user_display_name())
@ -1433,14 +1431,11 @@ class RecipeExportSerializer(WritableNestedModelSerializer):
class RecipeShoppingUpdateSerializer(serializers.ModelSerializer):
list_recipe = serializers.IntegerField(
write_only=True, allow_null=True, required=False,
list_recipe = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("Existing shopping list to update"))
ingredients = serializers.IntegerField(
write_only=True, allow_null=True, required=False, help_text=_(
ingredients = serializers.IntegerField(write_only=True, allow_null=True, required=False, help_text=_(
"List of ingredient IDs from the recipe to add, if not provided all ingredients will be added."))
servings = serializers.IntegerField(
default=1, write_only=True, allow_null=True, required=False, help_text=_(
servings = serializers.IntegerField(default=1, write_only=True, allow_null=True, required=False, help_text=_(
"Providing a list_recipe ID and servings of 0 will delete that shopping list."))
class Meta:
@ -1449,14 +1444,11 @@ class RecipeShoppingUpdateSerializer(serializers.ModelSerializer):
class FoodShoppingUpdateSerializer(serializers.ModelSerializer):
amount = serializers.IntegerField(
write_only=True, allow_null=True, required=False,
amount = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("Amount of food to add to the shopping list"))
unit = serializers.IntegerField(
write_only=True, allow_null=True, required=False,
unit = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("ID of unit to use for the shopping list"))
delete = serializers.ChoiceField(
choices=['true'], write_only=True, allow_null=True, allow_blank=True,
delete = serializers.ChoiceField(choices=['true'], write_only=True, allow_null=True, allow_blank=True,
help_text=_("When set to true will delete all food from active shopping lists."))
class Meta:

View File

@ -1,55 +0,0 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% load django_tables2 %}
{% block title %}{% trans 'List' %}{% endblock %}
{% block content %}
{% if request.resolver_match.url_name in 'list_storage,list_recipe_import,list_sync_log' %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'data_sync' %}">{% trans 'External Recipes' %}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ title }}</li>
</ol>
</nav>
{% endif %}
<div class="table-container">
<span class="col col-md-9">
<h3 style="margin-bottom: 2vh">{{ title }} {% trans 'List' %}</h3>
</span>
{% if filter %}
<br/>
<br/>
<form action="." method="get">
{% csrf_token %}
{{ filter.form|crispy }}
<button type="submit" class="btn btn-success">{% trans 'Filter' %}</button>
</form>
{% endif %}
{% if import_btn %}
<a href="{% url 'data_batch_import' %}" class="btn btn-warning">{% trans 'Import all' %}</a>
<br/>
<br/>
{% endif %}
{% for table in tables %}
<span class="col col-md-9">
<h3 style="margin-bottom: 2vh">{{ table.attrs.table_name }} {% trans 'List' %}
{% if table.attrs.create_url %}
<a href="{% url table.attrs.create_url %}"> <i class="fas fa-plus-circle"></i> </a>
{% endif %}
</h3>
</span>
{% render_table table %}
{% endfor %}
</div>
{% endblock content %}

View File

@ -10,17 +10,17 @@ register = template.Library()
@register.simple_tag
def theme_values(request):
return get_theming_values(request)
def get_theming_values(request):
space = None
if space in request and request.space:
if getattr(request,'space',None):
space = request.space
if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0:
with scopes_disabled():
space = Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first()
return get_theming_values(space, request.user)
def get_theming_values(space, user):
themes = {
UserPreference.BOOTSTRAP: 'themes/bootstrap.min.css',
UserPreference.FLATLY: 'themes/flatly.min.css',
@ -46,23 +46,24 @@ def get_theming_values(space, user):
'nav_bg_color': '#ddbf86',
'nav_text_class': 'navbar-light',
'sticky_nav': 'position: sticky; top: 0; left: 0; z-index: 1000;',
'app_name': 'Tandoor Recipes',
}
if user.is_authenticated:
if user.userpreference.theme in themes:
tv['theme'] = static(themes[user.userpreference.theme])
if user.userpreference.nav_bg_color:
tv['nav_bg_color'] = user.userpreference.nav_bg_color
if user.userpreference.nav_text_color and user.userpreference.nav_text_color in nav_text_type_mapping:
tv['nav_text_class'] = nav_text_type_mapping[user.userpreference.nav_text_color]
if not user.userpreference.nav_sticky:
if request.user.is_authenticated:
if request.user.userpreference.theme in themes:
tv['theme'] = static(themes[request.user.userpreference.theme])
if request.user.userpreference.nav_bg_color:
tv['nav_bg_color'] = request.user.userpreference.nav_bg_color
if request.user.userpreference.nav_text_color and request.user.userpreference.nav_text_color in nav_text_type_mapping:
tv['nav_text_class'] = nav_text_type_mapping[request.user.userpreference.nav_text_color]
if not request.user.userpreference.nav_sticky:
tv['sticky_nav'] = ''
if space:
for logo in list(tv.keys()):
if logo.startswith('logo_color_') and getattr(space, logo, None):
tv[logo] = getattr(space, logo).file.url
if space.custom_space_theme:
tv['custom_theme'] = space.custom_space_theme.file.url
if space.space_theme in themes:
@ -73,4 +74,6 @@ def get_theming_values(space, user):
tv['nav_bg_color'] = space.nav_bg_color
if space.nav_text_color and space.nav_text_color in nav_text_type_mapping:
tv['nav_text_class'] = nav_text_type_mapping[space.nav_text_color]
if space.app_name:
tv['app_name'] = space.app_name
return tv

View File

@ -1,36 +1,68 @@
from django.contrib import auth
from django.templatetags.static import static
from django.test import RequestFactory
from django_scopes import scopes_disabled
from cookbook.models import Space, UserPreference, UserFile
from cookbook.templatetags.theming_tags import theme_values, get_theming_values
def test_theming_function(space_1, u1_s1):
user = auth.get_user(u1_s1)
# uf = UserFile.objects.create(name='test', space=space_1, created_by=user) #TODO add file tests
user = auth.get_user(u1_s1)
request = RequestFactory()
request.user = auth.get_user(u1_s1)
request.space = space_1
assert get_theming_values(space_1, user)['theme'] == static('themes/tandoor.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#ddbf86'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-light'
assert get_theming_values(space_1, user)['nav_logo'] == static('assets/brand_logo.png')
assert get_theming_values(space_1, user)['sticky_nav'] == 'position: sticky; top: 0; left: 0; z-index: 1000;'
# defaults apply without setting anything (user preference is automatically created with these defaults)
assert get_theming_values(request)['theme'] == static('themes/tandoor.min.css')
assert get_theming_values(request)['nav_bg_color'] == '#ddbf86'
assert get_theming_values(request)['nav_text_class'] == 'navbar-light'
assert get_theming_values(request)['nav_logo'] == static('assets/brand_logo.png')
assert get_theming_values(request)['sticky_nav'] == 'position: sticky; top: 0; left: 0; z-index: 1000;'
assert get_theming_values(request)['app_name'] == 'Tandoor Recipes'
user.userpreference.theme = UserPreference.TANDOOR_DARK
user.userpreference.nav_bg_color = '#ffffff'
user.userpreference.nav_text_color = UserPreference.LIGHT
user.userpreference.nav_sticky = False
user.userpreference.save()
with scopes_disabled():
up = UserPreference.objects.filter(user=request.user).first()
up.theme = UserPreference.TANDOOR_DARK
up.nav_bg_color = '#ffffff'
up.nav_text_color = UserPreference.LIGHT
up.nav_sticky = False
up.save()
assert get_theming_values(space_1, user)['theme'] == static('themes/tandoor_dark.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#ffffff'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-dark'
assert get_theming_values(space_1, user)['sticky_nav'] == ''
request = RequestFactory()
request.user = auth.get_user(u1_s1)
request.space = space_1
# user values apply if only those are present
assert get_theming_values(request)['theme'] == static('themes/tandoor_dark.min.css')
assert get_theming_values(request)['nav_bg_color'] == '#ffffff'
assert get_theming_values(request)['nav_text_class'] == 'navbar-dark'
assert get_theming_values(request)['sticky_nav'] == ''
assert get_theming_values(request)['app_name'] == 'Tandoor Recipes'
space_1.space_theme = Space.BOOTSTRAP
space_1.nav_bg_color = '#000000'
space_1.nav_text_color = UserPreference.DARK
space_1.app_name = 'test_app_name'
space_1.save()
assert get_theming_values(space_1, user)['theme'] == static('themes/bootstrap.min.css')
assert get_theming_values(space_1, user)['nav_bg_color'] == '#000000'
assert get_theming_values(space_1, user)['nav_text_class'] == 'navbar-light'
request = RequestFactory()
request.user = auth.get_user(u1_s1)
request.space = space_1
# space settings apply when set
assert get_theming_values(request)['theme'] == static('themes/bootstrap.min.css')
assert get_theming_values(request)['nav_bg_color'] == '#000000'
assert get_theming_values(request)['nav_text_class'] == 'navbar-light'
assert get_theming_values(request)['app_name'] == 'test_app_name'
user.userspace_set.all().delete()
request = RequestFactory()
request.user = auth.get_user(u1_s1)
# default user settings should apply when user has no space
assert get_theming_values(request)['nav_bg_color'] == '#ffffff'
assert get_theming_values(request)['nav_text_class'] == 'navbar-dark'
assert get_theming_values(request)['nav_logo'] == static('assets/brand_logo.png')

View File

@ -51,7 +51,7 @@ router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
router.register(r'space', api.SpaceViewSet)
router.register(r'step', api.StepViewSet)
router.register(r'storage', api.StorageViewSet)
router.register(r'home-assistant-config', api.ConnectorConfigConfigViewSet)
router.register(r'connector-config', api.ConnectorConfigConfigViewSet)
router.register(r'supermarket', api.SupermarketViewSet)
router.register(r'supermarket-category', api.SupermarketCategoryViewSet)
router.register(r'supermarket-category-relation', api.SupermarketCategoryRelationViewSet)

View File

@ -87,8 +87,7 @@ def invite_link(request):
InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, space=request.space).all())
RequestConfig(request, paginate={'per_page': 25}).configure(table)
return render(
request, 'generic/list_template.html', {
return render(request, 'generic/list_template.html', {
'title': _("Invite Links"),
'table': table,
'create_url': 'new_invite_link'

View File

@ -31,6 +31,7 @@ from cookbook.helper.permission_helper import (group_required, has_group_permiss
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference,
ShareLink, Space, UserSpace, ViewLog)
from cookbook.tables import CookLogTable, ViewLogTable
from cookbook.templatetags.theming_tags import get_theming_values
from cookbook.version_info import VERSION_INFO
from recipes.settings import PLUGINS, BASE_DIR
@ -78,6 +79,11 @@ def space_overview(request):
messages.add_message(request, messages.WARNING, _('This feature is not available in the demo version!'))
else:
if create_form.is_valid():
if Space.objects.filter(created_by=request.user).count() >= request.user.userpreference.max_owned_spaces:
messages.add_message(request, messages.ERROR,
_('You have the reached the maximum amount of spaces that can be owned by you.') + f' ({request.user.userpreference.max_owned_spaces})')
return HttpResponseRedirect(reverse('view_space_overview'))
created_space = Space.objects.create(
name=create_form.cleaned_data['name'],
created_by=request.user,
@ -481,29 +487,24 @@ def report_share_abuse(request, token):
def web_manifest(request):
icons = [
{"src": static("/assets/logo_color.svg"), "sizes": "any"},
{"src": static("/assets/logo_color144.png"), "type": "image/png", "sizes": "144x144"},
{"src": static("/assets/logo_color512.png"), "type": "image/png", "sizes": "512x512"}
]
theme_values = get_theming_values(request)
if request.user.is_authenticated and getattr(request.space, 'logo_color_svg') and getattr(request.space, 'logo_color_144') and getattr(request.space, 'logo_color_512'):
icons = [
{"src": request.space.logo_color_svg.file.url, "sizes": "any"},
{"src": request.space.logo_color_144.file.url, "type": "image/png", "sizes": "144x144"},
{"src": request.space.logo_color_512.file.url, "type": "image/png", "sizes": "512x512"}
{"src": theme_values['logo_color_svg'], "sizes": "any"},
{"src": theme_values['logo_color_144'], "type": "image/png", "sizes": "144x144"},
{"src": theme_values['logo_color_512'], "type": "image/png", "sizes": "512x512"}
]
manifest_info = {
"name": "Tandoor Recipes",
"short_name": "Tandoor",
"name": theme_values['app_name'],
"short_name": theme_values['app_name'],
"description": _("Manage recipes, shopping list, meal plans and more."),
"icons": icons,
"start_url": "./search",
"background_color": "#ffcb76",
"background_color": theme_values['nav_bg_color'],
"display": "standalone",
"scope": ".",
"theme_color": "#ffcb76",
"theme_color": theme_values['nav_bg_color'],
"shortcuts": [
{
"name": _("Plan"),

View File

@ -524,6 +524,18 @@ The default value for the user preference 'sticky navigation' (always show navba
STICKY_NAV_PREF_DEFAULT=1
```
#### Max owned spaces
> default `100` - options: `0-X`
The default for the number of spaces a user can own. By setting to 0 space creation for users will be disabled.
Superusers can always bypass this limit.
```
MAX_OWNED_SPACES_PREF_DEFAULT=100
```
### Cosmetic / Preferences
#### Timezone

View File

@ -57,7 +57,8 @@ COMMENT_PREF_DEFAULT = bool(int(os.getenv('COMMENT_PREF_DEFAULT', True)))
FRACTION_PREF_DEFAULT = bool(int(os.getenv('FRACTION_PREF_DEFAULT', False)))
KJ_PREF_DEFAULT = bool(int(os.getenv('KJ_PREF_DEFAULT', False)))
STICKY_NAV_PREF_DEFAULT = bool(int(os.getenv('STICKY_NAV_PREF_DEFAULT', True)))
UNAUTHENTICATED_THEME_FROM_SPACE = 2 #int(os.getenv('UNAUTHENTICATED_THEME_FROM_SPACE', 0))
MAX_OWNED_SPACES_PREF_DEFAULT = int(os.getenv('MAX_OWNED_SPACES_PREF_DEFAULT', 100))
UNAUTHENTICATED_THEME_FROM_SPACE = int(os.getenv('UNAUTHENTICATED_THEME_FROM_SPACE', 0))
# minimum interval that users can set for automatic sync of shopping lists
SHOPPING_MIN_AUTOSYNC_INTERVAL = int(

View File

@ -16,14 +16,14 @@
"file_upload_disabled": "Nahrávání souborů není povoleno pro Váš prostor.",
"warning_space_delete": "Můžete smazat váš prostor včetně všech receptů, nákupních seznamů, jídelníčků a všeho ostatního, co jste vytvořili. Tuto akci nemůžete vzít zpět! Jste si jisti, že chcete pokračovat?",
"food_inherit_info": "Pole potravin, která budou standardně zděděna.",
"step_time_minutes": "Nastavte čas v minutách",
"step_time_minutes": "Délka kroku v minutách",
"confirm_delete": "Jste si jisti že chcete odstranit tento {objekt}?",
"import_running": "Probíhá import, čekejte prosím!",
"all_fields_optional": "Všechna pole jsou nepviná a mohou být ponechána prázdná.",
"convert_internal": "Převést na interní recept",
"show_only_internal": "Zobrazit pouze interní recepty",
"show_split_screen": "Rozdělené zobrazení",
"Log_Recipe_Cooking": "",
"Log_Recipe_Cooking": "Záznam vaření receptu",
"External_Recipe_Image": "Externí obrázek receptu",
"Add_to_Shopping": "Přidat k nákupu",
"Add_to_Plan": "Přidat do jídelníčku",
@ -35,8 +35,8 @@
"Hide_as_header": "Skryj jako nadpis",
"Add_nutrition_recipe": "Přidat nutriční hodnoty",
"Remove_nutrition_recipe": "Smazat nutriční hodnoty",
"Copy_template_reference": "",
"Save_and_View": "Uložit & Zobrazit",
"Copy_template_reference": "Zkopírovat šablonu odkazu",
"Save_and_View": "Uložit a zobrazit",
"Manage_Books": "Spravovat kuchařky",
"Meal_Plan": "Jídelníček",
"Select_Book": "Vyber kuchařku",
@ -44,19 +44,19 @@
"Recipe_Image": "Obrázek k receptu",
"Import_finished": "Import dokončen",
"View_Recipes": "Zobrazit recepty",
"Log_Cooking": "",
"Log_Cooking": "Zaznamenat vaření",
"New_Recipe": "Nový recept",
"Url_Import": "Import pomocí URL odkazu",
"Reset_Search": "Zrušit filtry vyhledávání",
"Recently_Viewed": "Naposledy prohlížené",
"Load_More": "Načíst další",
"New_Keyword": "Nové klíčové slovo",
"Delete_Keyword": "Smazat klíčové slovo",
"Edit_Keyword": "Upravit klíčové slovo",
"New_Keyword": "Nový štítek",
"Delete_Keyword": "Smazat štítek",
"Edit_Keyword": "Upravit štítek",
"Edit_Recipe": "Upravit recept",
"Move_Keyword": "Přesunout klíčové slovo",
"Merge_Keyword": "Sloučit klíčové slovo",
"Hide_Keywords": "Skrýt klíčové slovo",
"Move_Keyword": "Přesunout štítek",
"Merge_Keyword": "Sloučit štítek",
"Hide_Keywords": "Skrýt štítek",
"Hide_Recipes": "Skrýt recept",
"Move_Up": "Nahoru",
"Move_Down": "Dolů",
@ -76,14 +76,14 @@
"Private_Recipe_Help": "Recept můžete zobrazit pouze vy a lidé, se kterými jej sdílíte.",
"reusable_help_text": "Má-li pozvánka platit pro více než jednoho uživatele.",
"Add_Step": "Přidat krok",
"Keywords": "Klíčová slova",
"Keywords": "Štítky",
"Books": "Kuchařky",
"Proteins": "Proteiny",
"Fats": "Tuky",
"Carbohydrates": "Sacharidy",
"Calories": "Kalorie",
"Energy": "Energie",
"Nutrition": "",
"Nutrition": "Výživové hodnoty",
"Date": "Datum",
"Share": "Sdílet",
"Automation": "Automatizace",
@ -153,7 +153,7 @@
"Hide_Food": "Skrýt potravinu",
"Food_Alias": "Přezdívka potraviny",
"Unit_Alias": "Přezdívka jednotky",
"Keyword_Alias": "Přezdívka klíčového slova",
"Keyword_Alias": "Přezdívka štítku",
"Delete_Food": "Smazat potravinu",
"No_ID": "ID nenalezeno, odstranění není možné.",
"Meal_Plan_Days": "Budoucí jídelníčky",
@ -162,7 +162,7 @@
"Food": "Potravina",
"Original_Text": "Původní text",
"Recipe_Book": "Kuchařka",
"del_confirmation_tree": "Jste si jistí, že chcete odstranit {source} se všemi pořazenými ?",
"del_confirmation_tree": "Jste si jistí, že chcete odstranit {source} i se všemi potomky?",
"delete_title": "Smazat {type}",
"create_title": "Nový {type}",
"edit_title": "Upravit {type}",
@ -170,7 +170,7 @@
"Type": "Typ",
"Description": "Popis",
"Recipe": "Recept",
"tree_root": "",
"tree_root": "Kořen stromu",
"Icon": "Ikona",
"Unit": "Jednotka",
"Decimals": "Desetinná místa",
@ -179,7 +179,7 @@
"New_Unit": "Nová jednotka",
"Create_New_Shopping Category": "Vytvořit novou nákupní kategorii",
"Create_New_Food": "Přidat novou potravinu",
"Create_New_Keyword": "Přidat nové klíčové slovo",
"Create_New_Keyword": "Přidat nový štítek",
"Create_New_Unit": "Přidat novou jednotku",
"Create_New_Meal_Type": "Přidat nový druh jídla",
"Create_New_Shopping_Category": "Přidat novou nákupní kategorii",
@ -254,7 +254,7 @@
"SupermarketCategoriesOnly": "Pouze kategorie obchodu",
"MoveCategory": "Přesunout do: ",
"CountMore": "...+{count} víc",
"IgnoreThis": "Nikdy automaticky nepřídávat {food} na nákupní seznam",
"IgnoreThis": "Nikdy nepřidávat automaticky {food} na nákupní seznam",
"DelayFor": "Odložit na {hours} hodin",
"Warning": "Varování",
"NoCategory": "Není vybrána žádná kategorie.",
@ -271,7 +271,7 @@
"default_delay": "Výchozí doba odložení v hodinách",
"plan_share_desc": "Nové položky v jídelníčku budou automaticky sdíleny s vybranými uživateli.",
"shopping_share_desc": "Uživatelé uvidí všechny položky na vašem nákupním seznamu. Abyste viděli položky na jejich seznamu, musí si přidat vás.",
"shopping_auto_sync_desc": "Nastavením 0 dojde k vypnutí automatické synchronizace. Při prohlížení nákupního seznamu je vždy po uplynutí nastaveného počtu vteřin aktualizován o změny, které mohli provést jiní uživatelé. To je užitečné, pokud nakupujete ve více lidech, ale může používat více dat.",
"shopping_auto_sync_desc": "Zadáním hodnoty 0 se automatická synchronizace vypne. Při prohlížení nákupního seznamu se seznam aktualizuje po stanovených sekundách, aby se synchronizovaly změny, které mohl provést někdo jiný. To je užitečné při nakupování s více lidmi, ale spotřebovávají se při tom mobilní data.",
"mealplan_autoadd_shopping_desc": "Automaticky podle jídelníčku přidat ingredience na nákupní seznam.",
"mealplan_autoexclude_onhand_desc": "Nepřidávat ingredience, které jsou k dispozici, na nákupní seznam, když je vytvořen podle jídelníčku (manuálně nebo automaticky).",
"mealplan_autoinclude_related_desc": "Když je nákupní seznam vytvořen podle jídelníčku, přidat i položky z přidružených receptů.",
@ -280,7 +280,7 @@
"Coming_Soon": "Již brzy",
"Auto_Planner": "Automatický plánovač",
"New_Cookbook": "Nová kuchařka",
"Hide_Keyword": "Skrýt klíčová slova",
"Hide_Keyword": "Skrýt štítky",
"Hour": "Hodina",
"Hours": "Hodiny",
"Day": "Den",
@ -328,7 +328,7 @@
"OnHand_help": "Potravina je v inventáři a nebude automaticky přidána na nákupní seznam. Status \"k dipozici\" je sdílen s nakupujícími uživateli.",
"ignore_shopping_help": "Nikdy nepřidávat potravinu na nákupní seznam (např. voda)",
"shopping_category_help": "Obchody mohou být seřazeny a třízeny pomocí nákupních kategorií podle rozvržení uliček a regálů.",
"food_recipe_help": "",
"food_recipe_help": "Zde uvedený recept bude připojen k jakémukoli jinému receptu, který používá tuto potravinu",
"Foods": "Potraviny",
"Account": "Účet",
"Cosmetic": "Zobrazení",
@ -338,7 +338,7 @@
"simple_mode": "Jednoduchý režim",
"advanced": "Pokročilé",
"fields": "Pole",
"show_keywords": "Zobrazit klíčová slova",
"show_keywords": "Zobrazit štítky",
"show_foods": "Zobrazit potraviny",
"show_books": "Zobrazit kuchařky",
"show_rating": "Zobrazit hodnocení",
@ -359,8 +359,8 @@
"times_cooked": "Kolkrát vařeno",
"date_created": "Datum vytvoření",
"show_sortby": "Zobrazit Seřazeno podle",
"search_rank": "",
"make_now": "",
"search_rank": "Skóre shody",
"make_now": "Udělat hned",
"recipe_filter": "Filtrovat recepty",
"book_filter_help": "Zahrnout i recepty z filtru stejně jako manuálně přidané.",
"review_shopping": "Zkontrolovat nákupní položky před uložením",
@ -392,9 +392,9 @@
"search_create_help_text": "Vytvořit nový recept přímo v Tandoor.",
"warning_duplicate_filter": "Varování: Kvůli technickým omezení může použití několika filtrů se stejnou kombinací (a/nebo/ne) přinést neočekávaný výsledek.",
"reset_children": "Resetovat propsání podřízených",
"reset_children_help": "",
"reset_children_help": "Přepíše všechny potomky hodnotami dle nastavení propisovaných polí. Pokud není nastaveno pole Propisovaná pole podřízených, tak bude nastaveno pole Propsat hodnoty polí na aktuální hodnotu.",
"reset_food_inheritance": "Resetovat propisování",
"reset_food_inheritance_info": "",
"reset_food_inheritance_info": "Obnoví u všech potravin propisovaná pole na výchozí hodnotu a nastavit daná pole dle nadřazené položky.",
"substitute_help": "Při hledání podle ingrediencí, které jsou k dispozici, jsou zvažovány náhrady.",
"substitute_siblings_help": "Všechny potraviny, které sdílejí nadřazenou položku jsou považovány za náhrady.",
"substitute_children_help": "Všechny potraviny, které jsou podřízeny této, jsou považovány za náhražky.",
@ -425,8 +425,8 @@
"Social_Authentication": "Přihlašování pomocí účtů sociálních sítí",
"Random Recipes": "Náhodné recepty",
"parameter_count": "Parametr {count}",
"select_keyword": "Vybrat klíčové slovo",
"add_keyword": "Přidat klíčové slovo",
"select_keyword": "Vybrat štítek",
"add_keyword": "Přidat štítek",
"select_file": "Vybrat soubor",
"select_recipe": "Vybrat recept",
"select_unit": "Vybrat jednotku",
@ -439,7 +439,7 @@
"Username": "Uživatelské jméno",
"First_name": "Jméno",
"Last_name": "Příjmení",
"Keyword": "Klíčové slovo",
"Keyword": "Štítek",
"Advanced": "Rozšířené",
"Page": "Stránka",
"Single": "Jednoduchý",
@ -479,10 +479,10 @@
"Create Recipe": "Vytvořit recept",
"Import Recipe": "Importovat recept",
"per_serving": "na porci",
"open_data_help_text": "Projekt Tandoor Open Data nabízí komunitou poskytnutá data pro Tandoor. Toto pole je automaticky vyplněno při importu a může být později upraveno.",
"Data_Import_Info": "Rozšiřte svůj prostor o seznamy potravin, jednotek a další spravované komunitou, a vylepšete tak svoji sbírku receptů.",
"open_data_help_text": "Projekt Tandoor Open Data nabízí komunitou poskytnutá otevřená data pro Tandoor. Toto pole se vyplní automaticky při importu a umožňuje budoucí aktualizace.",
"Data_Import_Info": "Rozšiřte svůj prostor o seznamy potravin, jednotek a dalších položek spravovaných komunitou, a vylepšete tak svoji sbírku receptů.",
"Update_Existing_Data": "Aktualizovat existující data",
"Use_Metric": "Používat metrické jednotky",
"Use_Metric": "Použít metrické jednotky",
"Learn_More": "Zjistit víc",
"converted_unit": "Převedená jendotka",
"converted_amount": "Převedené množství",
@ -490,9 +490,67 @@
"base_amount": "Základní množství",
"Datatype": "Datový typ",
"Number of Objects": "Počet Objektů",
"Property": "Vlastnost",
"Property": "Nutriční vlastnost",
"Conversion": "Převod",
"Properties": "Vlastnosti",
"recipe_property_info": "Můžete také přidávat vlastnosti k Vašim potravinám. Hodnoty budou automaticky přepočteny na základě Vašeho receptu!",
"total": "celkem"
"Properties": "Nutriční vlastnosti",
"recipe_property_info": "Nutriční hodnoty se automaticky dopočtou podle receptu, pokud zadáte nutriční hodnoty přímo potravinám!",
"total": "celkem",
"CustomTheme": "Vlastní téma",
"CustomThemeHelp": "Přepsat styly vybraného motivu nahráním vlastního souboru CSS.",
"CustomLogoHelp": "Nahrajte čtvercové obrázky různých velikostí pro úpravu loga v záložce prohlížeče a v nainstalované webové aplikaci.",
"err_importing_recipe": "Během importu receptu došlo k chybě!",
"Open_Data_Slug": "Identifikátor pro otevřená data",
"Open_Data_Import": "Import otevřených dat",
"FDC_Search": "Vyhledávání v FDC",
"property_type_fdc_hint": "Data z databáze FDC mohou automaticky čerpat pouze typy vlastností se zadaným FDC ID",
"StartDate": "Počáteční datum",
"EndDate": "Konečné datum",
"Welcome": "Vítejte",
"Property_Editor": "Editovat nutriční vlastnosti",
"FDC_ID": "FDC ID",
"FDC_ID_help": "ID v databázi FDC",
"CustomImageHelp": "Nahrajte obrázek, který se zobrazí v přehledu prostoru.",
"CustomNavLogoHelp": "Nahrajte obrázek, který se má zobrazit jako logo v navigačním panelu.",
"CustomLogos": "Vlastní loga",
"OrderInformation": "Položky jsou seřazeny podle čísel od malých po velké.",
"kg": "kilogram [kg] (metrický systém, hmotnost)",
"g": "gram [g] (metrický systém, hmotnost)",
"ounce": "unce [oz] (imperiální systém, hmotnost)",
"pound": "libra (hmotnost)",
"Properties_Food_Unit": "Jednotka nutriční vlastnosti",
"Properties_Food_Amount": "Množství nutriční vlastnosti",
"tsp": "lžička [tsp] (US, objem)",
"imperial_tsp": "lžička imperiální [imp tbsp] (UK, objem)",
"Transpose_Words": "Transponovat slova",
"show_step_ingredients_setting": "Zobrazit ingredience u jednotlivých kroků receptu",
"Logo": "Logo",
"Show_Logo": "Zobrazit logo",
"show_step_ingredients_setting_help": "Zobrazí tabulku ingrediencí vedle kroků receptu. Nastavení se aplikuje při vytváření receptu a následně je možné volbu změnit při úpravě receptu.",
"show_step_ingredients": "Zobrazit ingredience u kroku",
"hide_step_ingredients": "Skrýt ingredience u kroku",
"Show_Logo_Help": "Zobrazit logo Tandoor nebo logo prostoru na navigačním panelu.",
"Nav_Text_Mode_Help": "Pro každé téma se chová jinak.",
"Space_Cosmetic_Settings": "Některá kosmetická nastavení mohou měnit správci prostoru a budou mít přednost před nastavením klienta pro daný prostor.",
"Nav_Text_Mode": "Textový režim navigace",
"show_ingredients_table": "Zobrazit tabulku složek vedle textu kroku",
"pint": "pinta [pt] (US, objem)",
"quart": "quart [qt] (US, objem)",
"imperial_fluid_ounce": "tekutá unce imperiální [imp fl oz] (UK, objem)",
"imperial_pint": "pinta imperiální [imp pt] (UK, objem)",
"imperial_quart": "quart imperiální [imp qt] (UK, objem)",
"gallon": "galon [gal] (US, objem)",
"tbsp": "lžíce [tbsp] (US, objem)",
"imperial_gallon": "galon imperiální [imp gal] (UK, objem)",
"imperial_tbsp": "lžíce imperiální [imp tbsp] (UK, objem)",
"Choose_Category": "Vyberte kategorii",
"Back": "Zpět",
"Food_Replace": "Nahrazení v potravině",
"Unit_Replace": "Nahrazení v jednotce",
"Name_Replace": "Nahrazení v názvu",
"ml": "mililitr [ml] (metrický systém, objem)",
"l": "litr [l] (metrický systém, objem)",
"fluid_ounce": "tekutá unce [fl oz] (US, objem)",
"make_now_count": "Nejvyšší počet chybějících ingrediencí",
"Alignment": "Zarovnání",
"Never_Unit": "Není jednotkou"
}

View File

@ -536,5 +536,24 @@
"Unit_Replace": "Einheit Ersetzen",
"quart": "\"Quart\" [qt] (US, Volumen)",
"imperial_quart": "Engl. \"Quart\" [imp qt] (UK, Volumen)",
"err_importing_recipe": "Beim Importieren des Rezeptes ist ein Fehler aufgetreten!"
"err_importing_recipe": "Beim Importieren des Rezeptes ist ein Fehler aufgetreten!",
"property_type_fdc_hint": "Nur Nährwerte mit einer FDC ID können automatisch Daten aus der FDC Datenbank beziehen",
"Property_Editor": "Nährwerte bearbeiten",
"CustomTheme": "Benutzerdefiniertes Theme",
"CustomThemeHelp": "Überschreiben Sie die Stile des ausgewählten Themes, indem Sie eine eigene CSS-Datei hochladen.",
"CustomLogoHelp": "Laden Sie quadratische Bilder in verschiedenen Größen hoch, um das Logo im Browsertab und der installierten Webanwendung zu ändern.",
"Show_Logo_Help": "Zeigen Sie das Tandoor- oder Space-Logo in der Navigationsleiste an.",
"Space_Cosmetic_Settings": "Einige optische Einstellungen können von Administratoren des Bereichs geändert werden und setzen die Client-Einstellungen für diesen Bereich außer Kraft.",
"Properties_Food_Amount": "Nährwertangaben",
"Properties_Food_Unit": "Nährwert Einheit",
"FDC_Search": "FDC Suche",
"Logo": "Logo",
"Show_Logo": "Logo anzeigen",
"Nav_Text_Mode": "Navigation Textmodus",
"Nav_Text_Mode_Help": "Verhält sich bei jedem Theme anders.",
"FDC_ID": "FDC ID",
"FDC_ID_help": "FDC Datenbank ID",
"CustomImageHelp": "Laden Sie ein Bild hoch, das in der Space-Übersicht angezeigt werden soll.",
"CustomNavLogoHelp": "Laden Sie ein Bild hoch, das als Logo für die Navigationsleiste verwendet werden soll.",
"CustomLogos": "Individuelle Logos"
}