mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-30 21:49:50 -05:00
Compare commits
73 Commits
1.4.4
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc82049f42 | ||
|
|
da8262a9b5 | ||
|
|
f0cf4a23e4 | ||
|
|
489c81c378 | ||
|
|
730344e326 | ||
|
|
7e6b1d3638 | ||
|
|
15f65cd711 | ||
|
|
dba205dafb | ||
|
|
5ae149a1b6 | ||
|
|
4bb2307007 | ||
|
|
be0088aec6 | ||
|
|
c56710ae0c | ||
|
|
1a420bc002 | ||
|
|
545e4f7af4 | ||
|
|
d2a148ae7d | ||
|
|
580591a69e | ||
|
|
409b438776 | ||
|
|
549175b56d | ||
|
|
0e3f5006b1 | ||
|
|
54043a0ae5 | ||
|
|
36fdc8cd9e | ||
|
|
87cf3b2289 | ||
|
|
adb4071fdb | ||
|
|
2a20f5e6e2 | ||
|
|
00f7ae3d66 | ||
|
|
f1f4e7ca8e | ||
|
|
6d7b3b8bfa | ||
|
|
7ebccf564d | ||
|
|
0421a1aa6c | ||
|
|
c118ab9a3c | ||
|
|
02a12cf724 | ||
|
|
f28ca41b7b | ||
|
|
6e677cf3cd | ||
|
|
d30a23f7ef | ||
|
|
88fea6f25d | ||
|
|
fc0b5bd738 | ||
|
|
5174f9939c | ||
|
|
8f9a489c7e | ||
|
|
fc72efac04 | ||
|
|
72f57cf671 | ||
|
|
85b95d1e96 | ||
|
|
35dee43f0b | ||
|
|
fb683bf230 | ||
|
|
a852f581ba | ||
|
|
cc417f1499 | ||
|
|
7f9da4c4fb | ||
|
|
31d3f9abee | ||
|
|
f9670e9833 | ||
|
|
465af8c1a4 | ||
|
|
ffe743e233 | ||
|
|
6b09731a55 | ||
|
|
182a94e0c7 | ||
|
|
2adaedfd1a | ||
|
|
5074326471 | ||
|
|
4807a16a0f | ||
|
|
af044f1002 | ||
|
|
cdf77c8796 | ||
|
|
e68bedf7eb | ||
|
|
5e21e7fa8e | ||
|
|
f49b39b216 | ||
|
|
0d24292f52 | ||
|
|
f3b7016be8 | ||
|
|
0f77c831c9 | ||
|
|
be48e57453 | ||
|
|
3b45ca18af | ||
|
|
da1b22c148 | ||
|
|
9dab21f972 | ||
|
|
ca9c96647e | ||
|
|
70e6585669 | ||
|
|
d0cb7a79f9 | ||
|
|
cfd24de72a | ||
|
|
54acfe3e39 | ||
|
|
2f8b479fdd |
2
.idea/dictionaries/vabene1111_PC.xml
generated
2
.idea/dictionaries/vabene1111_PC.xml
generated
@@ -3,6 +3,8 @@
|
||||
<words>
|
||||
<w>autosync</w>
|
||||
<w>chowdown</w>
|
||||
<w>cookingmachine</w>
|
||||
<w>cookit</w>
|
||||
<w>csrftoken</w>
|
||||
<w>gunicorn</w>
|
||||
<w>ical</w>
|
||||
|
||||
0
cookbook/cooking_machines/__init__.py
Normal file
0
cookbook/cooking_machines/__init__.py
Normal file
116
cookbook/cooking_machines/homeconnect_cookit.py
Normal file
116
cookbook/cooking_machines/homeconnect_cookit.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import json
|
||||
import random
|
||||
from datetime import timedelta
|
||||
|
||||
import requests
|
||||
from django.utils.timezone import now
|
||||
|
||||
from cookbook.models import CookingMachine
|
||||
|
||||
|
||||
# Tandoor is not affiliated in any way or form with the holders of Trademark or other right associated with the mentioned names. All mentioned protected names are purely used to identify to the user a certain device or integration.
|
||||
class HomeConnectCookit:
|
||||
AUTH_AUTHORIZE_URL = 'https://api.home-connect.com/security/oauth/authorize'
|
||||
AUTH_TOKEN_URL = 'https://api.home-connect.com/security/oauth/token'
|
||||
AUTH_REFRESH_URL = 'https://api.home-connect.com/security/oauth/token'
|
||||
|
||||
RECIPE_API_URL = 'https://prod.reu.rest.homeconnectegw.com/user-generated-recipes/server/api/v1/recipes'
|
||||
IMAGE_API_URL = 'https://prod.reu.rest.homeconnectegw.com/user-generated-recipes/server/api/v1/images'
|
||||
|
||||
CLIENT_ID = '' # TODO load from .env settings
|
||||
_CLIENT_SECRET = '' # TODO load from .env settings
|
||||
|
||||
_cooking_machine = None
|
||||
|
||||
def __init__(self, cooking_machine):
|
||||
self._cooking_machine = cooking_machine
|
||||
|
||||
def get_auth_link(self):
|
||||
return f"{self.AUTH_AUTHORIZE_URL}?client_id={self.CLIENT_ID}&response_type=code&scope=IdentifyAppliance%20Settings&state={random.randint(100000, 999999)}"
|
||||
|
||||
def _validate_token(self):
|
||||
if self._cooking_machine.access_token is None and self._cooking_machine.refresh_token is None:
|
||||
return False # user needs to login
|
||||
elif self._cooking_machine.access_token_expiry < now() + timedelta(minutes=10):
|
||||
return False # refresh token
|
||||
|
||||
def _refresh_access_token(self):
|
||||
token_response = requests.post(self.AUTH_REFRESH_URL, {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': self._cooking_machine.refresh_token,
|
||||
'client_secret': self._CLIENT_SECRET,
|
||||
})
|
||||
if token_response.status_code == 200:
|
||||
token_response_body = json.loads(token_response.content)
|
||||
self._cooking_machine.access_token = token_response_body['access_token']
|
||||
self._cooking_machine.access_token_expiry = now() + timedelta(seconds=(token_response_body['expires_in'] - (60 * 10)))
|
||||
self._cooking_machine.refresh_token = token_response_body['refresh_token']
|
||||
self._cooking_machine.refresh_token_expiry = now() + timedelta(days=58)
|
||||
self._cooking_machine.save()
|
||||
|
||||
def get_access_token(self, code):
|
||||
token_response = requests.post(self.AUTH_TOKEN_URL, {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'client_id': self.CLIENT_ID,
|
||||
'client_secret': self._CLIENT_SECRET,
|
||||
})
|
||||
if token_response.status_code == 200:
|
||||
token_response_body = json.loads(token_response.content)
|
||||
self._cooking_machine.access_token = token_response_body['access_token']
|
||||
self._cooking_machine.access_token_expiry = now() + timedelta(seconds=(token_response_body['expires_in'] - (60 * 10)))
|
||||
self._cooking_machine.refresh_token = token_response_body['refresh_token']
|
||||
self._cooking_machine.refresh_token_expiry = now() + timedelta(days=58)
|
||||
self._cooking_machine.save()
|
||||
|
||||
def _get_default_headers(self):
|
||||
auth_token = ''
|
||||
return {
|
||||
'authorization': f'Bearer {self._cooking_machine.access_token}',
|
||||
'accept-language': "en-US",
|
||||
"referer": "https://prod.reu.rest.homeconnectegw.com/user-generated- recipes/client/editor/recipedetails",
|
||||
"user-agent": "Mozilla/5.0 (Linux; Android 10; Android SDK built for x86 Build/QSR1.210802.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36",
|
||||
"x-requested-with": "com.bshg.homeconnect.android.release"
|
||||
}
|
||||
|
||||
def push_recipe(self, recipe):
|
||||
data = {
|
||||
"title": recipe.name,
|
||||
"description": recipe.description,
|
||||
"ingredients": [],
|
||||
"steps": [],
|
||||
"durations": {
|
||||
"totalTime": (recipe.working_time + recipe.waiting_time) * 60,
|
||||
"cookingTime": 0, # recipe.waiting_time * 60, #TODO cooking time must be sum of step duration attribute, otherwise creation fails
|
||||
"preparationTime": recipe.working_time * 60,
|
||||
},
|
||||
"keywords": [],
|
||||
"servings": {
|
||||
"amount": int(recipe.servings),
|
||||
"unit": 'portion', # required
|
||||
},
|
||||
"servingTipsStep": {
|
||||
"textInstructions": "Serve"
|
||||
},
|
||||
"complexityLevel": "medium",
|
||||
"image": {
|
||||
"url": "https://media3.bsh-group.com/Recipes/800x480/17062805_210217_My-own-recipe_Picture_188ppi.jpg",
|
||||
"mimeType": "image/jpeg"
|
||||
# TODO add image upload
|
||||
},
|
||||
"accessories": [], # TODO add once tandoor supports tools
|
||||
"legalDisclaimerApproved": True # TODO force user to approve disclaimer
|
||||
}
|
||||
for step in recipe.steps.all():
|
||||
data['steps'].append({
|
||||
"textInstructions": step.instruction
|
||||
})
|
||||
for i in step.ingredients.all():
|
||||
data['ingredients'].append({
|
||||
"amount": int(i.amount),
|
||||
"unit": i.unit.name,
|
||||
"name": i.food.name,
|
||||
})
|
||||
# TODO create synced recipe
|
||||
response = requests.post(f'{self.RECIPE_API_URL}', json=data, headers=self._get_default_headers())
|
||||
return response
|
||||
@@ -52,7 +52,6 @@ def has_group_permission(user, groups, no_cache=False):
|
||||
return cached_result
|
||||
|
||||
result = False
|
||||
print('running check', user, groups_allowed)
|
||||
if user.is_authenticated:
|
||||
if user_space := user.userspace_set.filter(active=True):
|
||||
if len(user_space) != 1:
|
||||
|
||||
@@ -7,7 +7,7 @@ from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.recipe_url_import import iso_duration_to_minutes
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Ingredient, Keyword, Recipe, Step
|
||||
from cookbook.models import Ingredient, Keyword, Recipe, Step, NutritionInformation
|
||||
|
||||
|
||||
class NextcloudCookbook(Integration):
|
||||
@@ -70,12 +70,21 @@ class NextcloudCookbook(Integration):
|
||||
recipe.steps.add(step)
|
||||
|
||||
if 'nutrition' in recipe_json:
|
||||
nutrition = {}
|
||||
try:
|
||||
recipe.nutrition.calories = recipe_json['nutrition']['calories'].replace(' kcal', '').replace(' ', '')
|
||||
recipe.nutrition.proteins = recipe_json['nutrition']['calories'].replace(' g', '').replace(',', '.').replace(' ', '')
|
||||
recipe.nutrition.fats = recipe_json['nutrition']['calories'].replace(' g', '').replace(',', '.').replace(' ', '')
|
||||
recipe.nutrition.carbohydrates = recipe_json['nutrition']['calories'].replace(' g', '').replace(',', '.').replace(' ', '')
|
||||
except Exception:
|
||||
if 'calories' in recipe_json['nutrition']:
|
||||
nutrition['calories'] = int(re.search(r'\d+', recipe_json['nutrition']['calories']).group())
|
||||
if 'proteinContent' in recipe_json['nutrition']:
|
||||
nutrition['proteins'] = int(re.search(r'\d+', recipe_json['nutrition']['proteinContent']).group())
|
||||
if 'fatContent' in recipe_json['nutrition']:
|
||||
nutrition['fats'] = int(re.search(r'\d+', recipe_json['nutrition']['fatContent']).group())
|
||||
if 'carbohydrateContent' in recipe_json['nutrition']:
|
||||
nutrition['carbohydrates'] = int(re.search(r'\d+', recipe_json['nutrition']['carbohydrateContent']).group())
|
||||
|
||||
if nutrition != {}:
|
||||
recipe.nutrition = NutritionInformation.objects.create(**nutrition, space=self.request.space)
|
||||
recipe.save()
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
for f in self.files:
|
||||
|
||||
2621
cookbook/locale/id/LC_MESSAGES/django.po
Normal file
2621
cookbook/locale/id/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
2621
cookbook/locale/tr/id/LC_MESSAGES/django.po
Normal file
2621
cookbook/locale/tr/id/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
31
cookbook/migrations/0185_cookingmachine.py
Normal file
31
cookbook/migrations/0185_cookingmachine.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 4.0.7 on 2022-10-02 11:51
|
||||
|
||||
import cookbook.models
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0184_alter_userpreference_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CookingMachine',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('type', models.CharField(choices=[('HOMECONNECT_COOKIT', 'HomeConnect CookIt')], max_length=128)),
|
||||
('name', models.CharField(max_length=128)),
|
||||
('serial', models.CharField(blank=True, max_length=512, null=True)),
|
||||
('description', models.TextField(blank=True, default='')),
|
||||
('access_token', models.CharField(blank=True, max_length=4096, null=True)),
|
||||
('access_token_expiry', models.DateTimeField(blank=True, null=True)),
|
||||
('refresh_token', models.CharField(blank=True, max_length=4096, null=True)),
|
||||
('refresh_token_expiry', models.DateTimeField(blank=True, null=True)),
|
||||
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
|
||||
],
|
||||
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||
),
|
||||
]
|
||||
@@ -366,7 +366,7 @@ class UserPreference(models.Model, PermissionModelMixin):
|
||||
)
|
||||
|
||||
user = AutoOneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
||||
image = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True,blank=True, related_name='user_image')
|
||||
image = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='user_image')
|
||||
theme = models.CharField(choices=THEMES, max_length=128, default=TANDOOR)
|
||||
nav_color = models.CharField(choices=COLORS, max_length=128, default=PRIMARY)
|
||||
default_unit = models.CharField(max_length=32, default='g')
|
||||
@@ -1010,6 +1010,27 @@ def default_valid_until():
|
||||
return date.today() + timedelta(days=14)
|
||||
|
||||
|
||||
class CookingMachine(models.Model, PermissionModelMixin):
|
||||
# Tandoor is not affiliated in any way or form with the holders of Trademark or other right associated with the mentioned names. All mentioned protected names are purely used to identify to the user a certain device or integration.
|
||||
HOMECONNECT_COOKIT = 'HOMECONNECT_COOKIT'
|
||||
MACHINE_TYPES = (
|
||||
(HOMECONNECT_COOKIT, _('HomeConnect CookIt')),
|
||||
)
|
||||
|
||||
type = models.CharField(choices=MACHINE_TYPES, max_length=128)
|
||||
name = models.CharField(max_length=128)
|
||||
serial = models.CharField(max_length=512, null=True, blank=True)
|
||||
description = models.TextField(default='', blank=True)
|
||||
|
||||
access_token = models.CharField(max_length=4096, null=True, blank=True)
|
||||
access_token_expiry = models.DateTimeField(null=True, blank=True)
|
||||
refresh_token = models.CharField(max_length=4096, null=True, blank=True)
|
||||
refresh_token_expiry = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
|
||||
class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, PermissionModelMixin):
|
||||
uuid = models.UUIDField(default=uuid.uuid4)
|
||||
email = models.EmailField(blank=True)
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
{% block content_fluid %}
|
||||
|
||||
<a href="{{ login_url }}" target="_blank" rel="noreferrer nofollow">Login CookIt</a>
|
||||
<br/>
|
||||
<a href="?sync=748" >Sync</a>
|
||||
|
||||
{{ data }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -120,6 +120,8 @@ urlpatterns = [
|
||||
path('api/download-file/<int:file_id>/', api.download_file, name='api_download_file'),
|
||||
|
||||
|
||||
path('cooking-machine/auth/homeconnect/', views.test2, name='cookingmachine_auth_homeconnect'),
|
||||
|
||||
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
|
||||
path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), # TODO is this deprecated?
|
||||
|
||||
@@ -20,12 +20,13 @@ from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from oauth2_provider.models import AccessToken
|
||||
|
||||
from cookbook.cooking_machines.homeconnect_cookit import HomeConnectCookit
|
||||
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, ShoppingPreferenceForm,
|
||||
SpaceCreateForm, SpaceJoinForm, User,
|
||||
UserCreateForm, UserNameForm, UserPreference, UserPreferenceForm)
|
||||
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,
|
||||
Space, ViewLog, UserSpace)
|
||||
Space, ViewLog, UserSpace, CookingMachine)
|
||||
from cookbook.tables import (CookLogTable, ViewLogTable)
|
||||
from recipes.version import BUILD_REF, VERSION_NUMBER
|
||||
|
||||
@@ -434,17 +435,22 @@ def test(request):
|
||||
if not settings.DEBUG:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
parser = IngredientParser(request, False)
|
||||
machine = CookingMachine.objects.get_or_create(type=CookingMachine.HOMECONNECT_COOKIT, name='Test', space=request.space)[0]
|
||||
test = HomeConnectCookit(machine)
|
||||
|
||||
data = {
|
||||
'original': '1 Porreestange(n) , ca. 200 g'
|
||||
}
|
||||
data['parsed'] = parser.parse(data['original'])
|
||||
|
||||
return render(request, 'test.html', {'data': data})
|
||||
return render(request, 'test.html', {'login_url': test.get_auth_link()})
|
||||
|
||||
|
||||
def test2(request):
|
||||
if not settings.DEBUG:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
machine = CookingMachine.objects.get_or_create(type=CookingMachine.HOMECONNECT_COOKIT, name='Test', space=request.space)[0]
|
||||
test = HomeConnectCookit(machine)
|
||||
if 'code' in request.GET:
|
||||
test.get_access_token(request.GET['code'])
|
||||
|
||||
if 'sync' in request.GET:
|
||||
result = test.push_recipe(Recipe.objects.get(pk=request.GET['sync'], space=request.space))
|
||||
|
||||
return render(request, 'test.html', {'data': request})
|
||||
|
||||
12
node_modules/.yarn-integrity
generated
vendored
Normal file
12
node_modules/.yarn-integrity
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"systemParams": "win32-x64-93",
|
||||
"modulesFolders": [
|
||||
"node_modules"
|
||||
],
|
||||
"flags": [],
|
||||
"linkedModules": [],
|
||||
"topLevelPatterns": [],
|
||||
"lockfileEntries": {},
|
||||
"files": [],
|
||||
"artifacts": {}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
Django==4.0.7
|
||||
cryptography==37.0.2
|
||||
cryptography==38.0.1
|
||||
django-annoying==0.10.6
|
||||
django-autocomplete-light==3.9.4
|
||||
django-cleanup==6.0.0
|
||||
django-crispy-forms==1.14.0
|
||||
django-tables2==2.4.1
|
||||
djangorestframework==3.13.1
|
||||
djangorestframework==3.14.0
|
||||
drf-writable-nested==0.7.0
|
||||
django-oauth-toolkit==2.1.0
|
||||
django-debug-toolbar==3.6.0
|
||||
@@ -27,20 +27,20 @@ uritemplate==4.1.1
|
||||
beautifulsoup4==4.11.1
|
||||
microdata==0.8.0
|
||||
Jinja2==3.1.2
|
||||
django-webpack-loader==1.5.0
|
||||
django-webpack-loader==1.6.0
|
||||
git+https://github.com/ierror/django-js-reverse@7cab78c4531780ab4b32033d5104ccd5be1a246a
|
||||
django-allauth==0.51.0
|
||||
recipe-scrapers==14.14.0
|
||||
recipe-scrapers==14.14.1
|
||||
django-scopes==1.2.0.post1
|
||||
pytest==7.1.2
|
||||
pytest==7.1.3
|
||||
pytest-django==4.5.2
|
||||
django-treebeard==4.5.1
|
||||
django-cors-headers==3.13.0
|
||||
django-storages==1.12.3
|
||||
boto3==1.24.21
|
||||
django-storages==1.13.1
|
||||
boto3==1.24.84
|
||||
django-prometheus==2.2.0
|
||||
django-hCaptcha==0.2.0
|
||||
python-ldap==3.4.2
|
||||
python-ldap==3.4.3
|
||||
django-auth-ldap==4.1.0
|
||||
pytest-factoryboy==2.5.0
|
||||
pyppeteer==1.0.2
|
||||
|
||||
@@ -8,61 +8,61 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/eslint-parser": "^7.16.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@kevinfaguiar/vue-twemoji-picker": "^5.7.4",
|
||||
"@popperjs/core": "^2.11.2",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@riophae/vue-treeselect": "^0.4.0",
|
||||
"@vue/cli": "^5.0.4",
|
||||
"@vue/cli": "^5.0.8",
|
||||
"axios": "^0.27.2",
|
||||
"babel": "^6.23.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^8.2.5",
|
||||
"bootstrap-vue": "^2.21.2",
|
||||
"core-js": "^3.25.0",
|
||||
"core-js": "^3.25.3",
|
||||
"html2pdf.js": "^0.10.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mavon-editor": "^2.10.4",
|
||||
"moment": "^2.29.4",
|
||||
"prismjs": "^1.27.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-class-component": "^7.2.3",
|
||||
"vue-click-outside": "^1.1.0",
|
||||
"vue-clickaway": "^2.2.2",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-cookies": "^1.8.1",
|
||||
"vue-i18n": "^8.26.8",
|
||||
"vue-i18n": "^8.27.2",
|
||||
"vue-infinite-loading": "^2.4.5",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-property-decorator": "^9.1.2",
|
||||
"vue-sanitize": "^0.2.2",
|
||||
"vue-simple-calendar": "^5.0.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue2-touch-events": "^3.2.2",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.0",
|
||||
"workbox-webpack-plugin": "^6.3.0"
|
||||
"vue-template-compiler": "2.6.14",
|
||||
"workbox-webpack-plugin": "^6.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kazupon/vue-i18n-loader": "^0.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||
"@typescript-eslint/parser": "^4.32.0",
|
||||
"@vue/cli-plugin-babel": "^5.0.4",
|
||||
"@vue/cli-plugin-eslint": "~5.0.4",
|
||||
"@vue/cli-plugin-pwa": "^5.0.4",
|
||||
"@vue/cli-plugin-typescript": "^5.0.4",
|
||||
"@vue/cli-service": "^5.0.4",
|
||||
"@vue/compiler-sfc": "^3.2.29",
|
||||
"@vue/cli-plugin-babel": "^5.0.8",
|
||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
||||
"@vue/cli-plugin-pwa": "^5.0.8",
|
||||
"@vue/cli-plugin-typescript": "^5.0.8",
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"@vue/compiler-sfc": "^3.2.40",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"typescript": "~4.8.2",
|
||||
"typescript": "~4.8.4",
|
||||
"vue-cli-plugin-i18n": "^2.3.1",
|
||||
"webpack-bundle-tracker": "1.5.0",
|
||||
"workbox-expiration": "^6.3.0",
|
||||
"workbox-navigation-preload": "^6.0.2",
|
||||
"workbox-precaching": "^6.5.3",
|
||||
"workbox-routing": "^6.5.0",
|
||||
"webpack-bundle-tracker": "1.6.0",
|
||||
"workbox-expiration": "^6.5.4",
|
||||
"workbox-navigation-preload": "^6.5.4",
|
||||
"workbox-precaching": "^6.5.4",
|
||||
"workbox-routing": "^6.5.4",
|
||||
"workbox-strategies": "^6.2.4"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
||||
@@ -576,6 +576,21 @@
|
||||
<i class="fas fa-code"></i>
|
||||
{{ $t("Copy_template_reference") }}
|
||||
</button>
|
||||
<button type="button" class="dropdown-item"
|
||||
@click="duplicateIngredient(step, ingredient, index + 1)">
|
||||
<i class="fas fa-copy"></i>
|
||||
{{ $t("Copy") }}
|
||||
</button>
|
||||
<button type="button" class="dropdown-item" v-if="index > 0"
|
||||
@click="moveIngredient(step, ingredient, index-1)">
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
{{ $t("Up") }}
|
||||
</button>
|
||||
<button type="button" class="dropdown-item" v-if="index !== step.ingredients.length - 1"
|
||||
@click="moveIngredient(step, ingredient, index+1)">
|
||||
<i class="fas fa-arrow-down"></i>
|
||||
{{ $t("Down") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -648,7 +663,8 @@
|
||||
v-if="recipe !== undefined">
|
||||
<div class="col-3 col-md-6 mb-1 mb-md-0 pr-2 pl-2">
|
||||
<a :href="resolveDjangoUrl('delete_recipe', recipe.id)"
|
||||
class="d-block d-md-none btn btn-block btn-danger shadow-none btn-sm"><i class="fa fa-trash fa-lg"></i></a>
|
||||
class="d-block d-md-none btn btn-block btn-danger shadow-none btn-sm"><i
|
||||
class="fa fa-trash fa-lg"></i></a>
|
||||
<a :href="resolveDjangoUrl('delete_recipe', recipe.id)"
|
||||
class="d-none d-md-block btn btn-block btn-danger shadow-none btn-sm">{{ $t("Delete") }}</a>
|
||||
</div>
|
||||
@@ -1039,6 +1055,12 @@ export default {
|
||||
this.recipe.steps.splice(new_index < 0 ? 0 : new_index, 0, step)
|
||||
this.sortSteps()
|
||||
},
|
||||
moveIngredient: function (step, ingredient, new_index) {
|
||||
step.ingredients.splice(step.ingredients.indexOf(ingredient), 1)
|
||||
step.ingredients.splice(new_index < 0 ? 0 : new_index, 0, ingredient)
|
||||
this.sortIngredients(step)
|
||||
},
|
||||
|
||||
addFoodType: function (tag, index) {
|
||||
let [tmp, step, id] = index.split("_")
|
||||
|
||||
@@ -1212,6 +1234,10 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
duplicateIngredient: function (step, ingredient, new_index) {
|
||||
delete ingredient.id
|
||||
step.ingredients.splice(new_index < 0 ? 0 : new_index, 0, ingredient)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<template v-if="step.name">{{ step.name }}</template>
|
||||
<template v-else>{{ $t("Step") }} {{ index + 1 }}</template>
|
||||
<small style="margin-left: 4px" class="text-muted" v-if="step.time !== 0"><i
|
||||
class="fas fa-user-clock"></i> {{ step.time }} {{ $t("min") }} </small>
|
||||
class="fas fa-user-clock"></i> {{ step_time }}</small>
|
||||
<small v-if="start_time !== ''" class="d-print-none">
|
||||
<b-link :id="`id_reactive_popover_${step.id}`" @click="openPopover" href="#">
|
||||
{{ moment(start_time).add(step.time_offset, "minutes").format("HH:mm") }}
|
||||
@@ -131,7 +131,7 @@ import CompileComponent from "@/components/CompileComponent"
|
||||
import IngredientsCard from "@/components/IngredientsCard"
|
||||
import Vue from "vue"
|
||||
import moment from "moment"
|
||||
import {ResolveUrlMixin} from "@/utils/utils"
|
||||
import {ResolveUrlMixin, calculateHourMinuteSplit} from "@/utils/utils"
|
||||
|
||||
Vue.prototype.moment = moment
|
||||
|
||||
@@ -150,6 +150,10 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
step_time: function() {
|
||||
return calculateHourMinuteSplit(this.step.time)},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
details_visible: true,
|
||||
|
||||
462
vue/src/locales/id.json
Normal file
462
vue/src/locales/id.json
Normal file
@@ -0,0 +1,462 @@
|
||||
{
|
||||
"warning_feature_beta": "Fitur ini saat ini dalam status BETA (pengujian). Harap perkirakan bug dan kemungkinan kerusakan perubahan di masa mendatang (mungkin kehilangan data terkait fitur) saat menggunakan fitur ini.",
|
||||
"err_fetching_resource": "Terjadi kesalahan saat mengambil sumber daya!",
|
||||
"err_creating_resource": "Terjadi kesalahan saat membuat sumber daya!",
|
||||
"err_updating_resource": "Terjadi kesalahan saat mengupdate sumber daya!",
|
||||
"err_deleting_resource": "Terjadi kesalahan saat menghapus sumber daya!",
|
||||
"err_deleting_protected_resource": "Objek yang Anda coba hapus masih digunakan dan tidak dapat dihapus.",
|
||||
"err_moving_resource": "Terjadi kesalahan saat memindahkan sumber daya!",
|
||||
"err_merging_resource": "Terjadi kesalahan saat menggabungkan sumber daya!",
|
||||
"success_fetching_resource": "Berhasil mengambil sumber daya!",
|
||||
"success_creating_resource": "Berhasil membuat sumber daya!",
|
||||
"success_updating_resource": "Berhasil memperbarui sumber daya!",
|
||||
"success_deleting_resource": "Berhasil menghapus sumber daya!",
|
||||
"success_moving_resource": "Berhasil memindahkan sumber daya!",
|
||||
"success_merging_resource": "Berhasil menggabungkan sumber daya!",
|
||||
"file_upload_disabled": "Unggahan file tidak diaktifkan untuk ruang Anda.",
|
||||
"warning_space_delete": "Anda dapat menghapus ruang Anda termasuk semua resep, daftar belanja, rencana makan, dan apa pun yang telah Anda buat. Ini tidak dapat dibatalkan! Apakah Anda yakin ingin melakukan ini?",
|
||||
"food_inherit_info": "Bidang pada makanan yang harus diwarisi secara default.",
|
||||
"facet_count_info": "Tampilkan jumlah resep pada filter pencarian.",
|
||||
"step_time_minutes": "Langkah waktu dalam menit",
|
||||
"confirm_delete": "Anda yakin ingin menghapus {object} ini?",
|
||||
"import_running": "Impor berjalan, harap tunggu!",
|
||||
"all_fields_optional": "Semua bidang adalah opsional dan dapat dibiarkan kosong.",
|
||||
"convert_internal": "Ubah ke resep internal",
|
||||
"show_only_internal": "Hanya tampilkan resep internal",
|
||||
"show_split_screen": "Tampilan Terpisah",
|
||||
"Log_Recipe_Cooking": "Log Resep Memasak",
|
||||
"External_Recipe_Image": "Gambar Resep Eksternal",
|
||||
"Add_to_Shopping": "Tambahkan ke Belanja",
|
||||
"Add_to_Plan": "Tambahkan ke Rencana",
|
||||
"Step_start_time": "Langkah waktu mulai",
|
||||
"Sort_by_new": "Urutkan berdasarkan baru",
|
||||
"Table_of_Contents": "Daftar isi",
|
||||
"Recipes_per_page": "Resep per Halaman",
|
||||
"Show_as_header": "Tampilkan sebagai tajuk",
|
||||
"Hide_as_header": "Sembunyikan sebagai tajuk",
|
||||
"Add_nutrition_recipe": "Tambahkan nutrisi ke resep",
|
||||
"Remove_nutrition_recipe": "Hapus nutrisi dari resep",
|
||||
"Copy_template_reference": "Salin referensi template",
|
||||
"Save_and_View": "Simpan & Lihat",
|
||||
"Manage_Books": "Kelola Buku",
|
||||
"Meal_Plan": "rencana makan",
|
||||
"Select_Book": "Pilih Buku",
|
||||
"Select_File": "Pilih Buku",
|
||||
"Recipe_Image": "Gambar Resep",
|
||||
"Import_finished": "Impor selesai",
|
||||
"View_Recipes": "Lihat Resep",
|
||||
"Log_Cooking": "Log Memasak",
|
||||
"New_Recipe": "Resep Baru",
|
||||
"Url_Import": "Impor Url",
|
||||
"Reset_Search": "Setel Ulang Pencarian",
|
||||
"Recently_Viewed": "baru saja dilihat",
|
||||
"Load_More": "Muat lebih banyak",
|
||||
"New_Keyword": "Kata Kunci Baru",
|
||||
"Delete_Keyword": "Hapus Kata Kunci",
|
||||
"Edit_Keyword": "Rubah Kata Kunci",
|
||||
"Edit_Recipe": "Rubah Resep",
|
||||
"Move_Keyword": "Pindahkan Kata Kunci",
|
||||
"Merge_Keyword": "Gabungkan Kata Kunci",
|
||||
"Hide_Keywords": "Sembunyikan Kata Kunci",
|
||||
"Hide_Recipes": "Sembunyikan Resep",
|
||||
"Move_Up": "Pindahkan keatas",
|
||||
"Move_Down": "Pindahkan kebawah",
|
||||
"Step_Name": "Nama Langkah",
|
||||
"Step_Type": "Tipe Langkah",
|
||||
"Make_Header": "Buat Header",
|
||||
"Make_Ingredient": "Buat bahan",
|
||||
"Enable_Amount": "Aktifkan Jumlah",
|
||||
"Disable_Amount": "Nonaktifkan Jumlah",
|
||||
"Ingredient Editor": "Editor Bahan",
|
||||
"Private_Recipe": "Resep Pribadi",
|
||||
"Private_Recipe_Help": "Resep hanya diperlihatkan kepada Anda dan orang-orang yang dibagikan resep tersebut.",
|
||||
"reusable_help_text": "Haruskah tautan undangan dapat digunakan untuk lebih dari satu pengguna.",
|
||||
"Add_Step": "Tambahkan Langkah",
|
||||
"Keywords": "Kata Kunci",
|
||||
"Books": "Buku",
|
||||
"Proteins": "Protein",
|
||||
"Fats": "Lemak",
|
||||
"Carbohydrates": "Karbohidrat",
|
||||
"Calories": "Kalori",
|
||||
"Energy": "Energi",
|
||||
"Nutrition": "Nutrisi",
|
||||
"Date": "Tanggal",
|
||||
"Share": "Bagikan",
|
||||
"Automation": "Automatis",
|
||||
"Parameter": "Parameter",
|
||||
"Export": "Ekspor",
|
||||
"Copy": "Salin",
|
||||
"Rating": "Peringkat",
|
||||
"Close": "Tutup",
|
||||
"Cancel": "Batal",
|
||||
"Link": "Link",
|
||||
"Add": "Tambahkan",
|
||||
"New": "Baru",
|
||||
"Note": "Catatan",
|
||||
"Success": "Sukses",
|
||||
"Failure": "Kegagalan",
|
||||
"Protected": "Terlindung",
|
||||
"Ingredients": "bahan-bahan",
|
||||
"Supermarket": "Supermarket",
|
||||
"Categories": "Kategori",
|
||||
"Category": "Kategori",
|
||||
"Selected": "Terpilih",
|
||||
"min": "min",
|
||||
"Servings": "Porsi",
|
||||
"Waiting": "Menunggu",
|
||||
"Preparation": "",
|
||||
"External": "",
|
||||
"Size": "",
|
||||
"Files": "",
|
||||
"File": "",
|
||||
"Edit": "",
|
||||
"Image": "",
|
||||
"Delete": "",
|
||||
"Open": "",
|
||||
"Ok": "",
|
||||
"Save": "",
|
||||
"Step": "",
|
||||
"Search": "",
|
||||
"Import": "",
|
||||
"Print": "",
|
||||
"Settings": "",
|
||||
"or": "",
|
||||
"and": "",
|
||||
"Information": "",
|
||||
"Download": "",
|
||||
"Create": "",
|
||||
"Search Settings": "",
|
||||
"View": "",
|
||||
"Recipes": "",
|
||||
"Move": "",
|
||||
"Merge": "",
|
||||
"Parent": "",
|
||||
"Copy Link": "",
|
||||
"Copy Token": "",
|
||||
"delete_confirmation": "",
|
||||
"move_confirmation": "",
|
||||
"merge_confirmation": "",
|
||||
"create_rule": "",
|
||||
"move_selection": "",
|
||||
"merge_selection": "",
|
||||
"Root": "",
|
||||
"Ignore_Shopping": "",
|
||||
"Shopping_Category": "",
|
||||
"Shopping_Categories": "",
|
||||
"Edit_Food": "",
|
||||
"Move_Food": "",
|
||||
"New_Food": "",
|
||||
"Hide_Food": "",
|
||||
"Food_Alias": "",
|
||||
"Unit_Alias": "",
|
||||
"Keyword_Alias": "",
|
||||
"Delete_Food": "",
|
||||
"No_ID": "",
|
||||
"Meal_Plan_Days": "",
|
||||
"merge_title": "",
|
||||
"move_title": "",
|
||||
"Food": "",
|
||||
"Recipe_Book": "",
|
||||
"del_confirmation_tree": "",
|
||||
"delete_title": "",
|
||||
"create_title": "",
|
||||
"edit_title": "",
|
||||
"Name": "",
|
||||
"Type": "",
|
||||
"Description": "",
|
||||
"Recipe": "",
|
||||
"tree_root": "",
|
||||
"Icon": "",
|
||||
"Unit": "",
|
||||
"Decimals": "",
|
||||
"Default_Unit": "",
|
||||
"No_Results": "",
|
||||
"New_Unit": "",
|
||||
"Create_New_Shopping Category": "",
|
||||
"Create_New_Food": "",
|
||||
"Create_New_Keyword": "",
|
||||
"Create_New_Unit": "",
|
||||
"Create_New_Meal_Type": "",
|
||||
"Create_New_Shopping_Category": "",
|
||||
"and_up": "",
|
||||
"and_down": "",
|
||||
"Instructions": "",
|
||||
"Unrated": "",
|
||||
"Automate": "",
|
||||
"Empty": "",
|
||||
"Key_Ctrl": "",
|
||||
"Key_Shift": "",
|
||||
"Time": "",
|
||||
"Text": "",
|
||||
"Shopping_list": "",
|
||||
"Added_by": "",
|
||||
"Added_on": "",
|
||||
"AddToShopping": "",
|
||||
"IngredientInShopping": "",
|
||||
"NotInShopping": "",
|
||||
"OnHand": "",
|
||||
"FoodOnHand": "",
|
||||
"FoodNotOnHand": "",
|
||||
"Undefined": "",
|
||||
"Create_Meal_Plan_Entry": "",
|
||||
"Edit_Meal_Plan_Entry": "",
|
||||
"Title": "",
|
||||
"Week": "",
|
||||
"Month": "",
|
||||
"Year": "",
|
||||
"Planner": "",
|
||||
"Planner_Settings": "",
|
||||
"Period": "",
|
||||
"Plan_Period_To_Show": "",
|
||||
"Periods": "",
|
||||
"Plan_Show_How_Many_Periods": "",
|
||||
"Starting_Day": "",
|
||||
"Meal_Types": "",
|
||||
"Meal_Type": "",
|
||||
"New_Entry": "",
|
||||
"Clone": "",
|
||||
"Drag_Here_To_Delete": "",
|
||||
"Meal_Type_Required": "",
|
||||
"Title_or_Recipe_Required": "",
|
||||
"Color": "",
|
||||
"New_Meal_Type": "",
|
||||
"Use_Fractions": "",
|
||||
"Use_Fractions_Help": "",
|
||||
"AddFoodToShopping": "",
|
||||
"RemoveFoodFromShopping": "",
|
||||
"DeleteShoppingConfirm": "",
|
||||
"IgnoredFood": "",
|
||||
"Add_Servings_to_Shopping": "",
|
||||
"Week_Numbers": "",
|
||||
"Show_Week_Numbers": "",
|
||||
"Export_As_ICal": "",
|
||||
"Export_To_ICal": "",
|
||||
"Cannot_Add_Notes_To_Shopping": "",
|
||||
"Added_To_Shopping_List": "",
|
||||
"Shopping_List_Empty": "",
|
||||
"Next_Period": "",
|
||||
"Previous_Period": "",
|
||||
"Current_Period": "",
|
||||
"Next_Day": "",
|
||||
"Previous_Day": "",
|
||||
"Inherit": "",
|
||||
"InheritFields": "",
|
||||
"FoodInherit": "",
|
||||
"ShowUncategorizedFood": "",
|
||||
"GroupBy": "",
|
||||
"Language": "",
|
||||
"Theme": "",
|
||||
"SupermarketCategoriesOnly": "",
|
||||
"MoveCategory": "",
|
||||
"CountMore": "",
|
||||
"IgnoreThis": "",
|
||||
"DelayFor": "",
|
||||
"Warning": "",
|
||||
"NoCategory": "",
|
||||
"InheritWarning": "",
|
||||
"ShowDelayed": "",
|
||||
"Completed": "",
|
||||
"OfflineAlert": "",
|
||||
"shopping_share": "",
|
||||
"shopping_auto_sync": "",
|
||||
"one_url_per_line": "",
|
||||
"mealplan_autoadd_shopping": "",
|
||||
"mealplan_autoexclude_onhand": "",
|
||||
"mealplan_autoinclude_related": "",
|
||||
"default_delay": "",
|
||||
"plan_share_desc": "",
|
||||
"shopping_share_desc": "",
|
||||
"shopping_auto_sync_desc": "",
|
||||
"mealplan_autoadd_shopping_desc": "",
|
||||
"mealplan_autoexclude_onhand_desc": "",
|
||||
"mealplan_autoinclude_related_desc": "",
|
||||
"default_delay_desc": "",
|
||||
"filter_to_supermarket": "",
|
||||
"Coming_Soon": "",
|
||||
"Auto_Planner": "",
|
||||
"New_Cookbook": "",
|
||||
"Hide_Keyword": "",
|
||||
"Hour": "",
|
||||
"Hours": "",
|
||||
"Day": "",
|
||||
"Days": "",
|
||||
"Second": "",
|
||||
"Seconds": "",
|
||||
"Clear": "",
|
||||
"Users": "",
|
||||
"Invites": "",
|
||||
"err_move_self": "",
|
||||
"nothing": "",
|
||||
"err_merge_self": "",
|
||||
"show_sql": "",
|
||||
"filter_to_supermarket_desc": "",
|
||||
"CategoryName": "",
|
||||
"SupermarketName": "",
|
||||
"CategoryInstruction": "",
|
||||
"shopping_recent_days_desc": "",
|
||||
"shopping_recent_days": "",
|
||||
"download_pdf": "",
|
||||
"download_csv": "",
|
||||
"csv_delim_help": "",
|
||||
"csv_delim_label": "",
|
||||
"SuccessClipboard": "",
|
||||
"copy_to_clipboard": "",
|
||||
"csv_prefix_help": "",
|
||||
"csv_prefix_label": "",
|
||||
"copy_markdown_table": "",
|
||||
"in_shopping": "",
|
||||
"DelayUntil": "",
|
||||
"Pin": "",
|
||||
"mark_complete": "",
|
||||
"QuickEntry": "",
|
||||
"shopping_add_onhand_desc": "",
|
||||
"shopping_add_onhand": "",
|
||||
"related_recipes": "",
|
||||
"today_recipes": "",
|
||||
"sql_debug": "",
|
||||
"remember_search": "",
|
||||
"remember_hours": "",
|
||||
"tree_select": "",
|
||||
"OnHand_help": "",
|
||||
"ignore_shopping_help": "",
|
||||
"shopping_category_help": "",
|
||||
"food_recipe_help": "",
|
||||
"Foods": "",
|
||||
"Account": "",
|
||||
"Cosmetic": "",
|
||||
"API": "",
|
||||
"enable_expert": "",
|
||||
"expert_mode": "",
|
||||
"simple_mode": "",
|
||||
"advanced": "",
|
||||
"fields": "",
|
||||
"show_keywords": "",
|
||||
"show_foods": "",
|
||||
"show_books": "",
|
||||
"show_rating": "",
|
||||
"show_units": "",
|
||||
"show_filters": "",
|
||||
"not": "",
|
||||
"save_filter": "",
|
||||
"filter_name": "",
|
||||
"left_handed": "",
|
||||
"left_handed_help": "",
|
||||
"Custom Filter": "",
|
||||
"shared_with": "",
|
||||
"sort_by": "",
|
||||
"asc": "",
|
||||
"desc": "",
|
||||
"date_viewed": "",
|
||||
"last_cooked": "",
|
||||
"times_cooked": "",
|
||||
"date_created": "",
|
||||
"show_sortby": "",
|
||||
"search_rank": "",
|
||||
"make_now": "",
|
||||
"recipe_filter": "",
|
||||
"book_filter_help": "",
|
||||
"review_shopping": "",
|
||||
"view_recipe": "",
|
||||
"copy_to_new": "",
|
||||
"recipe_name": "",
|
||||
"paste_ingredients_placeholder": "",
|
||||
"paste_ingredients": "",
|
||||
"ingredient_list": "",
|
||||
"explain": "",
|
||||
"filter": "",
|
||||
"Website": "",
|
||||
"App": "",
|
||||
"Message": "",
|
||||
"Bookmarklet": "",
|
||||
"Sticky_Nav": "",
|
||||
"Sticky_Nav_Help": "",
|
||||
"Nav_Color": "",
|
||||
"Nav_Color_Help": "",
|
||||
"Use_Kj": "",
|
||||
"Comments_setting": "",
|
||||
"click_image_import": "",
|
||||
"no_more_images_found": "",
|
||||
"import_duplicates": "",
|
||||
"paste_json": "",
|
||||
"Click_To_Edit": "",
|
||||
"search_no_recipes": "",
|
||||
"search_import_help_text": "",
|
||||
"search_create_help_text": "",
|
||||
"warning_duplicate_filter": "",
|
||||
"reset_children": "",
|
||||
"reset_children_help": "",
|
||||
"reset_food_inheritance": "",
|
||||
"reset_food_inheritance_info": "",
|
||||
"substitute_help": "",
|
||||
"substitute_siblings_help": "",
|
||||
"substitute_children_help": "",
|
||||
"substitute_siblings": "",
|
||||
"substitute_children": "",
|
||||
"SubstituteOnHand": "",
|
||||
"ChildInheritFields": "",
|
||||
"ChildInheritFields_help": "",
|
||||
"InheritFields_help": "",
|
||||
"show_ingredient_overview": "",
|
||||
"Ingredient Overview": "",
|
||||
"last_viewed": "",
|
||||
"created_on": "",
|
||||
"updatedon": "",
|
||||
"Imported_From": "",
|
||||
"advanced_search_settings": "",
|
||||
"nothing_planned_today": "",
|
||||
"no_pinned_recipes": "",
|
||||
"Planned": "",
|
||||
"Pinned": "",
|
||||
"Imported": "",
|
||||
"Quick actions": "",
|
||||
"Ratings": "",
|
||||
"Internal": "",
|
||||
"Units": "",
|
||||
"Manage_Emails": "",
|
||||
"Change_Password": "",
|
||||
"Social_Authentication": "",
|
||||
"Random Recipes": "",
|
||||
"parameter_count": "",
|
||||
"select_keyword": "",
|
||||
"add_keyword": "",
|
||||
"select_file": "",
|
||||
"select_recipe": "",
|
||||
"select_unit": "",
|
||||
"select_food": "",
|
||||
"remove_selection": "",
|
||||
"empty_list": "",
|
||||
"Select": "",
|
||||
"Supermarkets": "",
|
||||
"User": "",
|
||||
"Username": "",
|
||||
"First_name": "",
|
||||
"Last_name": "",
|
||||
"Keyword": "",
|
||||
"Advanced": "",
|
||||
"Page": "",
|
||||
"Single": "",
|
||||
"Multiple": "",
|
||||
"Reset": "",
|
||||
"Disabled": "",
|
||||
"Disable": "",
|
||||
"Options": "",
|
||||
"Create Food": "",
|
||||
"create_food_desc": "",
|
||||
"additional_options": "",
|
||||
"Importer_Help": "",
|
||||
"Documentation": "",
|
||||
"Select_App_To_Import": "",
|
||||
"Import_Supported": "",
|
||||
"Export_Supported": "",
|
||||
"Import_Not_Yet_Supported": "",
|
||||
"Export_Not_Yet_Supported": "",
|
||||
"Import_Result_Info": "",
|
||||
"Recipes_In_Import": "",
|
||||
"Toggle": "",
|
||||
"Import_Error": "",
|
||||
"Warning_Delete_Supermarket_Category": "",
|
||||
"New_Supermarket": "",
|
||||
"New_Supermarket_Category": "",
|
||||
"Are_You_Sure": "",
|
||||
"Valid Until": ""
|
||||
}
|
||||
1151
vue/yarn.lock
1151
vue/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user