Compare commits

...

9 Commits

Author SHA1 Message Date
Herculino Trotta
585652064a locale(Portuguese (Brazil)): update translation
Currently translated at 100.0% (617 of 617 strings)

Translation: WYGIWYH/App
Translate-URL: https://translations.herculino.com/projects/wygiwyh/app/pt_BR/
2025-03-31 05:38:18 +00:00
eitchtee
ea6f61d5e4 chore(locale): update translation files
[skip ci] Automatically generated by Django makemessages workflow
2025-03-31 05:30:21 +00:00
Herculino Trotta
e986f7d802 Merge pull request #224
feat: add demo mode and allow for automatic admin creation from env variables
2025-03-31 02:29:44 -03:00
Herculino Trotta
26b218ae51 feat(app): disable API when demo mode is enabled 2025-03-31 02:28:48 -03:00
Herculino Trotta
19f0bc1034 feat(app): show current user e-mail on user menu 2025-03-31 02:28:33 -03:00
Herculino Trotta
47d34f3c27 feat(app): add a demo mode 2025-03-31 02:14:00 -03:00
Herculino Trotta
046e02d506 feat(app): add environment variables to automatically create superuser on startup 2025-03-31 02:11:13 -03:00
valentin-p
92c7a29b6a locale(German): update translation
Currently translated at 99.8% (610 of 611 strings)

Translation: WYGIWYH/App
Translate-URL: https://translations.herculino.com/projects/wygiwyh/app/de/
2025-03-30 15:07:17 +00:00
valentin-p
d95e5f71cc locale((French)): added translation using Weblate 2025-03-30 13:40:51 +00:00
25 changed files with 3631 additions and 196 deletions

View File

@@ -10,6 +10,11 @@ SECRET_KEY=<GENERATE A SAFE SECRET KEY AND PLACE IT HERE>
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
OUTBOUND_PORT=9005
# Uncomment these variables to automatically create an admin account using these credentials on startup.
# After your first successfull login you can remove these variables from your file for safety reasons.
#ADMIN_EMAIL=<ENTER YOUR EMAIL>
#ADMIN_PASSWORD=<YOUR SAFE PASSWORD>
SQL_DATABASE=wygiwyh
SQL_USER=wygiwyh
SQL_PASSWORD=<INSERT A SAFE PASSWORD HERE>

View File

@@ -76,7 +76,7 @@ $ nano .env # or any other editor you want to use
# Run the app
$ docker compose up -d
# Create the first admin account
# Create the first admin account. This isn't required if you set the enviroment variables: ADMIN_EMAIL and ADMIN_PASSWORD.
$ docker compose exec -it web python manage.py createsuperuser
```
@@ -117,7 +117,7 @@ To create the first user, open the container's console using Unraid's UI, by cli
|-------------------------------|-------------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| DJANGO_ALLOWED_HOSTS | string | localhost 127.0.0.1 | A list of space separated domains and IPs representing the host/domain names that WYGIWYH site can serve. [Click here](https://docs.djangoproject.com/en/5.1/ref/settings/#allowed-hosts) for more details |
| HTTPS_ENABLED | true\|false | false | Whether to use secure cookies. If this is set to true, the cookie will be marked as “secure”, which means browsers may ensure that the cookie is only sent under an HTTPS connection |
| URL | string | http://localhost http://127.0.0.1 | A list of space separated domains and IPs (with the protocol) representing the trusted origins for unsafe requests (e.g. POST). [Click here](https://docs.djangoproject.com/en/5.1/ref/settings/#csrf-trusted-origins ) for more details |
| URL | string | http://localhost http://127.0.0.1 | A list of space separated domains and IPs (with the protocol) representing the trusted origins for unsafe requests (e.g. POST). [Click here](https://docs.djangoproject.com/en/5.1/ref/settings/#csrf-trusted-origins ) for more details |
| SECRET_KEY | string | "" | This is used to provide cryptographic signing, and should be set to a unique, unpredictable value. |
| DEBUG | true\|false | false | Turns DEBUG mode on or off, this is useful to gather more data about possible errors you're having. Don't use in production. |
| SQL_DATABASE | string | None *required | The name of your postgres database |
@@ -129,6 +129,9 @@ To create the first user, open the container's console using Unraid's UI, by cli
| ENABLE_SOFT_DELETE | true\|false | false | Whether to enable transactions soft delete, if enabled, deleted transactions will remain in the database. Useful for imports and avoiding duplicate entries. |
| KEEP_DELETED_TRANSACTIONS_FOR | int | 365 | Time in days to keep soft deleted transactions for. If 0, will keep all transactions indefinitely. Only works if ENABLE_SOFT_DELETE is true. |
| TASK_WORKERS | int | 1 | How many workers to have for async tasks. One should be enough for most use cases |
| DEMO | true\|false | false | If demo mode is enabled. |
| ADMIN_EMAIL | string | None | Automatically creates an admin account with this email. Must have `ADMIN_PASSWORD` also set. |
| ADMIN_PASSWORD | string | None | Automatically creates an admin account with this password. Must have `ADMIN_EMAIL` also set. |
# How it works

View File

@@ -261,7 +261,10 @@ if DEBUG:
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.DjangoModelPermissions"],
"DEFAULT_PERMISSION_CLASSES": [
"apps.api.permissions.NotInDemoMode",
"rest_framework.permissions.DjangoModelPermissions",
],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
@@ -394,3 +397,4 @@ PWA_SERVICE_WORKER_PATH = BASE_DIR / "templates" / "pwa" / "serviceworker.js"
ENABLE_SOFT_DELETE = os.getenv("ENABLE_SOFT_DELETE", "false").lower() == "true"
KEEP_DELETED_TRANSACTIONS_FOR = int(os.getenv("KEEP_DELETED_ENTRIES_FOR", "365"))
APP_VERSION = os.getenv("APP_VERSION", "unknown")
DEMO = os.getenv("DEMO_MODE", "false").lower() == "true"

View File

@@ -0,0 +1,10 @@
from rest_framework.permissions import BasePermission
from django.conf import settings
class NotInDemoMode(BasePermission):
def has_permission(self, request, view):
if settings.DEMO and not request.user.is_superuser:
return False
else:
return True

View File

@@ -0,0 +1,15 @@
from functools import wraps
from django.conf import settings
from django.core.exceptions import PermissionDenied
def disabled_on_demo(view):
@wraps(view)
def _view(request, *args, **kwargs):
if settings.DEMO and not request.user.is_superuser:
raise PermissionDenied
return view(request, *args, **kwargs)
return _view

View File

View File

@@ -0,0 +1,137 @@
import os
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth import get_user_model
from django.conf import settings
from django.db import IntegrityError
# Get the custom User model if defined, otherwise the default User model
User = get_user_model()
class Command(BaseCommand):
help = (
"Creates a superuser from environment variables (ADMIN_EMAIL, ADMIN_PASSWORD) "
"and optionally creates a demo user (demo@demo.com) if settings.DEMO is True."
)
def handle(self, *args, **options):
self.stdout.write("Starting user setup...")
# --- Create Superuser ---
admin_email = os.environ.get("ADMIN_EMAIL")
admin_password = os.environ.get("ADMIN_PASSWORD")
if admin_email and admin_password:
self.stdout.write(f"Attempting to create superuser: {admin_email}")
# Use email as username for simplicity, requires USERNAME_FIELD='email'
# or adapt if your USERNAME_FIELD is different.
# If USERNAME_FIELD is 'username', you might need ADMIN_USERNAME env var.
username_field = User.USERNAME_FIELD # Get the actual username field name
# Check if the user already exists by email or username
user_exists_kwargs = {"email": admin_email}
if username_field != "email":
# Assume username should also be the email if not explicitly provided
user_exists_kwargs[username_field] = admin_email
if User.objects.filter(**user_exists_kwargs).exists():
self.stdout.write(
self.style.WARNING(
f"Superuser with email '{admin_email}' (or corresponding username) already exists. Skipping creation."
)
)
else:
try:
create_kwargs = {
username_field: admin_email, # Use email as username by default
"email": admin_email,
"password": admin_password,
}
User.objects.create_superuser(**create_kwargs)
self.stdout.write(
self.style.SUCCESS(
f"Superuser '{admin_email}' created successfully."
)
)
except IntegrityError as e:
self.stdout.write(
self.style.ERROR(
f"Failed to create superuser '{admin_email}'. IntegrityError: {e}"
)
)
except Exception as e:
self.stdout.write(
self.style.ERROR(
f"An unexpected error occurred creating superuser '{admin_email}': {e}"
)
)
else:
self.stdout.write(
self.style.NOTICE(
"ADMIN_EMAIL or ADMIN_PASSWORD environment variables not set. Skipping superuser creation."
)
)
self.stdout.write("---") # Separator
# --- Create Demo User ---
# Use getattr to safely check for the DEMO setting, default to False if not present
create_demo_user = getattr(settings, "DEMO", False)
if create_demo_user:
demo_email = "demo@demo.com"
demo_password = (
"wygiwyhdemo" # Consider making this an env var too for security
)
demo_username = demo_email # Using email as username for consistency
self.stdout.write(
f"DEMO setting is True. Attempting to create demo user: {demo_email}"
)
username_field = User.USERNAME_FIELD # Get the actual username field name
# Check if the user already exists by email or username
user_exists_kwargs = {"email": demo_email}
if username_field != "email":
user_exists_kwargs[username_field] = demo_username
if User.objects.filter(**user_exists_kwargs).exists():
self.stdout.write(
self.style.WARNING(
f"Demo user with email '{demo_email}' (or corresponding username) already exists. Skipping creation."
)
)
else:
try:
create_kwargs = {
username_field: demo_username,
"email": demo_email,
"password": demo_password,
}
User.objects.create_user(**create_kwargs)
self.stdout.write(
self.style.SUCCESS(
f"Demo user '{demo_email}' created successfully."
)
)
except IntegrityError as e:
self.stdout.write(
self.style.ERROR(
f"Failed to create demo user '{demo_email}'. IntegrityError: {e}"
)
)
except Exception as e:
self.stdout.write(
self.style.ERROR(
f"An unexpected error occurred creating demo user '{demo_email}': {e}"
)
)
else:
self.stdout.write(
self.style.NOTICE(
"DEMO setting is not True (or not set). Skipping demo user creation."
)
)
self.stdout.write(self.style.SUCCESS("User setup command finished."))

View File

@@ -1,7 +1,9 @@
import logging
from asgiref.sync import sync_to_async
from django.conf import settings
from django.core import management
from django.db import DEFAULT_DB_ALIAS
from procrastinate import builtin_tasks
from procrastinate.contrib.django import app
@@ -40,3 +42,39 @@ async def remove_expired_sessions(timestamp=None):
"Error while executing 'remove_expired_sessions' task",
exc_info=True,
)
@app.periodic(cron="0 6 * * *")
@app.task(name="reset_demo_data")
def reset_demo_data():
"""
Wipes the database and loads fresh demo data if DEMO mode is active.
Runs daily at 6:00 AM.
"""
if not settings.DEMO:
return # Exit if not in demo mode
logger.info("Demo mode active. Starting daily data reset...")
try:
# 1. Flush the database (wipe all data)
logger.info("Flushing the database...")
# Using --noinput prevents prompts. Specify database if not default.
management.call_command(
"flush", "--noinput", database=DEFAULT_DB_ALIAS, verbosity=1
)
logger.info("Database flushed successfully.")
# 2. Load data from the fixture
fixture_name = "fixtures/demo_data.json"
logger.info(f"Loading data from fixture: {fixture_name}...")
management.call_command(
"loaddata", fixture_name, database=DEFAULT_DB_ALIAS, verbosity=1
)
logger.info(f"Data loaded successfully from {fixture_name}.")
logger.info("Daily demo data reset completed.")
except Exception as e:
logger.exception(f"Error during daily demo data reset: {e}")
raise

View File

@@ -11,9 +11,11 @@ from apps.common.decorators.htmx import only_htmx
from apps.currencies.forms import ExchangeRateForm, ExchangeRateServiceForm
from apps.currencies.models import ExchangeRate, ExchangeRateService
from apps.currencies.tasks import manual_fetch_exchange_rates
from apps.common.decorators.demo import disabled_on_demo
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def exchange_rates_services_index(request):
return render(
@@ -24,6 +26,7 @@ def exchange_rates_services_index(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def exchange_rates_services_list(request):
services = ExchangeRateService.objects.all()
@@ -37,6 +40,7 @@ def exchange_rates_services_list(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def exchange_rate_service_add(request):
if request.method == "POST":
@@ -63,6 +67,7 @@ def exchange_rate_service_add(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def exchange_rate_service_edit(request, pk):
service = get_object_or_404(ExchangeRateService, id=pk)
@@ -91,6 +96,7 @@ def exchange_rate_service_edit(request, pk):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def exchange_rate_service_delete(request, pk):
service = get_object_or_404(ExchangeRateService, id=pk)
@@ -109,6 +115,7 @@ def exchange_rate_service_delete(request, pk):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def exchange_rate_service_force_fetch(request):
manual_fetch_exchange_rates.defer()

View File

@@ -41,11 +41,13 @@ from apps.export_app.resources.transactions import (
RecurringTransactionResource,
)
from apps.export_app.resources.users import UserResource
from apps.common.decorators.demo import disabled_on_demo
logger = logging.getLogger()
@login_required
@disabled_on_demo
@user_passes_test(lambda u: u.is_superuser)
@require_http_methods(["GET"])
def export_index(request):
@@ -53,6 +55,7 @@ def export_index(request):
@login_required
@disabled_on_demo
@user_passes_test(lambda u: u.is_superuser)
@require_http_methods(["GET", "POST"])
def export_form(request):
@@ -182,6 +185,7 @@ def export_form(request):
@only_htmx
@login_required
@disabled_on_demo
@user_passes_test(lambda u: u.is_superuser)
@require_http_methods(["GET", "POST"])
def import_form(request):

View File

@@ -13,9 +13,11 @@ from apps.import_app.forms import ImportRunFileUploadForm, ImportProfileForm
from apps.import_app.models import ImportRun, ImportProfile
from apps.import_app.services import PresetService
from apps.import_app.tasks import process_import
from apps.common.decorators.demo import disabled_on_demo
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def import_presets_list(request):
presets = PresetService.get_all_presets()
@@ -27,6 +29,7 @@ def import_presets_list(request):
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_profile_index(request):
return render(
@@ -37,6 +40,7 @@ def import_profile_index(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_profile_list(request):
profiles = ImportProfile.objects.all()
@@ -50,6 +54,7 @@ def import_profile_list(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_profile_add(request):
message = request.POST.get("message", None)
@@ -85,6 +90,7 @@ def import_profile_add(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_profile_edit(request, profile_id):
profile = get_object_or_404(ImportProfile, id=profile_id)
@@ -114,6 +120,7 @@ def import_profile_edit(request, profile_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def import_profile_delete(request, profile_id):
profile = ImportProfile.objects.get(id=profile_id)
@@ -132,6 +139,7 @@ def import_profile_delete(request, profile_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_runs_list(request, profile_id):
profile = ImportProfile.objects.get(id=profile_id)
@@ -147,6 +155,7 @@ def import_runs_list(request, profile_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_run_log(request, profile_id, run_id):
run = ImportRun.objects.get(profile__id=profile_id, id=run_id)
@@ -160,6 +169,7 @@ def import_run_log(request, profile_id, run_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def import_run_add(request, profile_id):
profile = ImportProfile.objects.get(id=profile_id)
@@ -202,6 +212,7 @@ def import_run_add(request, profile_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def import_run_delete(request, profile_id, run_id):
run = ImportRun.objects.get(profile__id=profile_id, id=run_id)

View File

@@ -18,9 +18,11 @@ from apps.rules.models import (
)
from apps.common.models import SharedObject
from apps.common.forms import SharedObjectForm
from apps.common.decorators.demo import disabled_on_demo
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def rules_index(request):
return render(
@@ -31,6 +33,7 @@ def rules_index(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def rules_list(request):
transaction_rules = TransactionRule.objects.all().order_by("id")
@@ -43,6 +46,7 @@ def rules_list(request):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_toggle_activity(request, transaction_rule_id, **kwargs):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -65,6 +69,7 @@ def transaction_rule_toggle_activity(request, transaction_rule_id, **kwargs):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_add(request, **kwargs):
if request.method == "POST":
@@ -91,6 +96,7 @@ def transaction_rule_add(request, **kwargs):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_edit(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -129,6 +135,7 @@ def transaction_rule_edit(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_view(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -142,6 +149,7 @@ def transaction_rule_view(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def transaction_rule_delete(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -166,6 +174,7 @@ def transaction_rule_delete(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET"])
def transaction_rule_take_ownership(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -187,6 +196,7 @@ def transaction_rule_take_ownership(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_share(request, pk):
obj = get_object_or_404(TransactionRule, id=pk)
@@ -225,6 +235,7 @@ def transaction_rule_share(request, pk):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_action_add(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -252,6 +263,7 @@ def transaction_rule_action_add(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def transaction_rule_action_edit(request, transaction_rule_action_id):
transaction_rule_action = get_object_or_404(
@@ -289,6 +301,7 @@ def transaction_rule_action_edit(request, transaction_rule_action_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def transaction_rule_action_delete(request, transaction_rule_action_id):
transaction_rule_action = get_object_or_404(
@@ -309,6 +322,7 @@ def transaction_rule_action_delete(request, transaction_rule_action_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def update_or_create_transaction_rule_action_add(request, transaction_rule_id):
transaction_rule = get_object_or_404(TransactionRule, id=transaction_rule_id)
@@ -340,6 +354,7 @@ def update_or_create_transaction_rule_action_add(request, transaction_rule_id):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["GET", "POST"])
def update_or_create_transaction_rule_action_edit(request, pk):
linked_action = get_object_or_404(UpdateOrCreateTransactionRuleAction, id=pk)
@@ -374,6 +389,7 @@ def update_or_create_transaction_rule_action_edit(request, pk):
@only_htmx
@login_required
@disabled_on_demo
@require_http_methods(["DELETE"])
def update_or_create_transaction_rule_action_delete(request, pk):
linked_action = get_object_or_404(UpdateOrCreateTransactionRuleAction, id=pk)

View File

@@ -0,0 +1,34 @@
[
{
"model": "users.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$870000$kUmqeqdenjc2yFS8qbniwS$7qOMXzKG+yFmezdjhptkwuMJlqlZnQHXgAnonWurpBk=",
"last_login": "2025-03-31T03:22:25Z",
"is_superuser": false,
"first_name": "Demo",
"last_name": "User",
"is_staff": false,
"is_active": true,
"date_joined": "2025-03-31T03:21:04Z",
"email": "demo@demo.com",
"groups": [],
"user_permissions": []
}
},
{
"model": "users.usersettings",
"pk": 1,
"fields": {
"user": 1,
"hide_amounts": false,
"mute_sounds": false,
"date_format": "SHORT_DATE_FORMAT",
"datetime_format": "SHORT_DATETIME_FORMAT",
"number_format": "AA",
"language": "auto",
"timezone": "auto",
"start_page": "MONTHLY_OVERVIEW"
}
}
]

View File

@@ -7,9 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-09 21:56+0000\n"
"PO-Revision-Date: 2025-03-10 09:05+0000\n"
"Last-Translator: Schmitz Schmitz <stefanschmitz@t-online.de>\n"
"POT-Creation-Date: 2025-03-31 05:30+0000\n"
"PO-Revision-Date: 2025-03-30 15:07+0000\n"
"Last-Translator: valentin-p <valentinpouget@gmail.com>\n"
"Language-Team: German <https://translations.herculino.com/projects/wygiwyh/"
"app/de/>\n"
"Language: de\n"
@@ -17,11 +17,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10.2\n"
"X-Generator: Weblate 5.10.4\n"
#: apps/accounts/forms.py:24
msgid "Group name"
msgstr "Gruppenname"
msgstr "Gruppe Name"
#: apps/accounts/forms.py:40 apps/accounts/forms.py:98
#: apps/currencies/forms.py:53 apps/currencies/forms.py:91
@@ -190,7 +190,7 @@ msgstr "Kontengruppe erfolgreich hinzugefügt"
#: apps/accounts/views/account_groups.py:69
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
#: apps/dca/views.py:146 apps/rules/views.py:99 apps/rules/views.py:195
#: apps/dca/views.py:146 apps/rules/views.py:105 apps/rules/views.py:205
#: apps/transactions/views/categories.py:91
#: apps/transactions/views/categories.py:129
#: apps/transactions/views/entities.py:91
@@ -205,7 +205,7 @@ msgstr "Kontengruppe erfolgreich aktualisiert"
#: apps/accounts/views/account_groups.py:111
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
#: apps/rules/views.py:154 apps/transactions/views/categories.py:168
#: apps/rules/views.py:162 apps/transactions/views/categories.py:168
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
msgid "Item no longer shared with you"
msgstr "Einheit wird nicht länger mit dir geteilt"
@@ -216,14 +216,14 @@ msgstr "Kontengruppe erfolgreich gelöscht"
#: apps/accounts/views/account_groups.py:135
#: apps/accounts/views/accounts.py:169 apps/dca/views.py:129
#: apps/rules/views.py:178 apps/transactions/views/categories.py:192
#: apps/rules/views.py:187 apps/transactions/views/categories.py:192
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
msgid "Ownership taken successfully"
msgstr "Besitzeigenschaft erfolgreich übernommen"
#: apps/accounts/views/account_groups.py:165
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
#: apps/rules/views.py:208 apps/transactions/views/categories.py:142
#: apps/rules/views.py:218 apps/transactions/views/categories.py:142
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
msgid "Configuration saved successfully"
msgstr "Konfiguration erfolgreich gespeichert"
@@ -642,19 +642,19 @@ msgstr "Umrechnungskurs erfolgreich aktualisiert"
msgid "Exchange rate deleted successfully"
msgstr "Umrechnungskurs erfolgreich gelöscht"
#: apps/currencies/views/exchange_rates_services.py:46
#: apps/currencies/views/exchange_rates_services.py:50
msgid "Service added successfully"
msgstr "Dienst erfolgreich hinzugefügt"
#: apps/currencies/views/exchange_rates_services.py:74
#: apps/currencies/views/exchange_rates_services.py:79
msgid "Service updated successfully"
msgstr "Dienst erfolgreich aktualisiert"
#: apps/currencies/views/exchange_rates_services.py:100
#: apps/currencies/views/exchange_rates_services.py:106
msgid "Service deleted successfully"
msgstr "Dienst erfolgreich gelöscht"
#: apps/currencies/views/exchange_rates_services.py:115
#: apps/currencies/views/exchange_rates_services.py:122
msgid "Services queued successfully"
msgstr "Dienst erfolgreich in die Warteschlange eingereiht"
@@ -871,15 +871,15 @@ msgstr "Wiederherstellen"
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "Bitte eine ZIP-Datei oder zumindest eine CSV-Datei hochladen"
#: apps/export_app/views.py:174
#: apps/export_app/views.py:177
msgid "You have to select at least one export"
msgstr "Du musst mindestens einen Export auswählen"
#: apps/export_app/views.py:193
#: apps/export_app/views.py:197
msgid "Data restored successfully"
msgstr "Daten erfolgreich wiederhergestellt"
#: apps/export_app/views.py:205
#: apps/export_app/views.py:209
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
@@ -940,23 +940,23 @@ msgstr "Status"
msgid "File name"
msgstr "Dateiname"
#: apps/import_app/views.py:62
#: apps/import_app/views.py:67
msgid "Import Profile added successfully"
msgstr "Importprofil erfolgreich hinzugefügt"
#: apps/import_app/views.py:97
#: apps/import_app/views.py:103
msgid "Import Profile update successfully"
msgstr "Importprofil erfolgreich aktualisiert"
#: apps/import_app/views.py:123
#: apps/import_app/views.py:130
msgid "Import Profile deleted successfully"
msgstr "Importprofil erfolreich gelöscht"
#: apps/import_app/views.py:185
#: apps/import_app/views.py:195
msgid "Import Run queued successfully"
msgstr "Importvorgang erfolgreich in die Warteschlange eingereiht"
#: apps/import_app/views.py:211
#: apps/import_app/views.py:222
msgid "Run deleted successfully"
msgstr "Vorgang erfolgreich gelöscht"
@@ -1173,47 +1173,47 @@ msgstr ""
msgid "Update or create transaction action"
msgstr "Transaktions-Aktion aktualisieren oder erstellen"
#: apps/rules/views.py:54
#: apps/rules/views.py:58
msgid "Rule deactivated successfully"
msgstr "Regel erfolgreich deaktiviert"
#: apps/rules/views.py:56
#: apps/rules/views.py:60
msgid "Rule activated successfully"
msgstr "Regel erfolgreich aktiviert"
#: apps/rules/views.py:74
#: apps/rules/views.py:79
msgid "Rule added successfully"
msgstr "Regel erfolgreich hinzugefügt"
#: apps/rules/views.py:112
#: apps/rules/views.py:118
msgid "Rule updated successfully"
msgstr "Regel erfolgreich aktualisiert"
#: apps/rules/views.py:157
#: apps/rules/views.py:165
msgid "Rule deleted successfully"
msgstr "Regel erfolgreich gelöscht"
#: apps/rules/views.py:270
#: apps/rules/views.py:282
msgid "Action updated successfully"
msgstr "Aktion erfolgreich aktualisiert"
#: apps/rules/views.py:300
#: apps/rules/views.py:313
msgid "Action deleted successfully"
msgstr "Aktion erfolgreich gelöscht"
#: apps/rules/views.py:323
#: apps/rules/views.py:337
msgid "Update or Create Transaction action added successfully"
msgstr ""
"\"Transaktions-Aktualisierung oder -Erstellung\"-Aktion erfolgreich "
"hinzugefügt"
#: apps/rules/views.py:355
#: apps/rules/views.py:370
msgid "Update or Create Transaction action updated successfully"
msgstr ""
"\"Transaktions-Aktualisierung oder -Erstellung\"-Aktion erfolgreich "
"aktualisiert"
#: apps/rules/views.py:384
#: apps/rules/views.py:400
msgid "Update or Create Transaction action deleted successfully"
msgstr ""
"\"Transaktions-Aktualisierung oder -Erstellung\"-Aktion erfolgreich gelöscht"
@@ -1650,11 +1650,11 @@ msgstr "Berechtigungen"
msgid "Important dates"
msgstr "Wichtige Daten"
#: apps/users/forms.py:19 apps/users/models.py:13
#: apps/users/forms.py:19 apps/users/models.py:13 templates/users/login.html:19
msgid "E-mail"
msgstr "E-Mail"
#: apps/users/forms.py:25
#: apps/users/forms.py:25 templates/users/login.html:20
msgid "Password"
msgstr "Passwort"
@@ -2523,23 +2523,32 @@ msgstr "Django Admin"
msgid "Calculator"
msgstr "Rechner"
#: templates/includes/navbar/user_menu.html:12
#: templates/includes/navbar/user_menu.html:14
msgid "Settings"
msgstr "Einstellungen"
#: templates/includes/navbar/user_menu.html:39
#: templates/includes/navbar/user_menu.html:41
msgid "Clear cache"
msgstr "Cache leeren"
#: templates/includes/navbar/user_menu.html:43
#: templates/includes/navbar/user_menu.html:45
msgid "Logout"
msgstr "Abmelden"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:5
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:8
msgid "Access Denied"
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
msgid ""
"You do not have permission to perform this action or access this resource."
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:18
msgid "Something went wrong loading your data"
msgstr "Beim Laden deiner Daten ist etwas schief gegangen"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:6
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:19
msgid "Try reloading the page or check the console for more information."
msgstr ""
"Versuche die Seite neu zu laden oder überprüfe die Konsole für mehr "
@@ -2596,8 +2605,6 @@ msgid "average expenses"
msgstr "durchschnittliche Ausgaben"
#: templates/insights/fragments/emergency_fund.html:48
#, fuzzy
#| msgid "final total"
msgid "liquid total"
msgstr "Gesamtbilanz"
@@ -2712,6 +2719,14 @@ msgstr "Der Plan und alle zugehörigen Transaktionen werden gelöscht"
msgid "No installment plans"
msgstr "Keine Ratenzahlungs-Pläne"
#: templates/layouts/base.html:40
msgid "This is a demo!"
msgstr ""
#: templates/layouts/base.html:40
msgid "Any data you add here will be wiped in 24hrs or less"
msgstr ""
#: templates/mini_tools/currency_converter/currency_converter.html:58
msgid "Invert"
msgstr "Invertieren"
@@ -3027,6 +3042,14 @@ msgstr "Sounds abspielen"
msgid "Show amounts"
msgstr "Werte einblenden"
#: templates/users/login.html:17
msgid "Welcome to WYGIWYH's demo!"
msgstr ""
#: templates/users/login.html:18
msgid "Use the credentials below to login"
msgstr ""
#: templates/yearly_overview/pages/overview_by_account.html:7
#: templates/yearly_overview/pages/overview_by_currency.html:9
msgid "Yearly Overview"

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-09 21:56+0000\n"
"POT-Creation-Date: 2025-03-31 05:30+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -184,7 +184,7 @@ msgstr ""
#: apps/accounts/views/account_groups.py:69
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
#: apps/dca/views.py:146 apps/rules/views.py:99 apps/rules/views.py:195
#: apps/dca/views.py:146 apps/rules/views.py:105 apps/rules/views.py:205
#: apps/transactions/views/categories.py:91
#: apps/transactions/views/categories.py:129
#: apps/transactions/views/entities.py:91
@@ -199,7 +199,7 @@ msgstr ""
#: apps/accounts/views/account_groups.py:111
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
#: apps/rules/views.py:154 apps/transactions/views/categories.py:168
#: apps/rules/views.py:162 apps/transactions/views/categories.py:168
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
msgid "Item no longer shared with you"
msgstr ""
@@ -210,14 +210,14 @@ msgstr ""
#: apps/accounts/views/account_groups.py:135
#: apps/accounts/views/accounts.py:169 apps/dca/views.py:129
#: apps/rules/views.py:178 apps/transactions/views/categories.py:192
#: apps/rules/views.py:187 apps/transactions/views/categories.py:192
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
msgid "Ownership taken successfully"
msgstr ""
#: apps/accounts/views/account_groups.py:165
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
#: apps/rules/views.py:208 apps/transactions/views/categories.py:142
#: apps/rules/views.py:218 apps/transactions/views/categories.py:142
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
msgid "Configuration saved successfully"
msgstr ""
@@ -624,19 +624,19 @@ msgstr ""
msgid "Exchange rate deleted successfully"
msgstr ""
#: apps/currencies/views/exchange_rates_services.py:46
#: apps/currencies/views/exchange_rates_services.py:50
msgid "Service added successfully"
msgstr ""
#: apps/currencies/views/exchange_rates_services.py:74
#: apps/currencies/views/exchange_rates_services.py:79
msgid "Service updated successfully"
msgstr ""
#: apps/currencies/views/exchange_rates_services.py:100
#: apps/currencies/views/exchange_rates_services.py:106
msgid "Service deleted successfully"
msgstr ""
#: apps/currencies/views/exchange_rates_services.py:115
#: apps/currencies/views/exchange_rates_services.py:122
msgid "Services queued successfully"
msgstr ""
@@ -851,15 +851,15 @@ msgstr ""
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr ""
#: apps/export_app/views.py:174
#: apps/export_app/views.py:177
msgid "You have to select at least one export"
msgstr ""
#: apps/export_app/views.py:193
#: apps/export_app/views.py:197
msgid "Data restored successfully"
msgstr ""
#: apps/export_app/views.py:205
#: apps/export_app/views.py:209
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
@@ -918,23 +918,23 @@ msgstr ""
msgid "File name"
msgstr ""
#: apps/import_app/views.py:62
#: apps/import_app/views.py:67
msgid "Import Profile added successfully"
msgstr ""
#: apps/import_app/views.py:97
#: apps/import_app/views.py:103
msgid "Import Profile update successfully"
msgstr ""
#: apps/import_app/views.py:123
#: apps/import_app/views.py:130
msgid "Import Profile deleted successfully"
msgstr ""
#: apps/import_app/views.py:185
#: apps/import_app/views.py:195
msgid "Import Run queued successfully"
msgstr ""
#: apps/import_app/views.py:211
#: apps/import_app/views.py:222
msgid "Run deleted successfully"
msgstr ""
@@ -1149,43 +1149,43 @@ msgstr ""
msgid "Update or create transaction action"
msgstr ""
#: apps/rules/views.py:54
#: apps/rules/views.py:58
msgid "Rule deactivated successfully"
msgstr ""
#: apps/rules/views.py:56
#: apps/rules/views.py:60
msgid "Rule activated successfully"
msgstr ""
#: apps/rules/views.py:74
#: apps/rules/views.py:79
msgid "Rule added successfully"
msgstr ""
#: apps/rules/views.py:112
#: apps/rules/views.py:118
msgid "Rule updated successfully"
msgstr ""
#: apps/rules/views.py:157
#: apps/rules/views.py:165
msgid "Rule deleted successfully"
msgstr ""
#: apps/rules/views.py:270
#: apps/rules/views.py:282
msgid "Action updated successfully"
msgstr ""
#: apps/rules/views.py:300
#: apps/rules/views.py:313
msgid "Action deleted successfully"
msgstr ""
#: apps/rules/views.py:323
#: apps/rules/views.py:337
msgid "Update or Create Transaction action added successfully"
msgstr ""
#: apps/rules/views.py:355
#: apps/rules/views.py:370
msgid "Update or Create Transaction action updated successfully"
msgstr ""
#: apps/rules/views.py:384
#: apps/rules/views.py:400
msgid "Update or Create Transaction action deleted successfully"
msgstr ""
@@ -1614,11 +1614,11 @@ msgstr ""
msgid "Important dates"
msgstr ""
#: apps/users/forms.py:19 apps/users/models.py:13
#: apps/users/forms.py:19 apps/users/models.py:13 templates/users/login.html:19
msgid "E-mail"
msgstr ""
#: apps/users/forms.py:25
#: apps/users/forms.py:25 templates/users/login.html:20
msgid "Password"
msgstr ""
@@ -2484,23 +2484,32 @@ msgstr ""
msgid "Calculator"
msgstr ""
#: templates/includes/navbar/user_menu.html:12
#: templates/includes/navbar/user_menu.html:14
msgid "Settings"
msgstr ""
#: templates/includes/navbar/user_menu.html:39
#: templates/includes/navbar/user_menu.html:41
msgid "Clear cache"
msgstr ""
#: templates/includes/navbar/user_menu.html:43
#: templates/includes/navbar/user_menu.html:45
msgid "Logout"
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:5
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:8
msgid "Access Denied"
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
msgid ""
"You do not have permission to perform this action or access this resource."
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:18
msgid "Something went wrong loading your data"
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:6
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:19
msgid "Try reloading the page or check the console for more information."
msgstr ""
@@ -2667,6 +2676,14 @@ msgstr ""
msgid "No installment plans"
msgstr ""
#: templates/layouts/base.html:40
msgid "This is a demo!"
msgstr ""
#: templates/layouts/base.html:40
msgid "Any data you add here will be wiped in 24hrs or less"
msgstr ""
#: templates/mini_tools/currency_converter/currency_converter.html:58
msgid "Invert"
msgstr ""
@@ -2977,6 +2994,14 @@ msgstr ""
msgid "Show amounts"
msgstr ""
#: templates/users/login.html:17
msgid "Welcome to WYGIWYH's demo!"
msgstr ""
#: templates/users/login.html:18
msgid "Use the credentials below to login"
msgstr ""
#: templates/yearly_overview/pages/overview_by_account.html:7
#: templates/yearly_overview/pages/overview_by_currency.html:9
msgid "Yearly Overview"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-09 21:56+0000\n"
"POT-Creation-Date: 2025-03-31 05:30+0000\n"
"PO-Revision-Date: 2025-03-13 07:05+0000\n"
"Last-Translator: Dimitri Decrock <dj.flashpower@gmail.com>\n"
"Language-Team: Dutch <https://translations.herculino.com/projects/wygiwyh/"
@@ -190,7 +190,7 @@ msgstr "Rekeninggroep succesvol toegevoegd"
#: apps/accounts/views/account_groups.py:69
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
#: apps/dca/views.py:146 apps/rules/views.py:99 apps/rules/views.py:195
#: apps/dca/views.py:146 apps/rules/views.py:105 apps/rules/views.py:205
#: apps/transactions/views/categories.py:91
#: apps/transactions/views/categories.py:129
#: apps/transactions/views/entities.py:91
@@ -205,7 +205,7 @@ msgstr "Rekeninggroep succesvol bijgewerkt"
#: apps/accounts/views/account_groups.py:111
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
#: apps/rules/views.py:154 apps/transactions/views/categories.py:168
#: apps/rules/views.py:162 apps/transactions/views/categories.py:168
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
msgid "Item no longer shared with you"
msgstr "Item is niet langer met jouw gedeeld"
@@ -216,14 +216,14 @@ msgstr "Rekeninggroep succesvol verwijderd"
#: apps/accounts/views/account_groups.py:135
#: apps/accounts/views/accounts.py:169 apps/dca/views.py:129
#: apps/rules/views.py:178 apps/transactions/views/categories.py:192
#: apps/rules/views.py:187 apps/transactions/views/categories.py:192
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
msgid "Ownership taken successfully"
msgstr "Eigendom succesvol genomen"
#: apps/accounts/views/account_groups.py:165
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
#: apps/rules/views.py:208 apps/transactions/views/categories.py:142
#: apps/rules/views.py:218 apps/transactions/views/categories.py:142
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
msgid "Configuration saved successfully"
msgstr "Configuratie succesvol opgeslagen"
@@ -644,19 +644,19 @@ msgstr "Wisselkoers succesvol bijgewerkt"
msgid "Exchange rate deleted successfully"
msgstr "Wisselkoers succesvol verwijderd"
#: apps/currencies/views/exchange_rates_services.py:46
#: apps/currencies/views/exchange_rates_services.py:50
msgid "Service added successfully"
msgstr "Dienst succesvol toegevoegd"
#: apps/currencies/views/exchange_rates_services.py:74
#: apps/currencies/views/exchange_rates_services.py:79
msgid "Service updated successfully"
msgstr "Dienst succesvol bijgewerkt"
#: apps/currencies/views/exchange_rates_services.py:100
#: apps/currencies/views/exchange_rates_services.py:106
msgid "Service deleted successfully"
msgstr "Dienst succesvol verwijderd"
#: apps/currencies/views/exchange_rates_services.py:115
#: apps/currencies/views/exchange_rates_services.py:122
msgid "Services queued successfully"
msgstr "Diensten succesvol in de wachtrij geplaatst"
@@ -872,15 +872,15 @@ msgstr "Herstel"
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "Upload een ZIP-bestand of ten minste één CSV-bestand"
#: apps/export_app/views.py:174
#: apps/export_app/views.py:177
msgid "You have to select at least one export"
msgstr "U moet ten minste één export selecteren"
#: apps/export_app/views.py:193
#: apps/export_app/views.py:197
msgid "Data restored successfully"
msgstr "Gegevens succesvol hersteld"
#: apps/export_app/views.py:205
#: apps/export_app/views.py:209
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
@@ -941,23 +941,23 @@ msgstr "Status"
msgid "File name"
msgstr "Bestandsnaam"
#: apps/import_app/views.py:62
#: apps/import_app/views.py:67
msgid "Import Profile added successfully"
msgstr "Importprofiel succesvol toegevoegd"
#: apps/import_app/views.py:97
#: apps/import_app/views.py:103
msgid "Import Profile update successfully"
msgstr "Importprofiel succesvol bijgewerkt"
#: apps/import_app/views.py:123
#: apps/import_app/views.py:130
msgid "Import Profile deleted successfully"
msgstr "Importprofiel succesvol verwijderd"
#: apps/import_app/views.py:185
#: apps/import_app/views.py:195
msgid "Import Run queued successfully"
msgstr "Importrun met succes in de wachtrij geplaatst"
#: apps/import_app/views.py:211
#: apps/import_app/views.py:222
msgid "Run deleted successfully"
msgstr "Run met succes verwijderd"
@@ -1174,43 +1174,43 @@ msgstr ""
msgid "Update or create transaction action"
msgstr "Bewerk of maak verrichtingsregel actie"
#: apps/rules/views.py:54
#: apps/rules/views.py:58
msgid "Rule deactivated successfully"
msgstr "Regel succesvol uitgeschakeld"
#: apps/rules/views.py:56
#: apps/rules/views.py:60
msgid "Rule activated successfully"
msgstr "Regel succesvol ingeschakeld"
#: apps/rules/views.py:74
#: apps/rules/views.py:79
msgid "Rule added successfully"
msgstr "Regel succesvol toegevoegd"
#: apps/rules/views.py:112
#: apps/rules/views.py:118
msgid "Rule updated successfully"
msgstr "Regel succesvol bijgewerkt"
#: apps/rules/views.py:157
#: apps/rules/views.py:165
msgid "Rule deleted successfully"
msgstr "Regel succesvol verwijderd"
#: apps/rules/views.py:270
#: apps/rules/views.py:282
msgid "Action updated successfully"
msgstr "Actie succesvol bijgewerkt"
#: apps/rules/views.py:300
#: apps/rules/views.py:313
msgid "Action deleted successfully"
msgstr "Actie succesvol verwijderd"
#: apps/rules/views.py:323
#: apps/rules/views.py:337
msgid "Update or Create Transaction action added successfully"
msgstr "Verrichting Bijwerken Of Maken succesvol toegevoegd"
#: apps/rules/views.py:355
#: apps/rules/views.py:370
msgid "Update or Create Transaction action updated successfully"
msgstr "Verrichting Bijwerken Of Maken succesvol bijgewerkt"
#: apps/rules/views.py:384
#: apps/rules/views.py:400
msgid "Update or Create Transaction action deleted successfully"
msgstr "Verrichting Bijwerken Of Maken succesvol verwijderd"
@@ -1645,11 +1645,11 @@ msgstr "Rechten"
msgid "Important dates"
msgstr "Belangrijke datums"
#: apps/users/forms.py:19 apps/users/models.py:13
#: apps/users/forms.py:19 apps/users/models.py:13 templates/users/login.html:19
msgid "E-mail"
msgstr "E-mailadres"
#: apps/users/forms.py:25
#: apps/users/forms.py:25 templates/users/login.html:20
msgid "Password"
msgstr "Wachtwoord"
@@ -2516,23 +2516,32 @@ msgstr "Django Beheerder"
msgid "Calculator"
msgstr "Rekenmachine"
#: templates/includes/navbar/user_menu.html:12
#: templates/includes/navbar/user_menu.html:14
msgid "Settings"
msgstr "Instellingen"
#: templates/includes/navbar/user_menu.html:39
#: templates/includes/navbar/user_menu.html:41
msgid "Clear cache"
msgstr "Leegmaken"
#: templates/includes/navbar/user_menu.html:43
#: templates/includes/navbar/user_menu.html:45
msgid "Logout"
msgstr "Uitloggen"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:5
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:8
msgid "Access Denied"
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
msgid ""
"You do not have permission to perform this action or access this resource."
msgstr ""
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:18
msgid "Something went wrong loading your data"
msgstr "Er is iets misgegaan bij het laden van uw gegevens"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:6
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:19
msgid "Try reloading the page or check the console for more information."
msgstr ""
"Probeer de pagina opnieuw te laden of controleer de console voor meer "
@@ -2703,6 +2712,14 @@ msgstr "Hiermee worden het plan en alle bijbehorende verrichtingen verwijderd"
msgid "No installment plans"
msgstr "Geen afbetalingsplannen"
#: templates/layouts/base.html:40
msgid "This is a demo!"
msgstr ""
#: templates/layouts/base.html:40
msgid "Any data you add here will be wiped in 24hrs or less"
msgstr ""
#: templates/mini_tools/currency_converter/currency_converter.html:58
msgid "Invert"
msgstr "Omdraaien"
@@ -3019,6 +3036,14 @@ msgstr "Geluiden afspelen"
msgid "Show amounts"
msgstr "Bedragen tonen"
#: templates/users/login.html:17
msgid "Welcome to WYGIWYH's demo!"
msgstr ""
#: templates/users/login.html:18
msgid "Use the credentials below to login"
msgstr ""
#: templates/yearly_overview/pages/overview_by_account.html:7
#: templates/yearly_overview/pages/overview_by_currency.html:9
msgid "Yearly Overview"

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-03-09 21:56+0000\n"
"PO-Revision-Date: 2025-03-09 23:10+0000\n"
"POT-Creation-Date: 2025-03-31 05:30+0000\n"
"PO-Revision-Date: 2025-03-31 05:38+0000\n"
"Last-Translator: Herculino Trotta <netotrotta@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://translations.herculino.com/"
"projects/wygiwyh/app/pt_BR/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.10.2\n"
"X-Generator: Weblate 5.10.4\n"
#: apps/accounts/forms.py:24
msgid "Group name"
@@ -188,7 +188,7 @@ msgstr "Grupo de Conta adicionado com sucesso"
#: apps/accounts/views/account_groups.py:69
#: apps/accounts/views/account_groups.py:152 apps/accounts/views/accounts.py:68
#: apps/accounts/views/accounts.py:106 apps/dca/views.py:63
#: apps/dca/views.py:146 apps/rules/views.py:99 apps/rules/views.py:195
#: apps/dca/views.py:146 apps/rules/views.py:105 apps/rules/views.py:205
#: apps/transactions/views/categories.py:91
#: apps/transactions/views/categories.py:129
#: apps/transactions/views/entities.py:91
@@ -203,7 +203,7 @@ msgstr "Grupo de Conta atualizado com sucesso"
#: apps/accounts/views/account_groups.py:111
#: apps/accounts/views/accounts.py:145 apps/dca/views.py:105
#: apps/rules/views.py:154 apps/transactions/views/categories.py:168
#: apps/rules/views.py:162 apps/transactions/views/categories.py:168
#: apps/transactions/views/entities.py:130 apps/transactions/views/tags.py:130
msgid "Item no longer shared with you"
msgstr "Item não está mais compartilhado com você"
@@ -214,14 +214,14 @@ msgstr "Grupo de Conta apagado com sucesso"
#: apps/accounts/views/account_groups.py:135
#: apps/accounts/views/accounts.py:169 apps/dca/views.py:129
#: apps/rules/views.py:178 apps/transactions/views/categories.py:192
#: apps/rules/views.py:187 apps/transactions/views/categories.py:192
#: apps/transactions/views/entities.py:154 apps/transactions/views/tags.py:154
msgid "Ownership taken successfully"
msgstr "Propriedade assumida com sucesso"
#: apps/accounts/views/account_groups.py:165
#: apps/accounts/views/accounts.py:119 apps/dca/views.py:159
#: apps/rules/views.py:208 apps/transactions/views/categories.py:142
#: apps/rules/views.py:218 apps/transactions/views/categories.py:142
#: apps/transactions/views/entities.py:184 apps/transactions/views/tags.py:184
msgid "Configuration saved successfully"
msgstr "Configuração salva com sucesso"
@@ -643,19 +643,19 @@ msgstr "Taxa de câmbio atualizada com sucesso"
msgid "Exchange rate deleted successfully"
msgstr "Taxa de câmbio apagada com sucesso"
#: apps/currencies/views/exchange_rates_services.py:46
#: apps/currencies/views/exchange_rates_services.py:50
msgid "Service added successfully"
msgstr "Serviço adicionado com sucesso"
#: apps/currencies/views/exchange_rates_services.py:74
#: apps/currencies/views/exchange_rates_services.py:79
msgid "Service updated successfully"
msgstr "Serviço atualizado com sucesso"
#: apps/currencies/views/exchange_rates_services.py:100
#: apps/currencies/views/exchange_rates_services.py:106
msgid "Service deleted successfully"
msgstr "Serviço apagado com sucesso"
#: apps/currencies/views/exchange_rates_services.py:115
#: apps/currencies/views/exchange_rates_services.py:122
msgid "Services queued successfully"
msgstr "Serviços marcados para execução com sucesso"
@@ -870,15 +870,15 @@ msgstr "Restaurar"
msgid "Please upload either a ZIP file or at least one CSV file"
msgstr "Carregue um arquivo ZIP ou pelo menos um arquivo CSV"
#: apps/export_app/views.py:174
#: apps/export_app/views.py:177
msgid "You have to select at least one export"
msgstr "É necessário selecionar pelo menos uma exportação"
#: apps/export_app/views.py:193
#: apps/export_app/views.py:197
msgid "Data restored successfully"
msgstr "Dados restaurados com sucesso"
#: apps/export_app/views.py:205
#: apps/export_app/views.py:209
msgid ""
"There was an error restoring your data. Check the logs for more details."
msgstr ""
@@ -939,23 +939,23 @@ msgstr "Status"
msgid "File name"
msgstr "Nome do Arquivo"
#: apps/import_app/views.py:62
#: apps/import_app/views.py:67
msgid "Import Profile added successfully"
msgstr "Perfil de Importação adicionado com sucesso"
#: apps/import_app/views.py:97
#: apps/import_app/views.py:103
msgid "Import Profile update successfully"
msgstr "Importação atualizada com sucesso"
#: apps/import_app/views.py:123
#: apps/import_app/views.py:130
msgid "Import Profile deleted successfully"
msgstr "Importação apagada com sucesso"
#: apps/import_app/views.py:185
#: apps/import_app/views.py:195
msgid "Import Run queued successfully"
msgstr "Importação adicionada à fila com sucesso"
#: apps/import_app/views.py:211
#: apps/import_app/views.py:222
msgid "Run deleted successfully"
msgstr "Importação apagada com sucesso"
@@ -1172,43 +1172,43 @@ msgstr ""
msgid "Update or create transaction action"
msgstr "Ação de atualizar ou criar transação"
#: apps/rules/views.py:54
#: apps/rules/views.py:58
msgid "Rule deactivated successfully"
msgstr "Regra desativada com sucesso"
#: apps/rules/views.py:56
#: apps/rules/views.py:60
msgid "Rule activated successfully"
msgstr "Regra ativada com sucesso"
#: apps/rules/views.py:74
#: apps/rules/views.py:79
msgid "Rule added successfully"
msgstr "Regra adicionada com sucesso"
#: apps/rules/views.py:112
#: apps/rules/views.py:118
msgid "Rule updated successfully"
msgstr "Regra atualizada com sucesso"
#: apps/rules/views.py:157
#: apps/rules/views.py:165
msgid "Rule deleted successfully"
msgstr "Regra apagada com sucesso"
#: apps/rules/views.py:270
#: apps/rules/views.py:282
msgid "Action updated successfully"
msgstr "Ação atualizada com sucesso"
#: apps/rules/views.py:300
#: apps/rules/views.py:313
msgid "Action deleted successfully"
msgstr "Ação apagada com sucesso"
#: apps/rules/views.py:323
#: apps/rules/views.py:337
msgid "Update or Create Transaction action added successfully"
msgstr "Ação Atualizar ou Criar Transação adicionada com sucesso"
#: apps/rules/views.py:355
#: apps/rules/views.py:370
msgid "Update or Create Transaction action updated successfully"
msgstr "Ação Atualizar ou Criar Transação atualizada com sucesso"
#: apps/rules/views.py:384
#: apps/rules/views.py:400
msgid "Update or Create Transaction action deleted successfully"
msgstr "Ação Atualizar ou Criar Transação apagada com sucesso"
@@ -1642,11 +1642,11 @@ msgstr "Permissões"
msgid "Important dates"
msgstr "Datas importantes"
#: apps/users/forms.py:19 apps/users/models.py:13
#: apps/users/forms.py:19 apps/users/models.py:13 templates/users/login.html:19
msgid "E-mail"
msgstr "E-mail"
#: apps/users/forms.py:25
#: apps/users/forms.py:25 templates/users/login.html:20
msgid "Password"
msgstr "Senha"
@@ -2515,23 +2515,32 @@ msgstr "Django Admin"
msgid "Calculator"
msgstr "Calculadora"
#: templates/includes/navbar/user_menu.html:12
#: templates/includes/navbar/user_menu.html:14
msgid "Settings"
msgstr "Configurações"
#: templates/includes/navbar/user_menu.html:39
#: templates/includes/navbar/user_menu.html:41
msgid "Clear cache"
msgstr "Limpar cache"
#: templates/includes/navbar/user_menu.html:43
#: templates/includes/navbar/user_menu.html:45
msgid "Logout"
msgstr "Sair"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:5
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:8
msgid "Access Denied"
msgstr "Acesso Negado"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
msgid ""
"You do not have permission to perform this action or access this resource."
msgstr "Você não tem permissão para executar essa ação ou acessar esse recurso."
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:18
msgid "Something went wrong loading your data"
msgstr "Algo deu errado ao carregar seus dados"
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:6
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:19
msgid "Try reloading the page or check the console for more information."
msgstr ""
"Tente recarregar a página ou verifique o console para obter mais informações."
@@ -2701,6 +2710,15 @@ msgstr "Isso excluirá o parcelamento e todas as transações associadas a ele"
msgid "No installment plans"
msgstr "Nenhum parcelamento"
#: templates/layouts/base.html:40
msgid "This is a demo!"
msgstr "Isto é uma demonstração!"
#: templates/layouts/base.html:40
msgid "Any data you add here will be wiped in 24hrs or less"
msgstr ""
"Todos os dados que você adicionar aqui serão apagados em 24 horas ou menos"
#: templates/mini_tools/currency_converter/currency_converter.html:58
msgid "Invert"
msgstr "Inverter"
@@ -3014,6 +3032,14 @@ msgstr "Reproduzir sons"
msgid "Show amounts"
msgstr "Mostrar valores"
#: templates/users/login.html:17
msgid "Welcome to WYGIWYH's demo!"
msgstr "Boas-vindas à demonstração do WYGIWYH!"
#: templates/users/login.html:18
msgid "Use the credentials below to login"
msgstr "Use as credenciais abaixo para fazer login"
#: templates/yearly_overview/pages/overview_by_account.html:7
#: templates/yearly_overview/pages/overview_by_currency.html:9
msgid "Yearly Overview"

View File

@@ -5,6 +5,8 @@
<i class="fa-solid fa-user"></i>
</a>
<ul class="dropdown-menu dropdown-menu-start dropdown-menu-lg-end">
<li class="dropdown-item-text">{{ user.email }}</li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item"
hx-get="{% url 'user_settings' %}"
hx-target="#generic-offcanvas"

View File

@@ -1,15 +1,30 @@
{% load i18n %}
<script type="text/hyperscript">
behavior htmx_error_handler
on htmx:responseError or htmx:afterRequest[detail.failed] or htmx:sendError queue none
call Swal.fire({title: '{% trans 'Something went wrong loading your data' %}',
text: '{% trans 'Try reloading the page or check the console for more information.' %}',
icon: 'error',
customClass: {
confirmButton: 'btn btn-primary'
},
buttonsStyling: true})
then log event
then halt the event
end
behavior htmx_error_handler
on htmx:responseError or htmx:afterRequest[detail.failed] or htmx:sendError queue none
-- Check if the event detail contains the xhr object and the status is 403
if event.detail.xhr.status == 403 then
call Swal.fire({
title: '{% trans "Access Denied" %}',
text: '{% trans "You do not have permission to perform this action or access this resource." %}',
icon: 'warning',
customClass: {
confirmButton: 'btn btn-warning' -- Optional: different button style
},
buttonsStyling: true
})
else
call Swal.fire({
title: '{% trans "Something went wrong loading your data" %}',
text: '{% trans "Try reloading the page or check the console for more information." %}',
icon: 'error',
customClass: {
confirmButton: 'btn btn-primary'
},
buttonsStyling: true
})
end
then log event
then halt the event
end
</script>

View File

@@ -1,3 +1,4 @@
{% load settings %}
{% load pwa %}
{% load formats %}
{% load i18n %}
@@ -5,43 +6,53 @@
{% load webpack_loader %}
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
{% filter site_title %}
{% block title %}
{% endblock title %}
{% endfilter %}
</title>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
{% filter site_title %}
{% block title %}
{% endblock title %}
{% endfilter %}
</title>
{% include 'includes/head/favicons.html' %}
{% progressive_web_app_meta %}
{% include 'includes/head/favicons.html' %}
{% progressive_web_app_meta %}
{% include 'includes/styles.html' %}
{% block extra_styles %}{% endblock %}
{% include 'includes/scripts.html' %}
{% include 'includes/styles.html' %}
{% block extra_styles %}{% endblock %}
{% block extra_js_head %}{% endblock %}
</head>
<body class="font-monospace">
<div _="install hide_amounts
{% include 'includes/scripts.html' %}
{% block extra_js_head %}{% endblock %}
</head>
<body class="font-monospace">
<div _="install hide_amounts
install htmx_error_handler
{% block body_hyperscript %}{% endblock %}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% include 'includes/navbar.html' %}
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% include 'includes/navbar.html' %}
<div id="content">
{% block content %}{% endblock %}
</div>
{% include 'includes/offcanvas.html' %}
{% include 'includes/toasts.html' %}
{% settings "DEMO" as demo_mode %}
{% if demo_mode %}
<div class="px-3 m-0" id="demo-mode-alert" hx-preserve>
<div class="alert alert-warning alert-dismissible fade show my-3" role="alert">
<strong>{% trans 'This is a demo!' %}</strong> {% trans 'Any data you add here will be wiped in 24hrs or less' %}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
{% include 'includes/tools/calculator.html' %}
<div id="content">
{% block content %}{% endblock %}
</div>
{% block extra_js_body %}{% endblock %}
</body>
{% include 'includes/offcanvas.html' %}
{% include 'includes/toasts.html' %}
</div>
{% include 'includes/tools/calculator.html' %}
{% block extra_js_body %}{% endblock %}
</body>
</html>

View File

@@ -1,4 +1,6 @@
{% extends "layouts/base_auth.html" %}
{% load i18n %}
{% load settings %}
{% load crispy_forms_tags %}
{% block title %}Login{% endblock %}
@@ -7,15 +9,26 @@
<div>
<div class="container">
<div class="row vh-100 d-flex justify-content-center align-items-center">
<div class="col-md-6 col-xl-4 col-12">
<div class="card shadow-lg">
<div class="card-body">
<h2 class="card-title text-center mb-4">Login</h2>
{% crispy form %}
</div>
</div>
<div class="col-md-6 col-xl-4 col-12">
{% settings "DEMO" as demo_mode %}
{% if demo_mode %}
<div class="card shadow mb-3">
<div class="card-body">
<h1 class="h5 card-title text-center mb-4">{% trans "Welcome to WYGIWYH's demo!" %}</h1>
<p>{% trans 'Use the credentials below to login' %}:</p>
<p>{% trans 'E-mail' %}: <span class="badge text-bg-secondary user-select-all">demo@demo.com</span></p>
<p>{% trans 'Password' %}: <span class="badge text-bg-secondary user-select-all">wygiwyhdemo</span></p>
</div>
</div>
{% endif %}
<div class="card shadow-lg">
<div class="card-body">
<h1 class="h2 card-title text-center mb-4">Login</h1>
{% crispy form %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -11,4 +11,6 @@ python manage.py migrate
# Create flag file to signal migrations are complete
touch /tmp/migrations_complete
python manage.py setup_users
exec python manage.py runserver 0.0.0.0:8000

View File

@@ -13,4 +13,6 @@ python manage.py migrate
# Create flag file to signal migrations are complete
touch /tmp/migrations_complete
python manage.py setup_users
exec gunicorn WYGIWYH.wsgi:application --bind 0.0.0.0:8000 --timeout 600