mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-25 08:54:52 +01:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa85303f36 | ||
|
|
a5f4f43678 | ||
|
|
d807bd5da3 | ||
|
|
85314fb749 | ||
|
|
c4d5e93a41 | ||
|
|
86f0c4365e | ||
|
|
202592b940 | ||
|
|
aea149bd13 | ||
|
|
411365f101 | ||
|
|
2008476021 | ||
|
|
53afe5b8eb | ||
|
|
6193c7a048 | ||
|
|
41f81d90d7 | ||
|
|
bf623cf16b | ||
|
|
ec213330cd | ||
|
|
7aedf524c6 | ||
|
|
04602b1964 | ||
|
|
15cfc4f300 | ||
|
|
3463c7c62c | ||
|
|
7b76c10093 | ||
|
|
7ad26a2e7b | ||
|
|
7706ca2d5f | ||
|
|
56198e93ce | ||
|
|
a74323f739 | ||
|
|
e4efde177b | ||
|
|
5871a03ee2 | ||
|
|
67af4430e1 | ||
|
|
696dcdf951 | ||
|
|
e35bad0e08 | ||
|
|
904f7cac22 | ||
|
|
ccd73963ca | ||
|
|
b5469b0413 | ||
|
|
dae848d951 | ||
|
|
45a33ad0c0 | ||
|
|
89e50b17bd | ||
|
|
ac54ba3da1 | ||
|
|
2da610f15e | ||
|
|
4ab6c4c6b6 | ||
|
|
68dbedd938 | ||
|
|
2800c53346 | ||
|
|
132547a074 | ||
|
|
61ed87dc45 | ||
|
|
96c1227c4f | ||
|
|
33f1ac1785 | ||
|
|
e9e94a8343 | ||
|
|
ba24a53853 | ||
|
|
4955fbde33 | ||
|
|
d04067a91d | ||
|
|
01333a439b | ||
|
|
d26907ea94 | ||
|
|
c98d9d3ce9 | ||
|
|
bfa4d3dea3 | ||
|
|
90323049eb | ||
|
|
b62122ed23 | ||
|
|
f74946cba7 | ||
|
|
585652064a | ||
|
|
ea6f61d5e4 | ||
|
|
e986f7d802 | ||
|
|
26b218ae51 | ||
|
|
19f0bc1034 | ||
|
|
47d34f3c27 | ||
|
|
046e02d506 | ||
|
|
92c7a29b6a | ||
|
|
d95e5f71cc |
@@ -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>
|
||||
|
||||
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: eitchtee
|
||||
custom: ["https://www.paypal.com/donate/?hosted_button_id=FFWM4W9NQDMM6"]
|
||||
18
README.md
18
README.md
@@ -51,6 +51,17 @@ Frustrated by the lack of comprehensive options, I set out to build **WYGIWYH**
|
||||
* **Built-in Dollar-Cost Average (DCA) tracker**: Essential for tracking recurring investments, especially for crypto and stocks.
|
||||
* **API support for automation**: Seamlessly integrate with existing services to synchronize transactions.
|
||||
|
||||
# Demo
|
||||
|
||||
You can try WYGIWYH on [wygiwyh-demo.herculino.com](https://wygiwyh-demo.herculino.com/) with the credentials below:
|
||||
|
||||
> [!NOTE]
|
||||
> E-mail: `demo@demo.com`
|
||||
>
|
||||
> Password: `wygiwyhdemo`
|
||||
|
||||
Keep in mind that **any data you add will be wiped in 24 hours or less**. And that **most automation features like the API, Rules, Automatic Exchange Rates and Import/Export are disabled**.
|
||||
|
||||
# How To Use
|
||||
|
||||
To run this application, you'll need [Docker](https://docs.docker.com/engine/install/) with [docker-compose](https://docs.docker.com/compose/install/).
|
||||
@@ -76,7 +87,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 +128,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 +140,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
|
||||
|
||||
|
||||
@@ -163,10 +163,105 @@ AUTH_USER_MODEL = "users.User"
|
||||
|
||||
LANGUAGE_CODE = "en"
|
||||
LANGUAGES = (
|
||||
("af", "Afrikaans"),
|
||||
("ar", "العربية"),
|
||||
("ar-dz", "العربية (الجزائر)"), # Algerian Arabic often uses the base name + region
|
||||
("ast", "Asturianu"),
|
||||
("az", "Azərbaycan"),
|
||||
("bg", "Български"),
|
||||
("be", "Беларуская"),
|
||||
("bn", "বাংলা"),
|
||||
("br", "Brezhoneg"),
|
||||
("bs", "Bosanski"),
|
||||
("ca", "Català"),
|
||||
("ckb", "کوردیی ناوەندی"), # Central Kurdish (Sorani)
|
||||
("cs", "Čeština"),
|
||||
("cy", "Cymraeg"),
|
||||
("da", "Dansk"),
|
||||
("de", "Deutsch"),
|
||||
("dsb", "Dolnoserbšćina"),
|
||||
("el", "Ελληνικά"),
|
||||
("en", "English"),
|
||||
("en-au", "English (Australia)"),
|
||||
("en-gb", "English (UK)"),
|
||||
("eo", "Esperanto"),
|
||||
("es", "Español"),
|
||||
("es-ar", "Español (Argentina)"),
|
||||
("es-co", "Español (Colombia)"),
|
||||
("es-mx", "Español (México)"),
|
||||
("es-ni", "Español (Nicaragua)"),
|
||||
("es-ve", "Español (Venezuela)"),
|
||||
("et", "Eesti"),
|
||||
("eu", "Euskara"),
|
||||
("fa", "فارسی"),
|
||||
("fi", "Suomi"),
|
||||
("fr", "Français"),
|
||||
("fy", "Frysk"),
|
||||
("ga", "Gaeilge"),
|
||||
("gd", "Gàidhlig"),
|
||||
("gl", "Galego"),
|
||||
("he", "עברית"),
|
||||
("hi", "हिन्दी"),
|
||||
("hr", "Hrvatski"),
|
||||
("hsb", "Hornjoserbšćina"),
|
||||
("hu", "Magyar"),
|
||||
("hy", "Հայերեն"),
|
||||
("ia", "Interlingua"),
|
||||
("id", "Bahasa Indonesia"),
|
||||
("ig", "Igbo"),
|
||||
("io", "Ido"),
|
||||
("is", "Íslenska"),
|
||||
("it", "Italiano"),
|
||||
("ja", "日本語"),
|
||||
("ka", "ქართული"),
|
||||
("kab", "Taqbaylit"),
|
||||
("kk", "Қазақша"),
|
||||
("km", "ខ្មែរ"),
|
||||
("kn", "ಕನ್ನಡ"),
|
||||
("ko", "한국어"),
|
||||
("ky", "Кыргызча"),
|
||||
("lb", "Lëtzebuergesch"),
|
||||
("lt", "Lietuvių"),
|
||||
("lv", "Latviešu"),
|
||||
("mk", "Македонски"),
|
||||
("ml", "മലയാളം"),
|
||||
("mn", "Монгол"),
|
||||
("mr", "मराठी"),
|
||||
("ms", "Bahasa Melayu"),
|
||||
("my", "မြန်မာဘာသာ"),
|
||||
("nb", "Norsk (Bokmål)"),
|
||||
("ne", "नेपाली"),
|
||||
("nl", "Nederlands"),
|
||||
("nn", "Norsk (Nynorsk)"),
|
||||
("os", "Ирон"), # Ossetic
|
||||
("pa", "ਪੰਜਾਬੀ"),
|
||||
("pl", "Polski"),
|
||||
("pt", "Português"),
|
||||
("pt-br", "Português (Brasil)"),
|
||||
("ro", "Română"),
|
||||
("ru", "Русский"),
|
||||
("sk", "Slovenčina"),
|
||||
("sl", "Slovenščina"),
|
||||
("sq", "Shqip"),
|
||||
("sr", "Српски"),
|
||||
("sr-latn", "Srpski (Latinica)"),
|
||||
("sv", "Svenska"),
|
||||
("sw", "Kiswahili"),
|
||||
("ta", "தமிழ்"),
|
||||
("te", "తెలుగు"),
|
||||
("tg", "Тоҷикӣ"),
|
||||
("th", "ไทย"),
|
||||
("tk", "Türkmençe"),
|
||||
("tr", "Türkçe"),
|
||||
("tt", "Татарча"),
|
||||
("udm", "Удмурт"),
|
||||
("ug", "ئۇيغۇرچە"),
|
||||
("uk", "Українська"),
|
||||
("ur", "اردو"),
|
||||
("uz", "Oʻzbekcha"),
|
||||
("vi", "Tiếng Việt"),
|
||||
("zh-hans", "简体中文"),
|
||||
("zh-hant", "繁體中文"),
|
||||
)
|
||||
|
||||
TIME_ZONE = os.getenv("TZ", "UTC")
|
||||
@@ -261,7 +356,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 +492,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", "false").lower() == "true"
|
||||
|
||||
10
app/apps/api/permissions.py
Normal file
10
app/apps/api/permissions.py
Normal 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
|
||||
15
app/apps/common/decorators/demo.py
Normal file
15
app/apps/common/decorators/demo.py
Normal 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
|
||||
78
app/apps/common/decorators/user.py
Normal file
78
app/apps/common/decorators/user.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from functools import wraps
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse, NoReverseMatch
|
||||
|
||||
|
||||
def is_superuser(view):
|
||||
@wraps(view)
|
||||
def _view(request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
raise PermissionDenied
|
||||
|
||||
return view(request, *args, **kwargs)
|
||||
|
||||
return _view
|
||||
|
||||
|
||||
def htmx_login_required(function=None, login_url=None):
|
||||
"""
|
||||
Decorator that checks if the user is logged in.
|
||||
|
||||
Allows overriding the default login URL.
|
||||
|
||||
If the user is not logged in:
|
||||
- If "hx-request" is present in the request header, it returns a 200 response
|
||||
with a "HX-Redirect" header containing the determined login URL (including the "next" parameter).
|
||||
- If "hx-request" is not present, it redirects to the determined login page normally.
|
||||
|
||||
Args:
|
||||
function: The view function to decorate.
|
||||
login_url: Optional. The URL or URL name to redirect to for login.
|
||||
Defaults to settings.LOGIN_URL.
|
||||
"""
|
||||
|
||||
def decorator(view_func):
|
||||
# Simplified @wraps usage - it handles necessary attribute assignments by default
|
||||
@wraps(view_func)
|
||||
def wrapped_view(request, *args, **kwargs):
|
||||
if request.user.is_authenticated:
|
||||
return view_func(request, *args, **kwargs)
|
||||
else:
|
||||
# Determine the login URL
|
||||
resolved_login_url = login_url
|
||||
if not resolved_login_url:
|
||||
resolved_login_url = settings.LOGIN_URL
|
||||
|
||||
# Try to reverse the URL name if it's not a path
|
||||
try:
|
||||
# Check if it looks like a URL path already
|
||||
if "/" not in resolved_login_url and "." not in resolved_login_url:
|
||||
login_url_path = reverse(resolved_login_url)
|
||||
else:
|
||||
login_url_path = resolved_login_url
|
||||
except NoReverseMatch:
|
||||
# If reverse fails, assume it's already a URL path
|
||||
login_url_path = resolved_login_url
|
||||
|
||||
# Construct the full redirect path with 'next' parameter
|
||||
# Ensure request.path is URL-encoded if needed, though Django usually handles this
|
||||
redirect_path = f"{login_url_path}?next={request.get_full_path()}" # Use get_full_path() to include query params
|
||||
|
||||
if request.headers.get("hx-request"):
|
||||
# For HTMX requests, return a 200 with the HX-Redirect header.
|
||||
response = HttpResponse()
|
||||
response["HX-Redirect"] = login_url_path
|
||||
return response
|
||||
else:
|
||||
# For regular requests, redirect to the login page.
|
||||
return redirect(redirect_path)
|
||||
|
||||
return wrapped_view
|
||||
|
||||
if function:
|
||||
return decorator(function)
|
||||
return decorator
|
||||
@@ -20,7 +20,15 @@ class MonthYearModelField(models.DateField):
|
||||
# Set the day to 1
|
||||
return date.replace(day=1).date()
|
||||
except ValueError:
|
||||
raise ValidationError(_("Invalid date format. Use YYYY-MM."))
|
||||
try:
|
||||
# Also accept YYYY-MM-DD format (for loaddata)
|
||||
return (
|
||||
datetime.datetime.strptime(value, "%Y-%m-%d").replace(day=1).date()
|
||||
)
|
||||
except ValueError:
|
||||
raise ValidationError(
|
||||
_("Invalid date format. Use YYYY-MM or YYYY-MM-DD.")
|
||||
)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
kwargs["widget"] = MonthYearWidget
|
||||
|
||||
0
app/apps/common/management/__init__.py
Normal file
0
app/apps/common/management/__init__.py
Normal file
0
app/apps/common/management/commands/__init__.py
Normal file
0
app/apps/common/management/commands/__init__.py
Normal file
137
app/apps/common/management/commands/setup_users.py
Normal file
137
app/apps/common/management/commands/setup_users.py
Normal 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."))
|
||||
@@ -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,40 @@ async def remove_expired_sessions(timestamp=None):
|
||||
"Error while executing 'remove_expired_sessions' task",
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
|
||||
@app.periodic(cron="0 8 * * *")
|
||||
@app.task(name="reset_demo_data")
|
||||
def reset_demo_data(timestamp=None):
|
||||
"""
|
||||
Wipes the database and loads fresh demo data if DEMO mode is active.
|
||||
Runs daily at 8: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...")
|
||||
|
||||
management.call_command(
|
||||
"flush", "--noinput", database=DEFAULT_DB_ALIAS, verbosity=1
|
||||
)
|
||||
logger.info("Database flushed successfully.")
|
||||
|
||||
# 2. Load data from the fixture
|
||||
# TO-DO: Roll dates over based on today's date
|
||||
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
|
||||
|
||||
@@ -15,10 +15,11 @@ from cachalot.api import invalidate
|
||||
|
||||
from apps.common.decorators.htmx import only_htmx
|
||||
from apps.transactions.models import Transaction
|
||||
from apps.common.decorators.user import htmx_login_required
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@htmx_login_required
|
||||
@require_http_methods(["GET"])
|
||||
def toasts(request):
|
||||
return render(request, "common/fragments/toasts.html")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import decimal
|
||||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Sum, Avg, F
|
||||
from django.db.models import Sum
|
||||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_http_methods
|
||||
@@ -22,13 +20,13 @@ from apps.insights.utils.category_explorer import (
|
||||
get_category_sums_by_account,
|
||||
get_category_sums_by_currency,
|
||||
)
|
||||
from apps.insights.utils.category_overview import get_categories_totals
|
||||
from apps.insights.utils.sankey import (
|
||||
generate_sankey_data_by_account,
|
||||
generate_sankey_data_by_currency,
|
||||
)
|
||||
from apps.insights.utils.transactions import get_transactions
|
||||
from apps.transactions.models import TransactionCategory, Transaction
|
||||
from apps.insights.utils.category_overview import get_categories_totals
|
||||
from apps.transactions.utils.calculations import calculate_currency_totals
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -574,6 +574,7 @@ class InstallmentPlan(models.Model):
|
||||
installment_plan=self,
|
||||
installment_id=i,
|
||||
notes=self.notes if self.add_notes_to_transaction else "",
|
||||
owner=self.account.owner,
|
||||
)
|
||||
new_transaction.tags.set(self.tags.all())
|
||||
new_transaction.entities.set(self.entities.all())
|
||||
@@ -640,6 +641,7 @@ class InstallmentPlan(models.Model):
|
||||
installment_plan=self,
|
||||
installment_id=i,
|
||||
notes=self.notes if self.add_notes_to_transaction else "",
|
||||
owner=self.account.owner,
|
||||
)
|
||||
new_transaction.tags.set(self.tags.all())
|
||||
new_transaction.entities.set(self.entities.all())
|
||||
@@ -775,6 +777,7 @@ class RecurringTransaction(models.Model):
|
||||
is_paid=False,
|
||||
recurring_transaction=self,
|
||||
notes=self.notes if self.add_notes_to_transaction else "",
|
||||
owner=self.account.owner,
|
||||
)
|
||||
if self.tags.exists():
|
||||
created_transaction.tags.set(self.tags.all())
|
||||
@@ -797,12 +800,16 @@ class RecurringTransaction(models.Model):
|
||||
@classmethod
|
||||
def generate_upcoming_transactions(cls):
|
||||
today = timezone.now().date()
|
||||
recurring_transactions = cls.objects.filter(
|
||||
recurring_transactions = cls.all_objects.filter(
|
||||
Q(models.Q(end_date__isnull=True) | Q(end_date__gte=today))
|
||||
& Q(is_paused=False)
|
||||
)
|
||||
|
||||
for recurring_transaction in recurring_transactions:
|
||||
logger.info(
|
||||
f"Processing recurring transaction: {recurring_transaction.description}..."
|
||||
)
|
||||
|
||||
if recurring_transaction.last_generated_date:
|
||||
start_date = recurring_transaction.get_next_date(
|
||||
recurring_transaction.last_generated_date
|
||||
@@ -821,7 +828,10 @@ class RecurringTransaction(models.Model):
|
||||
today + (recurring_transaction.get_recurrence_delta() * 6),
|
||||
)
|
||||
|
||||
logger.info(f"End date: {end_date}")
|
||||
|
||||
while current_date <= end_date:
|
||||
logger.info(f"Creating transaction for date: {current_date}")
|
||||
recurring_transaction.create_transaction(current_date, reference_date)
|
||||
current_date = recurring_transaction.get_next_date(current_date)
|
||||
reference_date = recurring_transaction.get_next_date(reference_date)
|
||||
|
||||
@@ -2,16 +2,20 @@ from crispy_forms.bootstrap import (
|
||||
FormActions,
|
||||
)
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout, Submit
|
||||
from crispy_forms.layout import Layout, Submit, Row, Column, Field, Div
|
||||
from django import forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.forms import (
|
||||
UsernameField,
|
||||
AuthenticationForm,
|
||||
UserCreationForm,
|
||||
)
|
||||
from django.db import transaction
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from apps.common.widgets.crispy.submit import NoClassSubmit
|
||||
from apps.users.models import UserSettings
|
||||
from apps.common.middleware.thread_local import get_current_user
|
||||
|
||||
|
||||
class LoginForm(AuthenticationForm):
|
||||
@@ -132,3 +136,269 @@ class UserSettingsForm(forms.ModelForm):
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
self.fields["language"].help_text = _(
|
||||
"This changes the language (if available) and how numbers and dates are displayed\n"
|
||||
"Consider helping translate WYGIWYH to your language at %(translation_link)s"
|
||||
) % {
|
||||
"translation_link": '<a href="https://translations.herculino.com" target="_blank">translations.herculino.com</a>'
|
||||
}
|
||||
|
||||
|
||||
class UserUpdateForm(forms.ModelForm):
|
||||
new_password1 = forms.CharField(
|
||||
label=_("New Password"),
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
||||
required=False,
|
||||
help_text=_("Leave blank to keep the current password."),
|
||||
)
|
||||
new_password2 = forms.CharField(
|
||||
label=_("Confirm New Password"),
|
||||
widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = get_user_model()
|
||||
# Add the administrative fields
|
||||
fields = ["first_name", "last_name", "email", "is_active", "is_superuser"]
|
||||
# Help texts can be defined here or directly in the layout/field definition
|
||||
help_texts = {
|
||||
"is_active": _(
|
||||
"Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
),
|
||||
"is_superuser": _(
|
||||
"Designates that this user has all permissions without explicitly assigning them."
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.instance = kwargs.get("instance") # Store instance for validation/checks
|
||||
self.requesting_user = get_current_user()
|
||||
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_tag = False
|
||||
self.helper.form_method = "post"
|
||||
|
||||
# Define the layout using Crispy Forms, including the new fields
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column("first_name", css_class="form-group col-md-6"),
|
||||
Column("last_name", css_class="form-group col-md-6"),
|
||||
css_class="row",
|
||||
),
|
||||
Field("email"),
|
||||
# Group password fields (optional visual grouping)
|
||||
Div(
|
||||
Field("new_password1"),
|
||||
Field("new_password2"),
|
||||
css_class="border p-3 rounded mb-3",
|
||||
),
|
||||
# Group administrative status fields
|
||||
Div(
|
||||
Field("is_active"),
|
||||
Field("is_superuser"),
|
||||
css_class="border p-3 rounded mb-3 text-bg-secondary", # Example visual separation
|
||||
),
|
||||
)
|
||||
|
||||
if self.instance and self.instance.pk:
|
||||
self.helper.layout.append(
|
||||
FormActions(
|
||||
NoClassSubmit(
|
||||
"submit", _("Update"), css_class="btn btn-outline-primary w-100"
|
||||
),
|
||||
),
|
||||
)
|
||||
else:
|
||||
self.helper.layout.append(
|
||||
FormActions(
|
||||
NoClassSubmit(
|
||||
"submit", _("Add"), css_class="btn btn-outline-primary w-100"
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if (
|
||||
self.requesting_user == self.instance
|
||||
or not self.requesting_user.is_superuser
|
||||
):
|
||||
self.fields["is_superuser"].disabled = True
|
||||
self.fields["is_active"].disabled = True
|
||||
|
||||
# Keep existing clean methods
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data.get("email")
|
||||
# Use case-insensitive comparison for email uniqueness check
|
||||
if (
|
||||
self.instance
|
||||
and get_user_model()
|
||||
.objects.filter(email__iexact=email)
|
||||
.exclude(pk=self.instance.pk)
|
||||
.exists()
|
||||
):
|
||||
raise forms.ValidationError(
|
||||
_("This email address is already in use by another account.")
|
||||
)
|
||||
return email
|
||||
|
||||
def clean_new_password2(self):
|
||||
new_password1 = self.cleaned_data.get("new_password1")
|
||||
new_password2 = self.cleaned_data.get("new_password2")
|
||||
if new_password1 and new_password1 != new_password2:
|
||||
raise forms.ValidationError(_("The two password fields didn't match."))
|
||||
if new_password1 and not new_password2:
|
||||
raise forms.ValidationError(_("Please confirm your new password."))
|
||||
if new_password2 and not new_password1:
|
||||
raise forms.ValidationError(_("Please enter the new password first."))
|
||||
return new_password2
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
is_active_val = cleaned_data.get("is_active")
|
||||
is_superuser_val = cleaned_data.get("is_superuser")
|
||||
|
||||
# --- Crucial Security Check Example ---
|
||||
# Prevent the requesting user from deactivating or removing superuser status
|
||||
# from their *own* account via this form.
|
||||
if (
|
||||
self.requesting_user
|
||||
and self.instance
|
||||
and self.requesting_user.pk == self.instance.pk
|
||||
):
|
||||
# Check if 'is_active' field exists and user is trying to set it to False
|
||||
if "is_active" in self.fields and is_active_val is False:
|
||||
self.add_error(
|
||||
"is_active",
|
||||
_("You cannot deactivate your own account using this form."),
|
||||
)
|
||||
|
||||
# Check if 'is_superuser' field exists, the user *is* currently a superuser,
|
||||
# and they are trying to set it to False
|
||||
if (
|
||||
"is_superuser" in self.fields
|
||||
and self.instance.is_superuser
|
||||
and is_superuser_val is False
|
||||
):
|
||||
if get_user_model().objects.filter(is_superuser=True).count() <= 1:
|
||||
self.add_error(
|
||||
"is_superuser",
|
||||
_("Cannot remove status from the last superuser."),
|
||||
)
|
||||
else:
|
||||
self.add_error(
|
||||
"is_superuser",
|
||||
_(
|
||||
"You cannot remove your own superuser status using this form."
|
||||
),
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
# Save method remains the same, ModelForm handles boolean fields correctly
|
||||
def save(self, commit=True):
|
||||
user = super().save(commit=False)
|
||||
new_password = self.cleaned_data.get("new_password1")
|
||||
if new_password:
|
||||
user.set_password(new_password)
|
||||
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
class UserAddForm(UserCreationForm):
|
||||
"""
|
||||
A form for administrators to create new users.
|
||||
Includes fields for first name, last name, email, active status,
|
||||
and superuser status. Uses email as the username field.
|
||||
Inherits password handling from UserCreationForm.
|
||||
"""
|
||||
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = get_user_model()
|
||||
# Specify the fields to include. UserCreationForm automatically handles
|
||||
# 'password1' and 'password2'. We replace 'username' with 'email'.
|
||||
fields = ("email", "first_name", "last_name", "is_active", "is_superuser")
|
||||
field_classes = {
|
||||
"email": forms.EmailField
|
||||
} # Ensure email field uses EmailField validation
|
||||
help_texts = {
|
||||
"is_active": _(
|
||||
"Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
),
|
||||
"is_superuser": _(
|
||||
"Designates that this user has all permissions without explicitly assigning them."
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Set is_active to True by default for new users, can be overridden by admin
|
||||
self.fields["is_active"].initial = True
|
||||
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_tag = False
|
||||
self.helper.form_method = "post"
|
||||
|
||||
# Define the layout, including password fields from UserCreationForm
|
||||
self.helper.layout = Layout(
|
||||
Field("email"),
|
||||
Row(
|
||||
Column("first_name", css_class="form-group col-md-6"),
|
||||
Column("last_name", css_class="form-group col-md-6"),
|
||||
css_class="row",
|
||||
),
|
||||
# UserCreationForm provides 'password1' and 'password2' fields
|
||||
Div(
|
||||
Field("password1", autocomplete="new-password"),
|
||||
Field("password2", autocomplete="new-password"),
|
||||
css_class="border p-3 rounded mb-3",
|
||||
),
|
||||
# Administrative status fields
|
||||
Div(
|
||||
Field("is_active"),
|
||||
Field("is_superuser"),
|
||||
css_class="border p-3 rounded mb-3 text-bg-secondary",
|
||||
),
|
||||
)
|
||||
|
||||
if self.instance and self.instance.pk:
|
||||
self.helper.layout.append(
|
||||
FormActions(
|
||||
NoClassSubmit(
|
||||
"submit", _("Update"), css_class="btn btn-outline-primary w-100"
|
||||
),
|
||||
),
|
||||
)
|
||||
else:
|
||||
self.helper.layout.append(
|
||||
FormActions(
|
||||
NoClassSubmit(
|
||||
"submit", _("Add"), css_class="btn btn-outline-primary w-100"
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
def clean_email(self):
|
||||
"""Ensure email uniqueness (case-insensitive)."""
|
||||
email = self.cleaned_data.get("email")
|
||||
if email and get_user_model().objects.filter(email__iexact=email).exists():
|
||||
raise forms.ValidationError(
|
||||
_("A user with this email address already exists.")
|
||||
)
|
||||
return email
|
||||
|
||||
@transaction.atomic # Ensure user creation is atomic
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
Save the user instance. UserCreationForm's save handles password hashing.
|
||||
Our Meta class ensures other fields are included.
|
||||
"""
|
||||
user = super().save(commit=False)
|
||||
|
||||
if commit:
|
||||
user.save()
|
||||
return user
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.8 on 2025-04-13 03:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0019_alter_usersettings_language'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='usersettings',
|
||||
name='language',
|
||||
field=models.CharField(choices=[('auto', 'Auto'), ('af', 'Afrikaans'), ('ar', 'العربية'), ('ar-dz', 'العربية (الجزائر)'), ('ast', 'Asturianu'), ('az', 'Azərbaycan'), ('bg', 'Български'), ('be', 'Беларуская'), ('bn', 'বাংলা'), ('br', 'Brezhoneg'), ('bs', 'Bosanski'), ('ca', 'Català'), ('ckb', 'کوردیی ناوەندی'), ('cs', 'Čeština'), ('cy', 'Cymraeg'), ('da', 'Dansk'), ('de', 'Deutsch'), ('dsb', 'Dolnoserbšćina'), ('el', 'Ελληνικά'), ('en', 'English'), ('en-au', 'English (Australia)'), ('en-gb', 'English (UK)'), ('eo', 'Esperanto'), ('es', 'Español'), ('es-ar', 'Español (Argentina)'), ('es-co', 'Español (Colombia)'), ('es-mx', 'Español (México)'), ('es-ni', 'Español (Nicaragua)'), ('es-ve', 'Español (Venezuela)'), ('et', 'Eesti'), ('eu', 'Euskara'), ('fa', 'فارسی'), ('fi', 'Suomi'), ('fr', 'Français'), ('fy', 'Frysk'), ('ga', 'Gaeilge'), ('gd', 'Gàidhlig'), ('gl', 'Galego'), ('he', 'עברית'), ('hi', 'हिन्दी'), ('hr', 'Hrvatski'), ('hsb', 'Hornjoserbšćina'), ('hu', 'Magyar'), ('hy', 'Հայերեն'), ('ia', 'Interlingua'), ('id', 'Bahasa Indonesia'), ('ig', 'Igbo'), ('io', 'Ido'), ('is', 'Íslenska'), ('it', 'Italiano'), ('ja', '日本語'), ('ka', 'ქართული'), ('kab', 'Taqbaylit'), ('kk', 'Қазақша'), ('km', 'ខ្មែរ'), ('kn', 'ಕನ್ನಡ'), ('ko', '한국어'), ('ky', 'Кыргызча'), ('lb', 'Lëtzebuergesch'), ('lt', 'Lietuvių'), ('lv', 'Latviešu'), ('mk', 'Македонски'), ('ml', 'മലയാളം'), ('mn', 'Монгол'), ('mr', 'मराठी'), ('ms', 'Bahasa Melayu'), ('my', 'မြန်မာဘာသာ'), ('nb', 'Norsk (Bokmål)'), ('ne', 'नेपाली'), ('nl', 'Nederlands'), ('nn', 'Norsk (Nynorsk)'), ('os', 'Ирон'), ('pa', 'ਪੰਜਾਬੀ'), ('pl', 'Polski'), ('pt', 'Português'), ('pt-br', 'Português (Brasil)'), ('ro', 'Română'), ('ru', 'Русский'), ('sk', 'Slovenčina'), ('sl', 'Slovenščina'), ('sq', 'Shqip'), ('sr', 'Српски'), ('sr-latn', 'Srpski (Latinica)'), ('sv', 'Svenska'), ('sw', 'Kiswahili'), ('ta', 'தமிழ்'), ('te', 'తెలుగు'), ('tg', 'Тоҷикӣ'), ('th', 'ไทย'), ('tk', 'Türkmençe'), ('tr', 'Türkçe'), ('tt', 'Татарча'), ('udm', 'Удмурт'), ('ug', 'ئۇيغۇرچە'), ('uk', 'Українська'), ('ur', 'اردو'), ('uz', 'Oʻzbekcha'), ('vi', 'Tiếng Việt'), ('zh-hans', '简体中文'), ('zh-hant', '繁體中文')], default='auto', max_length=10, verbose_name='Language'),
|
||||
),
|
||||
]
|
||||
@@ -22,4 +22,24 @@ urlpatterns = [
|
||||
views.update_settings,
|
||||
name="user_settings",
|
||||
),
|
||||
path(
|
||||
"users/",
|
||||
views.users_index,
|
||||
name="users_index",
|
||||
),
|
||||
path(
|
||||
"users/list/",
|
||||
views.users_list,
|
||||
name="users_list",
|
||||
),
|
||||
path(
|
||||
"user/add/",
|
||||
views.user_add,
|
||||
name="user_add",
|
||||
),
|
||||
path(
|
||||
"user/<int:pk>/edit/",
|
||||
views.user_edit,
|
||||
name="user_edit",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import logout
|
||||
from django.contrib.auth import logout, get_user_model
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.views import (
|
||||
LoginView,
|
||||
)
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.shortcuts import redirect, render, get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from apps.common.decorators.htmx import only_htmx
|
||||
from apps.common.decorators.user import is_superuser, htmx_login_required
|
||||
from apps.users.forms import (
|
||||
LoginForm,
|
||||
UserSettingsForm,
|
||||
UserUpdateForm,
|
||||
UserAddForm,
|
||||
)
|
||||
from apps.common.decorators.htmx import only_htmx
|
||||
from apps.users.models import UserSettings
|
||||
|
||||
|
||||
@@ -22,7 +27,7 @@ def logout_view(request):
|
||||
return redirect(reverse("login"))
|
||||
|
||||
|
||||
@login_required
|
||||
@htmx_login_required
|
||||
def index(request):
|
||||
if request.user.settings.start_page == UserSettings.StartPage.MONTHLY:
|
||||
return redirect(reverse("monthly_index"))
|
||||
@@ -49,7 +54,7 @@ class UserLoginView(LoginView):
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@htmx_login_required
|
||||
def toggle_amount_visibility(request):
|
||||
user_settings, created = UserSettings.objects.get_or_create(user=request.user)
|
||||
current_hide_amounts = user_settings.hide_amounts
|
||||
@@ -70,7 +75,7 @@ def toggle_amount_visibility(request):
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@htmx_login_required
|
||||
def toggle_sound_playing(request):
|
||||
user_settings, created = UserSettings.objects.get_or_create(user=request.user)
|
||||
current_mute_sounds = user_settings.mute_sounds
|
||||
@@ -91,7 +96,7 @@ def toggle_sound_playing(request):
|
||||
|
||||
|
||||
@only_htmx
|
||||
@login_required
|
||||
@htmx_login_required
|
||||
def update_settings(request):
|
||||
user_settings = request.user.settings
|
||||
|
||||
@@ -108,3 +113,85 @@ def update_settings(request):
|
||||
form = UserSettingsForm(instance=user_settings)
|
||||
|
||||
return render(request, "users/fragments/user_settings.html", {"form": form})
|
||||
|
||||
|
||||
@htmx_login_required
|
||||
@is_superuser
|
||||
@require_http_methods(["GET"])
|
||||
def users_index(request):
|
||||
return render(
|
||||
request,
|
||||
"users/pages/index.html",
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@htmx_login_required
|
||||
@is_superuser
|
||||
@require_http_methods(["GET"])
|
||||
def users_list(request):
|
||||
users = get_user_model().objects.all().order_by("id")
|
||||
|
||||
return render(
|
||||
request,
|
||||
"users/fragments/list.html",
|
||||
{"users": users},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@htmx_login_required
|
||||
@is_superuser
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def user_add(request):
|
||||
if request.method == "POST":
|
||||
form = UserAddForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("Item added successfully"))
|
||||
|
||||
return HttpResponse(
|
||||
status=204,
|
||||
headers={
|
||||
"HX-Trigger": "updated, hide_offcanvas",
|
||||
},
|
||||
)
|
||||
else:
|
||||
form = UserAddForm()
|
||||
|
||||
return render(
|
||||
request,
|
||||
"users/fragments/add.html",
|
||||
{"form": form},
|
||||
)
|
||||
|
||||
|
||||
@only_htmx
|
||||
@htmx_login_required
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def user_edit(request, pk):
|
||||
user = get_object_or_404(get_user_model(), id=pk)
|
||||
|
||||
if not request.user.is_superuser and user != request.user:
|
||||
raise PermissionDenied
|
||||
|
||||
if request.method == "POST":
|
||||
form = UserUpdateForm(request.POST, instance=user)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("Item updated successfully"))
|
||||
|
||||
return HttpResponse(
|
||||
status=204,
|
||||
headers={
|
||||
"HX-Trigger": "updated, hide_offcanvas",
|
||||
},
|
||||
)
|
||||
else:
|
||||
form = UserUpdateForm(instance=user)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"users/fragments/edit.html",
|
||||
{"form": form, "user": user},
|
||||
)
|
||||
|
||||
1022
app/fixtures/demo_data.json
Normal file
1022
app/fixtures/demo_data.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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-04-13 22:01+0000\n"
|
||||
"PO-Revision-Date: 2025-04-13 02:40+0000\n"
|
||||
"Last-Translator: Prefill add-on <noreply-addon-prefill@weblate.org>\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
|
||||
@@ -31,6 +31,7 @@ msgstr "Gruppenname"
|
||||
#: apps/transactions/forms.py:269 apps/transactions/forms.py:629
|
||||
#: apps/transactions/forms.py:672 apps/transactions/forms.py:704
|
||||
#: apps/transactions/forms.py:739 apps/transactions/forms.py:891
|
||||
#: apps/users/forms.py:210 apps/users/forms.py:372
|
||||
msgid "Update"
|
||||
msgstr "Aktualisierung"
|
||||
|
||||
@@ -42,8 +43,8 @@ msgstr "Aktualisierung"
|
||||
#: apps/transactions/forms.py:187 apps/transactions/forms.py:211
|
||||
#: apps/transactions/forms.py:637 apps/transactions/forms.py:680
|
||||
#: apps/transactions/forms.py:712 apps/transactions/forms.py:747
|
||||
#: apps/transactions/forms.py:899
|
||||
#: templates/account_groups/fragments/list.html:9
|
||||
#: apps/transactions/forms.py:899 apps/users/forms.py:218
|
||||
#: apps/users/forms.py:380 templates/account_groups/fragments/list.html:9
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/categories/fragments/list.html:9
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
@@ -58,6 +59,7 @@ msgstr "Aktualisierung"
|
||||
#: templates/mini_tools/unit_price_calculator.html:162
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/rules/fragments/list.html:9 templates/tags/fragments/list.html:9
|
||||
#: templates/users/fragments/list.html:10
|
||||
msgid "Add"
|
||||
msgstr "Hinzufügen"
|
||||
|
||||
@@ -75,8 +77,9 @@ msgstr "Neuer Saldo"
|
||||
#: apps/transactions/forms.py:40 apps/transactions/forms.py:303
|
||||
#: apps/transactions/forms.py:310 apps/transactions/forms.py:510
|
||||
#: apps/transactions/forms.py:771 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:686
|
||||
#: templates/insights/fragments/category_overview/index.html:9
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:688
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:215
|
||||
msgid "Category"
|
||||
msgstr "Kategorie"
|
||||
|
||||
@@ -87,7 +90,7 @@ msgstr "Kategorie"
|
||||
#: apps/transactions/forms.py:48 apps/transactions/forms.py:319
|
||||
#: apps/transactions/forms.py:327 apps/transactions/forms.py:503
|
||||
#: apps/transactions/forms.py:764 apps/transactions/models.py:311
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:690
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:692
|
||||
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
|
||||
#: templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
@@ -108,6 +111,7 @@ msgstr "Tags"
|
||||
#: templates/recurring_transactions/fragments/table.html:18
|
||||
#: templates/rules/fragments/list.html:26
|
||||
#: templates/tags/fragments/table.html:16
|
||||
#: templates/users/fragments/list.html:29
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -162,7 +166,7 @@ msgstr ""
|
||||
#: apps/rules/models.py:30 apps/rules/models.py:242
|
||||
#: apps/transactions/forms.py:60 apps/transactions/forms.py:495
|
||||
#: apps/transactions/forms.py:756 apps/transactions/models.py:278
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:668
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:670
|
||||
msgid "Account"
|
||||
msgstr "Konto"
|
||||
|
||||
@@ -190,7 +194,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 +209,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 +220,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"
|
||||
@@ -286,7 +290,13 @@ msgstr "Fehler bei der Erstellung einer neuen Instanz"
|
||||
msgid "Ungrouped"
|
||||
msgstr "Ohne Gruppierung"
|
||||
|
||||
#: apps/common/fields/month_year.py:23 apps/common/fields/month_year.py:51
|
||||
#: apps/common/fields/month_year.py:30
|
||||
#, fuzzy
|
||||
#| msgid "Invalid date format. Use YYYY-MM."
|
||||
msgid "Invalid date format. Use YYYY-MM or YYYY-MM-DD."
|
||||
msgstr "Ungültiges Datumsformat. Nutze JJJJ-MM."
|
||||
|
||||
#: apps/common/fields/month_year.py:59
|
||||
msgid "Invalid date format. Use YYYY-MM."
|
||||
msgstr "Ungültiges Datumsformat. Nutze JJJJ-MM."
|
||||
|
||||
@@ -322,7 +332,7 @@ msgstr ""
|
||||
"Privat: Nur für den Besitzer und geteilte Nutzer sichtbar.<br/>Öffentlich: "
|
||||
"Sichtbar für alle Nutzer. Nur bearbeitbar durch Besitzer."
|
||||
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:131
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:135
|
||||
msgid "Save"
|
||||
msgstr "Speichern"
|
||||
|
||||
@@ -413,7 +423,7 @@ msgstr "Fehler"
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: apps/common/views.py:110
|
||||
#: apps/common/views.py:111
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr "Cache erfolgreich geleert"
|
||||
|
||||
@@ -538,7 +548,7 @@ msgstr "Diensttyp"
|
||||
#: templates/categories/fragments/list.html:21
|
||||
#: templates/entities/fragments/list.html:21
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21 templates/users/fragments/list.html:28
|
||||
msgid "Active"
|
||||
msgstr "Aktiv"
|
||||
|
||||
@@ -642,19 +652,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"
|
||||
|
||||
@@ -713,7 +723,7 @@ msgstr "Startwährung"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:173
|
||||
#: apps/rules/forms.py:188 apps/rules/models.py:37 apps/rules/models.py:270
|
||||
#: apps/transactions/forms.py:347 apps/transactions/models.py:301
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:696
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:698
|
||||
msgid "Notes"
|
||||
msgstr "Notizen"
|
||||
|
||||
@@ -770,6 +780,8 @@ msgid "Entry deleted successfully"
|
||||
msgstr "Eintrag erfolgreich gelöscht"
|
||||
|
||||
#: apps/export_app/forms.py:14 apps/export_app/forms.py:131
|
||||
#: templates/includes/navbar.html:147 templates/users/fragments/list.html:6
|
||||
#: templates/users/pages/index.html:4
|
||||
msgid "Users"
|
||||
msgstr "Nutzer"
|
||||
|
||||
@@ -794,13 +806,13 @@ msgstr "Kategorien"
|
||||
#: apps/transactions/forms.py:56 apps/transactions/forms.py:518
|
||||
#: apps/transactions/forms.py:779 apps/transactions/models.py:261
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:493
|
||||
#: apps/transactions/models.py:693 templates/entities/fragments/list.html:5
|
||||
#: apps/transactions/models.py:695 templates/entities/fragments/list.html:5
|
||||
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
|
||||
msgid "Entities"
|
||||
msgstr "Entitäten"
|
||||
|
||||
#: apps/export_app/forms.py:56 apps/export_app/forms.py:140
|
||||
#: apps/transactions/models.py:730 templates/includes/navbar.html:74
|
||||
#: apps/transactions/models.py:732 templates/includes/navbar.html:74
|
||||
#: templates/recurring_transactions/fragments/list.html:5
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
@@ -871,15 +883,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,29 +952,31 @@ 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"
|
||||
|
||||
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167
|
||||
#: templates/insights/fragments/category_overview/index.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:19
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/insights/fragments/category_overview/index.html:116
|
||||
msgid "Uncategorized"
|
||||
msgstr "Unkategorisiert"
|
||||
|
||||
@@ -1045,7 +1059,7 @@ msgstr "Bediener"
|
||||
|
||||
#: apps/rules/forms.py:167 apps/rules/forms.py:180 apps/rules/models.py:31
|
||||
#: apps/rules/models.py:246 apps/transactions/models.py:285
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:674
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:676
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
@@ -1062,20 +1076,20 @@ msgstr "Bezahlt"
|
||||
#: apps/rules/models.py:258 apps/transactions/forms.py:68
|
||||
#: apps/transactions/forms.py:334 apps/transactions/forms.py:524
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:471
|
||||
#: apps/transactions/models.py:698
|
||||
#: apps/transactions/models.py:700
|
||||
msgid "Reference Date"
|
||||
msgstr "Referenzdatum"
|
||||
|
||||
#: apps/rules/forms.py:171 apps/rules/forms.py:184 apps/rules/models.py:35
|
||||
#: apps/rules/models.py:262 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:679 templates/insights/fragments/sankey.html:95
|
||||
#: apps/transactions/models.py:681 templates/insights/fragments/sankey.html:95
|
||||
msgid "Amount"
|
||||
msgstr "Betrag"
|
||||
|
||||
#: apps/rules/forms.py:172 apps/rules/forms.py:185 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:36 apps/rules/models.py:266
|
||||
#: apps/transactions/forms.py:338 apps/transactions/models.py:299
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:682
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:684
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
@@ -1173,47 +1187,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"
|
||||
@@ -1339,7 +1353,7 @@ msgstr "Entität"
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
#: templates/calendar_view/fragments/list.html:54
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
msgid "Income"
|
||||
msgstr "Einnahme"
|
||||
@@ -1350,7 +1364,7 @@ msgstr "Einnahme"
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
#: templates/calendar_view/fragments/list.html:58
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
msgid "Expense"
|
||||
msgstr "Ausgabe"
|
||||
|
||||
@@ -1358,7 +1372,7 @@ msgstr "Ausgabe"
|
||||
msgid "Installment Plan"
|
||||
msgstr "Ratenzahlungs-Plan"
|
||||
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:729
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:731
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Wiederkehrende Transaktion"
|
||||
|
||||
@@ -1416,11 +1430,11 @@ msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
"Die Zahl mit der bei der Zählung der Ratenzahlungen begonnen werden soll"
|
||||
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:702
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:704
|
||||
msgid "Start Date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:703
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:705
|
||||
msgid "End Date"
|
||||
msgstr "Enddatum"
|
||||
|
||||
@@ -1432,48 +1446,48 @@ msgstr "Regelmäßigkeit"
|
||||
msgid "Installment Amount"
|
||||
msgstr "Ratenzahlungs-Wert"
|
||||
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:719
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:721
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Beschreibung zu Transaktionen hinzufügen"
|
||||
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:722
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:724
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Notizen zu Transaktionen hinzufügen"
|
||||
|
||||
#: apps/transactions/models.py:661
|
||||
#: apps/transactions/models.py:663
|
||||
msgid "day(s)"
|
||||
msgstr "Tag(e)"
|
||||
|
||||
#: apps/transactions/models.py:662
|
||||
#: apps/transactions/models.py:664
|
||||
msgid "week(s)"
|
||||
msgstr "Woche(n)"
|
||||
|
||||
#: apps/transactions/models.py:663
|
||||
#: apps/transactions/models.py:665
|
||||
msgid "month(s)"
|
||||
msgstr "Monat(e)"
|
||||
|
||||
#: apps/transactions/models.py:664
|
||||
#: apps/transactions/models.py:666
|
||||
msgid "year(s)"
|
||||
msgstr "Jahr(e)"
|
||||
|
||||
#: apps/transactions/models.py:666
|
||||
#: apps/transactions/models.py:668
|
||||
#: templates/recurring_transactions/fragments/list.html:24
|
||||
msgid "Paused"
|
||||
msgstr "Pausiert"
|
||||
|
||||
#: apps/transactions/models.py:705
|
||||
#: apps/transactions/models.py:707
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Regelmäßigkeit"
|
||||
|
||||
#: apps/transactions/models.py:708
|
||||
#: apps/transactions/models.py:710
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Wiederholungsintervall"
|
||||
|
||||
#: apps/transactions/models.py:712
|
||||
#: apps/transactions/models.py:714
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Letztes generiertes Datum"
|
||||
|
||||
#: apps/transactions/models.py:715
|
||||
#: apps/transactions/models.py:717
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Letztes generiertes Referenzdatum"
|
||||
|
||||
@@ -1650,40 +1664,108 @@ msgstr "Berechtigungen"
|
||||
msgid "Important dates"
|
||||
msgstr "Wichtige Daten"
|
||||
|
||||
#: apps/users/forms.py:19 apps/users/models.py:13
|
||||
#: apps/users/forms.py:23 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:29 templates/users/login.html:20
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: apps/users/forms.py:33
|
||||
#: apps/users/forms.py:37
|
||||
msgid "Invalid e-mail or password"
|
||||
msgstr "Ungültige E-Mail oder Passwort"
|
||||
|
||||
#: apps/users/forms.py:34
|
||||
#: apps/users/forms.py:38
|
||||
msgid "This account is deactivated"
|
||||
msgstr "Dieses Konto ist deaktiviert"
|
||||
|
||||
#: apps/users/forms.py:50 apps/users/forms.py:63 apps/users/forms.py:85
|
||||
#: apps/users/forms.py:54 apps/users/forms.py:67 apps/users/forms.py:89
|
||||
#: templates/monthly_overview/pages/overview.html:153
|
||||
#: templates/transactions/pages/transactions.html:35
|
||||
msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#: apps/users/forms.py:91 apps/users/models.py:41
|
||||
#: apps/users/forms.py:95 apps/users/models.py:41
|
||||
msgid "Date Format"
|
||||
msgstr "Datumsformat"
|
||||
|
||||
#: apps/users/forms.py:96 apps/users/models.py:46
|
||||
#: apps/users/forms.py:100 apps/users/models.py:46
|
||||
msgid "Datetime Format"
|
||||
msgstr "Datums- und Zeitformat"
|
||||
|
||||
#: apps/users/forms.py:102 apps/users/models.py:49
|
||||
#: apps/users/forms.py:106 apps/users/models.py:49
|
||||
msgid "Number Format"
|
||||
msgstr "Zahlenformat"
|
||||
|
||||
#: apps/users/forms.py:141
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This changes the language (if available) and how numbers and dates are "
|
||||
"displayed\n"
|
||||
"Consider helping translate WYGIWYH to your language at %(translation_link)s"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:150
|
||||
#, fuzzy
|
||||
#| msgid "Password"
|
||||
msgid "New Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: apps/users/forms.py:153
|
||||
msgid "Leave blank to keep the current password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:156
|
||||
msgid "Confirm New Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:168 apps/users/forms.py:329
|
||||
msgid ""
|
||||
"Designates whether this user should be treated as active. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:171 apps/users/forms.py:332
|
||||
msgid ""
|
||||
"Designates that this user has all permissions without explicitly assigning "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:242
|
||||
msgid "This email address is already in use by another account."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:250
|
||||
msgid "The two password fields didn't match."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:252
|
||||
msgid "Please confirm your new password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:254
|
||||
msgid "Please enter the new password first."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:274
|
||||
msgid "You cannot deactivate your own account using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:287
|
||||
msgid "Cannot remove status from the last superuser."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:293
|
||||
msgid "You cannot remove your own superuser status using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:390
|
||||
#, fuzzy
|
||||
#| msgid "A value for this field already exists in the rule."
|
||||
msgid "A user with this email address already exists."
|
||||
msgstr "Ein Wert für dieses Feld existiert bereits in dieser Regel."
|
||||
|
||||
#: apps/users/models.py:27 templates/includes/navbar.html:28
|
||||
msgid "Yearly by currency"
|
||||
msgstr "Jährlich nach Währung"
|
||||
@@ -1724,26 +1806,38 @@ msgstr "Zeitzone"
|
||||
msgid "Start page"
|
||||
msgstr "Startseite"
|
||||
|
||||
#: apps/users/views.py:62
|
||||
#: apps/users/views.py:67
|
||||
msgid "Transaction amounts are now hidden"
|
||||
msgstr "Beträge sind nun versteckt"
|
||||
|
||||
#: apps/users/views.py:65
|
||||
#: apps/users/views.py:70
|
||||
msgid "Transaction amounts are now displayed"
|
||||
msgstr "Beträge werden angezeigt"
|
||||
|
||||
#: apps/users/views.py:83
|
||||
#: apps/users/views.py:88
|
||||
msgid "Sounds are now muted"
|
||||
msgstr "Sounds sind stummgeschaltet"
|
||||
|
||||
#: apps/users/views.py:86
|
||||
#: apps/users/views.py:91
|
||||
msgid "Sounds will now play"
|
||||
msgstr "Sounds werden wiedergegeben"
|
||||
|
||||
#: apps/users/views.py:102
|
||||
#: apps/users/views.py:107
|
||||
msgid "Your settings have been updated"
|
||||
msgstr "Deine Einstellungen wurden aktualisiert"
|
||||
|
||||
#: apps/users/views.py:151
|
||||
#, fuzzy
|
||||
#| msgid "Rule added successfully"
|
||||
msgid "Item added successfully"
|
||||
msgstr "Regel erfolgreich hinzugefügt"
|
||||
|
||||
#: apps/users/views.py:182
|
||||
#, fuzzy
|
||||
#| msgid "Rule updated successfully"
|
||||
msgid "Item updated successfully"
|
||||
msgstr "Regel erfolgreich aktualisiert"
|
||||
|
||||
#: templates/account_groups/fragments/add.html:5
|
||||
msgid "Add account group"
|
||||
msgstr "Kontogruppe hinzufügen"
|
||||
@@ -1766,6 +1860,7 @@ msgstr "Kontogruppe bearbeiten"
|
||||
#: templates/recurring_transactions/fragments/table.html:25
|
||||
#: templates/rules/fragments/list.html:33
|
||||
#: templates/tags/fragments/table.html:23
|
||||
#: templates/users/fragments/list.html:38
|
||||
msgid "Actions"
|
||||
msgstr "Aktionen"
|
||||
|
||||
@@ -1788,6 +1883,7 @@ msgstr "Aktionen"
|
||||
#: templates/rules/fragments/transaction_rule/view.html:47
|
||||
#: templates/rules/fragments/transaction_rule/view.html:80
|
||||
#: templates/tags/fragments/table.html:28
|
||||
#: templates/users/fragments/list.html:43
|
||||
msgid "Edit"
|
||||
msgstr "Bearbeiten"
|
||||
|
||||
@@ -2010,7 +2106,7 @@ msgid "Muted"
|
||||
msgstr "Ausgeblendet"
|
||||
|
||||
#: templates/categories/fragments/table.html:75
|
||||
#: templates/insights/fragments/category_overview/index.html:67
|
||||
#: templates/insights/fragments/category_overview/index.html:225
|
||||
msgid "No categories"
|
||||
msgstr "Keine Kategorien"
|
||||
|
||||
@@ -2511,35 +2607,57 @@ msgstr "Verwaltung"
|
||||
msgid "Automation"
|
||||
msgstr "Automatisierung"
|
||||
|
||||
#: templates/includes/navbar.html:150
|
||||
#: templates/includes/navbar.html:145
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:154
|
||||
msgid "Only use this if you know what you're doing"
|
||||
msgstr "Nur benutzen, wenn du weißt was du tust"
|
||||
|
||||
#: templates/includes/navbar.html:151
|
||||
#: templates/includes/navbar.html:155
|
||||
msgid "Django Admin"
|
||||
msgstr "Django Admin"
|
||||
|
||||
#: templates/includes/navbar.html:160
|
||||
#: templates/includes/navbar.html:165
|
||||
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:19
|
||||
#, fuzzy
|
||||
#| msgid "Edit import profile"
|
||||
msgid "Edit profile"
|
||||
msgstr "Import-Profil bearbeiten"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:46
|
||||
msgid "Clear cache"
|
||||
msgstr "Cache leeren"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:43
|
||||
#: templates/includes/navbar/user_menu.html:50
|
||||
msgid "Logout"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:5
|
||||
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:8
|
||||
#, fuzzy
|
||||
msgid "Access Denied"
|
||||
msgstr "Access Denied"
|
||||
|
||||
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"You do not have permission to perform this action or access this resource."
|
||||
msgstr ""
|
||||
"You do not have permission to perform this action or access this resource."
|
||||
|
||||
#: 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 "
|
||||
@@ -2574,18 +2692,25 @@ msgstr "Einnahmen/Ausgaben nach Konto"
|
||||
msgid "Income/Expense by Currency"
|
||||
msgstr "Einnahmen/Ausgaben nach Währung"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
#: templates/insights/fragments/category_overview/index.html:13
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Gesamt"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:202
|
||||
#, fuzzy
|
||||
#| msgid "final total"
|
||||
msgid "Final Total"
|
||||
msgstr "Gesamtbilanz"
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:15
|
||||
msgid "You've spent an average of"
|
||||
msgstr "Deine Ausgaben liegen im Durchschnitt bei"
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:23
|
||||
#, fuzzy
|
||||
msgid "on the last 12 months, at this rate you could go by"
|
||||
msgstr ""
|
||||
msgstr "on the last 12 months, at this rate you could go by"
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:25
|
||||
msgid "months without any income."
|
||||
@@ -2596,8 +2721,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 +2835,16 @@ 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
|
||||
#, fuzzy
|
||||
msgid "This is a demo!"
|
||||
msgstr "This is a demo!"
|
||||
|
||||
#: templates/layouts/base.html:40
|
||||
#, fuzzy
|
||||
msgid "Any data you add here will be wiped in 24hrs or less"
|
||||
msgstr "Any data you add here will be wiped in 24hrs or less"
|
||||
|
||||
#: templates/mini_tools/currency_converter/currency_converter.html:58
|
||||
msgid "Invert"
|
||||
msgstr "Invertieren"
|
||||
@@ -3011,6 +3144,38 @@ msgstr "Gelöschte Transaktionen"
|
||||
msgid "Unchanged"
|
||||
msgstr "Unverändert"
|
||||
|
||||
#: templates/users/fragments/add.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Add new"
|
||||
msgid "Add user"
|
||||
msgstr "Neue hinzufügen"
|
||||
|
||||
#: templates/users/fragments/edit.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Edit category"
|
||||
msgid "Edit user"
|
||||
msgstr "Kategorie bearbeiten"
|
||||
|
||||
#: templates/users/fragments/list.html:30
|
||||
#, fuzzy
|
||||
#| msgid "E-mail"
|
||||
msgid "Email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
#: templates/users/fragments/list.html:31
|
||||
msgid "Superuser"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:51
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:80
|
||||
#, fuzzy
|
||||
#| msgid "Users"
|
||||
msgid "No users"
|
||||
msgstr "Nutzer"
|
||||
|
||||
#: templates/users/generic/hide_amounts.html:2
|
||||
msgid "Hide amounts"
|
||||
msgstr "Werte ausblenden"
|
||||
@@ -3027,6 +3192,16 @@ msgstr "Sounds abspielen"
|
||||
msgid "Show amounts"
|
||||
msgstr "Werte einblenden"
|
||||
|
||||
#: templates/users/login.html:17
|
||||
#, fuzzy
|
||||
msgid "Welcome to WYGIWYH's demo!"
|
||||
msgstr "Welcome to WYGIWYH's demo!"
|
||||
|
||||
#: templates/users/login.html:18
|
||||
#, fuzzy
|
||||
msgid "Use the credentials below to login"
|
||||
msgstr "Use the credentials below to login"
|
||||
|
||||
#: templates/yearly_overview/pages/overview_by_account.html:7
|
||||
#: templates/yearly_overview/pages/overview_by_currency.html:9
|
||||
msgid "Yearly Overview"
|
||||
|
||||
@@ -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-04-13 22:01+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"
|
||||
@@ -30,6 +30,7 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:269 apps/transactions/forms.py:629
|
||||
#: apps/transactions/forms.py:672 apps/transactions/forms.py:704
|
||||
#: apps/transactions/forms.py:739 apps/transactions/forms.py:891
|
||||
#: apps/users/forms.py:210 apps/users/forms.py:372
|
||||
msgid "Update"
|
||||
msgstr ""
|
||||
|
||||
@@ -41,8 +42,8 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:187 apps/transactions/forms.py:211
|
||||
#: apps/transactions/forms.py:637 apps/transactions/forms.py:680
|
||||
#: apps/transactions/forms.py:712 apps/transactions/forms.py:747
|
||||
#: apps/transactions/forms.py:899
|
||||
#: templates/account_groups/fragments/list.html:9
|
||||
#: apps/transactions/forms.py:899 apps/users/forms.py:218
|
||||
#: apps/users/forms.py:380 templates/account_groups/fragments/list.html:9
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/categories/fragments/list.html:9
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
@@ -57,6 +58,7 @@ msgstr ""
|
||||
#: templates/mini_tools/unit_price_calculator.html:162
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/rules/fragments/list.html:9 templates/tags/fragments/list.html:9
|
||||
#: templates/users/fragments/list.html:10
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
|
||||
@@ -74,8 +76,9 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:40 apps/transactions/forms.py:303
|
||||
#: apps/transactions/forms.py:310 apps/transactions/forms.py:510
|
||||
#: apps/transactions/forms.py:771 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:686
|
||||
#: templates/insights/fragments/category_overview/index.html:9
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:688
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:215
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
|
||||
@@ -86,7 +89,7 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:48 apps/transactions/forms.py:319
|
||||
#: apps/transactions/forms.py:327 apps/transactions/forms.py:503
|
||||
#: apps/transactions/forms.py:764 apps/transactions/models.py:311
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:690
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:692
|
||||
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
|
||||
#: templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
@@ -107,6 +110,7 @@ msgstr ""
|
||||
#: templates/recurring_transactions/fragments/table.html:18
|
||||
#: templates/rules/fragments/list.html:26
|
||||
#: templates/tags/fragments/table.html:16
|
||||
#: templates/users/fragments/list.html:29
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
@@ -158,7 +162,7 @@ msgstr ""
|
||||
#: apps/rules/models.py:30 apps/rules/models.py:242
|
||||
#: apps/transactions/forms.py:60 apps/transactions/forms.py:495
|
||||
#: apps/transactions/forms.py:756 apps/transactions/models.py:278
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:668
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:670
|
||||
msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
@@ -184,7 +188,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 +203,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 +214,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 ""
|
||||
@@ -280,7 +284,11 @@ msgstr ""
|
||||
msgid "Ungrouped"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/fields/month_year.py:23 apps/common/fields/month_year.py:51
|
||||
#: apps/common/fields/month_year.py:30
|
||||
msgid "Invalid date format. Use YYYY-MM or YYYY-MM-DD."
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/fields/month_year.py:59
|
||||
msgid "Invalid date format. Use YYYY-MM."
|
||||
msgstr ""
|
||||
|
||||
@@ -312,7 +320,7 @@ msgid ""
|
||||
"owner.<br/>Public: Shown for all users. Only editable by the owner."
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:131
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:135
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
|
||||
@@ -403,7 +411,7 @@ msgstr ""
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
#: apps/common/views.py:110
|
||||
#: apps/common/views.py:111
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr ""
|
||||
|
||||
@@ -528,7 +536,7 @@ msgstr ""
|
||||
#: templates/categories/fragments/list.html:21
|
||||
#: templates/entities/fragments/list.html:21
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21 templates/users/fragments/list.html:28
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
@@ -624,19 +632,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 ""
|
||||
|
||||
@@ -693,7 +701,7 @@ msgstr ""
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:173
|
||||
#: apps/rules/forms.py:188 apps/rules/models.py:37 apps/rules/models.py:270
|
||||
#: apps/transactions/forms.py:347 apps/transactions/models.py:301
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:696
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:698
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
@@ -750,6 +758,8 @@ msgid "Entry deleted successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:14 apps/export_app/forms.py:131
|
||||
#: templates/includes/navbar.html:147 templates/users/fragments/list.html:6
|
||||
#: templates/users/pages/index.html:4
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
@@ -774,13 +784,13 @@ msgstr ""
|
||||
#: apps/transactions/forms.py:56 apps/transactions/forms.py:518
|
||||
#: apps/transactions/forms.py:779 apps/transactions/models.py:261
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:493
|
||||
#: apps/transactions/models.py:693 templates/entities/fragments/list.html:5
|
||||
#: apps/transactions/models.py:695 templates/entities/fragments/list.html:5
|
||||
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
|
||||
msgid "Entities"
|
||||
msgstr ""
|
||||
|
||||
#: apps/export_app/forms.py:56 apps/export_app/forms.py:140
|
||||
#: apps/transactions/models.py:730 templates/includes/navbar.html:74
|
||||
#: apps/transactions/models.py:732 templates/includes/navbar.html:74
|
||||
#: templates/recurring_transactions/fragments/list.html:5
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
@@ -851,15 +861,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,29 +928,31 @@ 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 ""
|
||||
|
||||
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167
|
||||
#: templates/insights/fragments/category_overview/index.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:19
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/insights/fragments/category_overview/index.html:116
|
||||
msgid "Uncategorized"
|
||||
msgstr ""
|
||||
|
||||
@@ -1023,7 +1035,7 @@ msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:167 apps/rules/forms.py:180 apps/rules/models.py:31
|
||||
#: apps/rules/models.py:246 apps/transactions/models.py:285
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:674
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:676
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
@@ -1040,20 +1052,20 @@ msgstr ""
|
||||
#: apps/rules/models.py:258 apps/transactions/forms.py:68
|
||||
#: apps/transactions/forms.py:334 apps/transactions/forms.py:524
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:471
|
||||
#: apps/transactions/models.py:698
|
||||
#: apps/transactions/models.py:700
|
||||
msgid "Reference Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:171 apps/rules/forms.py:184 apps/rules/models.py:35
|
||||
#: apps/rules/models.py:262 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:679 templates/insights/fragments/sankey.html:95
|
||||
#: apps/transactions/models.py:681 templates/insights/fragments/sankey.html:95
|
||||
msgid "Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/rules/forms.py:172 apps/rules/forms.py:185 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:36 apps/rules/models.py:266
|
||||
#: apps/transactions/forms.py:338 apps/transactions/models.py:299
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:682
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:684
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
@@ -1149,43 +1161,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 ""
|
||||
|
||||
@@ -1304,7 +1316,7 @@ msgstr ""
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
#: templates/calendar_view/fragments/list.html:54
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
msgid "Income"
|
||||
msgstr ""
|
||||
@@ -1315,7 +1327,7 @@ msgstr ""
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
#: templates/calendar_view/fragments/list.html:58
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
@@ -1323,7 +1335,7 @@ msgstr ""
|
||||
msgid "Installment Plan"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:729
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:731
|
||||
msgid "Recurring Transaction"
|
||||
msgstr ""
|
||||
|
||||
@@ -1380,11 +1392,11 @@ msgstr ""
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:702
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:704
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:703
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:705
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
@@ -1396,48 +1408,48 @@ msgstr ""
|
||||
msgid "Installment Amount"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:719
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:721
|
||||
msgid "Add description to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:722
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:724
|
||||
msgid "Add notes to transactions"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:661
|
||||
#: apps/transactions/models.py:663
|
||||
msgid "day(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:662
|
||||
#: apps/transactions/models.py:664
|
||||
msgid "week(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:663
|
||||
#: apps/transactions/models.py:665
|
||||
msgid "month(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:664
|
||||
#: apps/transactions/models.py:666
|
||||
msgid "year(s)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:666
|
||||
#: apps/transactions/models.py:668
|
||||
#: templates/recurring_transactions/fragments/list.html:24
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:705
|
||||
#: apps/transactions/models.py:707
|
||||
msgid "Recurrence Type"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:708
|
||||
#: apps/transactions/models.py:710
|
||||
msgid "Recurrence Interval"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:712
|
||||
#: apps/transactions/models.py:714
|
||||
msgid "Last Generated Date"
|
||||
msgstr ""
|
||||
|
||||
#: apps/transactions/models.py:715
|
||||
#: apps/transactions/models.py:717
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr ""
|
||||
|
||||
@@ -1614,40 +1626,104 @@ msgstr ""
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:19 apps/users/models.py:13
|
||||
#: apps/users/forms.py:23 apps/users/models.py:13 templates/users/login.html:19
|
||||
msgid "E-mail"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:25
|
||||
#: apps/users/forms.py:29 templates/users/login.html:20
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:33
|
||||
#: apps/users/forms.py:37
|
||||
msgid "Invalid e-mail or password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:34
|
||||
#: apps/users/forms.py:38
|
||||
msgid "This account is deactivated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:50 apps/users/forms.py:63 apps/users/forms.py:85
|
||||
#: apps/users/forms.py:54 apps/users/forms.py:67 apps/users/forms.py:89
|
||||
#: templates/monthly_overview/pages/overview.html:153
|
||||
#: templates/transactions/pages/transactions.html:35
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:91 apps/users/models.py:41
|
||||
#: apps/users/forms.py:95 apps/users/models.py:41
|
||||
msgid "Date Format"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:96 apps/users/models.py:46
|
||||
#: apps/users/forms.py:100 apps/users/models.py:46
|
||||
msgid "Datetime Format"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:102 apps/users/models.py:49
|
||||
#: apps/users/forms.py:106 apps/users/models.py:49
|
||||
msgid "Number Format"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:141
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This changes the language (if available) and how numbers and dates are "
|
||||
"displayed\n"
|
||||
"Consider helping translate WYGIWYH to your language at %(translation_link)s"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:150
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:153
|
||||
msgid "Leave blank to keep the current password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:156
|
||||
msgid "Confirm New Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:168 apps/users/forms.py:329
|
||||
msgid ""
|
||||
"Designates whether this user should be treated as active. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:171 apps/users/forms.py:332
|
||||
msgid ""
|
||||
"Designates that this user has all permissions without explicitly assigning "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:242
|
||||
msgid "This email address is already in use by another account."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:250
|
||||
msgid "The two password fields didn't match."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:252
|
||||
msgid "Please confirm your new password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:254
|
||||
msgid "Please enter the new password first."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:274
|
||||
msgid "You cannot deactivate your own account using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:287
|
||||
msgid "Cannot remove status from the last superuser."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:293
|
||||
msgid "You cannot remove your own superuser status using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:390
|
||||
msgid "A user with this email address already exists."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/models.py:27 templates/includes/navbar.html:28
|
||||
msgid "Yearly by currency"
|
||||
msgstr ""
|
||||
@@ -1688,26 +1764,34 @@ msgstr ""
|
||||
msgid "Start page"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:62
|
||||
#: apps/users/views.py:67
|
||||
msgid "Transaction amounts are now hidden"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:65
|
||||
#: apps/users/views.py:70
|
||||
msgid "Transaction amounts are now displayed"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:83
|
||||
#: apps/users/views.py:88
|
||||
msgid "Sounds are now muted"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:86
|
||||
#: apps/users/views.py:91
|
||||
msgid "Sounds will now play"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:102
|
||||
#: apps/users/views.py:107
|
||||
msgid "Your settings have been updated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:151
|
||||
msgid "Item added successfully"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/views.py:182
|
||||
msgid "Item updated successfully"
|
||||
msgstr ""
|
||||
|
||||
#: templates/account_groups/fragments/add.html:5
|
||||
msgid "Add account group"
|
||||
msgstr ""
|
||||
@@ -1730,6 +1814,7 @@ msgstr ""
|
||||
#: templates/recurring_transactions/fragments/table.html:25
|
||||
#: templates/rules/fragments/list.html:33
|
||||
#: templates/tags/fragments/table.html:23
|
||||
#: templates/users/fragments/list.html:38
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
@@ -1752,6 +1837,7 @@ msgstr ""
|
||||
#: templates/rules/fragments/transaction_rule/view.html:47
|
||||
#: templates/rules/fragments/transaction_rule/view.html:80
|
||||
#: templates/tags/fragments/table.html:28
|
||||
#: templates/users/fragments/list.html:43
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
@@ -1974,7 +2060,7 @@ msgid "Muted"
|
||||
msgstr ""
|
||||
|
||||
#: templates/categories/fragments/table.html:75
|
||||
#: templates/insights/fragments/category_overview/index.html:67
|
||||
#: templates/insights/fragments/category_overview/index.html:225
|
||||
msgid "No categories"
|
||||
msgstr ""
|
||||
|
||||
@@ -2472,35 +2558,52 @@ msgstr ""
|
||||
msgid "Automation"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:150
|
||||
#: templates/includes/navbar.html:145
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:154
|
||||
msgid "Only use this if you know what you're doing"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:151
|
||||
#: templates/includes/navbar.html:155
|
||||
msgid "Django Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:160
|
||||
#: templates/includes/navbar.html:165
|
||||
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:19
|
||||
msgid "Edit profile"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:46
|
||||
msgid "Clear cache"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:43
|
||||
#: templates/includes/navbar/user_menu.html:50
|
||||
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 ""
|
||||
|
||||
@@ -2533,11 +2636,15 @@ msgstr ""
|
||||
msgid "Income/Expense by Currency"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
#: templates/insights/fragments/category_overview/index.html:13
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:202
|
||||
msgid "Final Total"
|
||||
msgstr ""
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:15
|
||||
msgid "You've spent an average of"
|
||||
msgstr ""
|
||||
@@ -2667,6 +2774,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 ""
|
||||
@@ -2961,6 +3076,30 @@ msgstr ""
|
||||
msgid "Unchanged"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/add.html:5
|
||||
msgid "Add user"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/edit.html:5
|
||||
msgid "Edit user"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:30
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:31
|
||||
msgid "Superuser"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:51
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:80
|
||||
msgid "No users"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/generic/hide_amounts.html:2
|
||||
msgid "Hide amounts"
|
||||
msgstr ""
|
||||
@@ -2977,6 +3116,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"
|
||||
|
||||
3769
app/locale/es/LC_MESSAGES/django.po
Normal file
3769
app/locale/es/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
3614
app/locale/fr/LC_MESSAGES/django.po
Normal file
3614
app/locale/fr/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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-13 07:05+0000\n"
|
||||
"POT-Creation-Date: 2025-04-13 22:01+0000\n"
|
||||
"PO-Revision-Date: 2025-04-13 11:16+0000\n"
|
||||
"Last-Translator: Dimitri Decrock <dj.flashpower@gmail.com>\n"
|
||||
"Language-Team: Dutch <https://translations.herculino.com/projects/wygiwyh/"
|
||||
"app/nl/>\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"
|
||||
@@ -31,6 +31,7 @@ msgstr "Groepsnaam"
|
||||
#: apps/transactions/forms.py:269 apps/transactions/forms.py:629
|
||||
#: apps/transactions/forms.py:672 apps/transactions/forms.py:704
|
||||
#: apps/transactions/forms.py:739 apps/transactions/forms.py:891
|
||||
#: apps/users/forms.py:210 apps/users/forms.py:372
|
||||
msgid "Update"
|
||||
msgstr "Bijwerken"
|
||||
|
||||
@@ -42,8 +43,8 @@ msgstr "Bijwerken"
|
||||
#: apps/transactions/forms.py:187 apps/transactions/forms.py:211
|
||||
#: apps/transactions/forms.py:637 apps/transactions/forms.py:680
|
||||
#: apps/transactions/forms.py:712 apps/transactions/forms.py:747
|
||||
#: apps/transactions/forms.py:899
|
||||
#: templates/account_groups/fragments/list.html:9
|
||||
#: apps/transactions/forms.py:899 apps/users/forms.py:218
|
||||
#: apps/users/forms.py:380 templates/account_groups/fragments/list.html:9
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/categories/fragments/list.html:9
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
@@ -58,6 +59,7 @@ msgstr "Bijwerken"
|
||||
#: templates/mini_tools/unit_price_calculator.html:162
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/rules/fragments/list.html:9 templates/tags/fragments/list.html:9
|
||||
#: templates/users/fragments/list.html:10
|
||||
msgid "Add"
|
||||
msgstr "Toevoegen"
|
||||
|
||||
@@ -75,8 +77,9 @@ msgstr "Nieuw saldo"
|
||||
#: apps/transactions/forms.py:40 apps/transactions/forms.py:303
|
||||
#: apps/transactions/forms.py:310 apps/transactions/forms.py:510
|
||||
#: apps/transactions/forms.py:771 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:686
|
||||
#: templates/insights/fragments/category_overview/index.html:9
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:688
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:215
|
||||
msgid "Category"
|
||||
msgstr "Categorie"
|
||||
|
||||
@@ -87,7 +90,7 @@ msgstr "Categorie"
|
||||
#: apps/transactions/forms.py:48 apps/transactions/forms.py:319
|
||||
#: apps/transactions/forms.py:327 apps/transactions/forms.py:503
|
||||
#: apps/transactions/forms.py:764 apps/transactions/models.py:311
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:690
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:692
|
||||
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
|
||||
#: templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
@@ -108,6 +111,7 @@ msgstr "Labels"
|
||||
#: templates/recurring_transactions/fragments/table.html:18
|
||||
#: templates/rules/fragments/list.html:26
|
||||
#: templates/tags/fragments/table.html:16
|
||||
#: templates/users/fragments/list.html:29
|
||||
msgid "Name"
|
||||
msgstr "Naam"
|
||||
|
||||
@@ -163,7 +167,7 @@ msgstr ""
|
||||
#: apps/rules/models.py:30 apps/rules/models.py:242
|
||||
#: apps/transactions/forms.py:60 apps/transactions/forms.py:495
|
||||
#: apps/transactions/forms.py:756 apps/transactions/models.py:278
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:668
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:670
|
||||
msgid "Account"
|
||||
msgstr "Rekening"
|
||||
|
||||
@@ -190,7 +194,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 +209,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 +220,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"
|
||||
@@ -286,7 +290,11 @@ msgstr "Fout bij het aanmaken van een nieuwe instantie"
|
||||
msgid "Ungrouped"
|
||||
msgstr "Niet gegroepeerd"
|
||||
|
||||
#: apps/common/fields/month_year.py:23 apps/common/fields/month_year.py:51
|
||||
#: apps/common/fields/month_year.py:30
|
||||
msgid "Invalid date format. Use YYYY-MM or YYYY-MM-DD."
|
||||
msgstr "Ongeldige datumnotatie. Gebruik JJJJ-MM of JJJJ-MM-DD."
|
||||
|
||||
#: apps/common/fields/month_year.py:59
|
||||
msgid "Invalid date format. Use YYYY-MM."
|
||||
msgstr "Ongeldige datumnotatie. Gebruik JJJJ-MM."
|
||||
|
||||
@@ -323,7 +331,7 @@ msgstr ""
|
||||
"bewerkbaar door de eigenaar.<br/>Publiek: Weergegeven voor alle gebruikers. "
|
||||
"Alleen bewerkbaar door de eigenaar."
|
||||
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:131
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:135
|
||||
msgid "Save"
|
||||
msgstr "Opslaan"
|
||||
|
||||
@@ -414,7 +422,7 @@ msgstr "Fout"
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: apps/common/views.py:110
|
||||
#: apps/common/views.py:111
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr "Cache succesvol gewist"
|
||||
|
||||
@@ -539,7 +547,7 @@ msgstr "Soort Dienst"
|
||||
#: templates/categories/fragments/list.html:21
|
||||
#: templates/entities/fragments/list.html:21
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21 templates/users/fragments/list.html:28
|
||||
msgid "Active"
|
||||
msgstr "Actief"
|
||||
|
||||
@@ -644,19 +652,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"
|
||||
|
||||
@@ -714,7 +722,7 @@ msgstr "Betaal Munteenheid"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:173
|
||||
#: apps/rules/forms.py:188 apps/rules/models.py:37 apps/rules/models.py:270
|
||||
#: apps/transactions/forms.py:347 apps/transactions/models.py:301
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:696
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:698
|
||||
msgid "Notes"
|
||||
msgstr "Opmerkingen"
|
||||
|
||||
@@ -771,6 +779,8 @@ msgid "Entry deleted successfully"
|
||||
msgstr "Item succesvol verwijderd"
|
||||
|
||||
#: apps/export_app/forms.py:14 apps/export_app/forms.py:131
|
||||
#: templates/includes/navbar.html:147 templates/users/fragments/list.html:6
|
||||
#: templates/users/pages/index.html:4
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
||||
|
||||
@@ -795,13 +805,13 @@ msgstr "Categorieën"
|
||||
#: apps/transactions/forms.py:56 apps/transactions/forms.py:518
|
||||
#: apps/transactions/forms.py:779 apps/transactions/models.py:261
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:493
|
||||
#: apps/transactions/models.py:693 templates/entities/fragments/list.html:5
|
||||
#: apps/transactions/models.py:695 templates/entities/fragments/list.html:5
|
||||
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
|
||||
msgid "Entities"
|
||||
msgstr "Bedrijven"
|
||||
|
||||
#: apps/export_app/forms.py:56 apps/export_app/forms.py:140
|
||||
#: apps/transactions/models.py:730 templates/includes/navbar.html:74
|
||||
#: apps/transactions/models.py:732 templates/includes/navbar.html:74
|
||||
#: templates/recurring_transactions/fragments/list.html:5
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
@@ -872,15 +882,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,29 +951,31 @@ 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"
|
||||
|
||||
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167
|
||||
#: templates/insights/fragments/category_overview/index.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:19
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/insights/fragments/category_overview/index.html:116
|
||||
msgid "Uncategorized"
|
||||
msgstr "Ongecategoriseerd"
|
||||
|
||||
@@ -1046,7 +1058,7 @@ msgstr "Operator"
|
||||
|
||||
#: apps/rules/forms.py:167 apps/rules/forms.py:180 apps/rules/models.py:31
|
||||
#: apps/rules/models.py:246 apps/transactions/models.py:285
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:674
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:676
|
||||
msgid "Type"
|
||||
msgstr "Soort"
|
||||
|
||||
@@ -1063,20 +1075,20 @@ msgstr "Betaald"
|
||||
#: apps/rules/models.py:258 apps/transactions/forms.py:68
|
||||
#: apps/transactions/forms.py:334 apps/transactions/forms.py:524
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:471
|
||||
#: apps/transactions/models.py:698
|
||||
#: apps/transactions/models.py:700
|
||||
msgid "Reference Date"
|
||||
msgstr "Referentiedatum"
|
||||
|
||||
#: apps/rules/forms.py:171 apps/rules/forms.py:184 apps/rules/models.py:35
|
||||
#: apps/rules/models.py:262 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:679 templates/insights/fragments/sankey.html:95
|
||||
#: apps/transactions/models.py:681 templates/insights/fragments/sankey.html:95
|
||||
msgid "Amount"
|
||||
msgstr "Bedrag"
|
||||
|
||||
#: apps/rules/forms.py:172 apps/rules/forms.py:185 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:36 apps/rules/models.py:266
|
||||
#: apps/transactions/forms.py:338 apps/transactions/models.py:299
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:682
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:684
|
||||
msgid "Description"
|
||||
msgstr "Beschrijving"
|
||||
|
||||
@@ -1174,43 +1186,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"
|
||||
|
||||
@@ -1335,7 +1347,7 @@ msgstr "Bedrijf"
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
#: templates/calendar_view/fragments/list.html:54
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
msgid "Income"
|
||||
msgstr "Ontvangsten Transactie"
|
||||
@@ -1346,7 +1358,7 @@ msgstr "Ontvangsten Transactie"
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
#: templates/calendar_view/fragments/list.html:58
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
msgid "Expense"
|
||||
msgstr "Uitgave"
|
||||
|
||||
@@ -1354,7 +1366,7 @@ msgstr "Uitgave"
|
||||
msgid "Installment Plan"
|
||||
msgstr "Afbetalingsplan"
|
||||
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:729
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:731
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Terugkerende verrichting"
|
||||
|
||||
@@ -1411,11 +1423,11 @@ msgstr "Begin afbetaling"
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "Het nummer van de aflevering om mee te beginnen"
|
||||
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:702
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:704
|
||||
msgid "Start Date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:703
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:705
|
||||
msgid "End Date"
|
||||
msgstr "Einddatum"
|
||||
|
||||
@@ -1427,48 +1439,48 @@ msgstr "Terugkeerpatroon"
|
||||
msgid "Installment Amount"
|
||||
msgstr "Termijnbedrag"
|
||||
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:719
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:721
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Beschrijving toevoegen aan verrichting"
|
||||
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:722
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:724
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Notities toevoegen aan verrichting"
|
||||
|
||||
#: apps/transactions/models.py:661
|
||||
#: apps/transactions/models.py:663
|
||||
msgid "day(s)"
|
||||
msgstr "dag(en)"
|
||||
|
||||
#: apps/transactions/models.py:662
|
||||
#: apps/transactions/models.py:664
|
||||
msgid "week(s)"
|
||||
msgstr "we(e)k(en)"
|
||||
|
||||
#: apps/transactions/models.py:663
|
||||
#: apps/transactions/models.py:665
|
||||
msgid "month(s)"
|
||||
msgstr "maand(en)"
|
||||
|
||||
#: apps/transactions/models.py:664
|
||||
#: apps/transactions/models.py:666
|
||||
msgid "year(s)"
|
||||
msgstr "ja(a)r(en)"
|
||||
|
||||
#: apps/transactions/models.py:666
|
||||
#: apps/transactions/models.py:668
|
||||
#: templates/recurring_transactions/fragments/list.html:24
|
||||
msgid "Paused"
|
||||
msgstr "Gepauzeerd"
|
||||
|
||||
#: apps/transactions/models.py:705
|
||||
#: apps/transactions/models.py:707
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Type Terugkeerpatroon"
|
||||
|
||||
#: apps/transactions/models.py:708
|
||||
#: apps/transactions/models.py:710
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Terugkeer Interval"
|
||||
|
||||
#: apps/transactions/models.py:712
|
||||
#: apps/transactions/models.py:714
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Laatste Gegenereerde Datum"
|
||||
|
||||
#: apps/transactions/models.py:715
|
||||
#: apps/transactions/models.py:717
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Laatste Gegenereerde Referentiedatum"
|
||||
|
||||
@@ -1645,40 +1657,111 @@ msgstr "Rechten"
|
||||
msgid "Important dates"
|
||||
msgstr "Belangrijke datums"
|
||||
|
||||
#: apps/users/forms.py:19 apps/users/models.py:13
|
||||
#: apps/users/forms.py:23 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:29 templates/users/login.html:20
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: apps/users/forms.py:33
|
||||
#: apps/users/forms.py:37
|
||||
msgid "Invalid e-mail or password"
|
||||
msgstr "Ongeldig e-mailadres of wachtwoord"
|
||||
|
||||
#: apps/users/forms.py:34
|
||||
#: apps/users/forms.py:38
|
||||
msgid "This account is deactivated"
|
||||
msgstr "Deze gebruiker is gedeactiveerd"
|
||||
|
||||
#: apps/users/forms.py:50 apps/users/forms.py:63 apps/users/forms.py:85
|
||||
#: apps/users/forms.py:54 apps/users/forms.py:67 apps/users/forms.py:89
|
||||
#: templates/monthly_overview/pages/overview.html:153
|
||||
#: templates/transactions/pages/transactions.html:35
|
||||
msgid "Default"
|
||||
msgstr "Standaard"
|
||||
|
||||
#: apps/users/forms.py:91 apps/users/models.py:41
|
||||
#: apps/users/forms.py:95 apps/users/models.py:41
|
||||
msgid "Date Format"
|
||||
msgstr "Datumnotatie"
|
||||
|
||||
#: apps/users/forms.py:96 apps/users/models.py:46
|
||||
#: apps/users/forms.py:100 apps/users/models.py:46
|
||||
msgid "Datetime Format"
|
||||
msgstr "Tijdsnotatie"
|
||||
|
||||
#: apps/users/forms.py:102 apps/users/models.py:49
|
||||
#: apps/users/forms.py:106 apps/users/models.py:49
|
||||
msgid "Number Format"
|
||||
msgstr "Schrijfwijze Nummers"
|
||||
|
||||
#: apps/users/forms.py:141
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This changes the language (if available) and how numbers and dates are "
|
||||
"displayed\n"
|
||||
"Consider helping translate WYGIWYH to your language at %(translation_link)s"
|
||||
msgstr ""
|
||||
"Dit verandert de taal (indien beschikbaar) en hoe getallen en datums worden "
|
||||
"weergegeven\n"
|
||||
"Overweeg om WYGIWYH te helpen vertalen naar jouw taal op %(translation_link)s"
|
||||
|
||||
#: apps/users/forms.py:150
|
||||
#, fuzzy
|
||||
#| msgid "Password"
|
||||
msgid "New Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: apps/users/forms.py:153
|
||||
msgid "Leave blank to keep the current password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:156
|
||||
msgid "Confirm New Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:168 apps/users/forms.py:329
|
||||
msgid ""
|
||||
"Designates whether this user should be treated as active. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:171 apps/users/forms.py:332
|
||||
msgid ""
|
||||
"Designates that this user has all permissions without explicitly assigning "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:242
|
||||
msgid "This email address is already in use by another account."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:250
|
||||
msgid "The two password fields didn't match."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:252
|
||||
msgid "Please confirm your new password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:254
|
||||
msgid "Please enter the new password first."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:274
|
||||
msgid "You cannot deactivate your own account using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:287
|
||||
msgid "Cannot remove status from the last superuser."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:293
|
||||
msgid "You cannot remove your own superuser status using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:390
|
||||
#, fuzzy
|
||||
#| msgid "A value for this field already exists in the rule."
|
||||
msgid "A user with this email address already exists."
|
||||
msgstr "Een waarde voor dit veld bestaat al in de regel."
|
||||
|
||||
#: apps/users/models.py:27 templates/includes/navbar.html:28
|
||||
msgid "Yearly by currency"
|
||||
msgstr "Jaarlijks per munteenheid"
|
||||
@@ -1719,26 +1802,38 @@ msgstr "Tijdszone"
|
||||
msgid "Start page"
|
||||
msgstr "Startpagina"
|
||||
|
||||
#: apps/users/views.py:62
|
||||
#: apps/users/views.py:67
|
||||
msgid "Transaction amounts are now hidden"
|
||||
msgstr "Verrichtingsbedragen worden nu verborgen"
|
||||
|
||||
#: apps/users/views.py:65
|
||||
#: apps/users/views.py:70
|
||||
msgid "Transaction amounts are now displayed"
|
||||
msgstr "Verrichtingsbedragen worden nu weergegeven"
|
||||
|
||||
#: apps/users/views.py:83
|
||||
#: apps/users/views.py:88
|
||||
msgid "Sounds are now muted"
|
||||
msgstr "De Geluiden zijn nu gedempt"
|
||||
|
||||
#: apps/users/views.py:86
|
||||
#: apps/users/views.py:91
|
||||
msgid "Sounds will now play"
|
||||
msgstr "De geluiden worden nu afgespeeld"
|
||||
|
||||
#: apps/users/views.py:102
|
||||
#: apps/users/views.py:107
|
||||
msgid "Your settings have been updated"
|
||||
msgstr "Jouw instellingen zijn bijgewerkt"
|
||||
|
||||
#: apps/users/views.py:151
|
||||
#, fuzzy
|
||||
#| msgid "Rule added successfully"
|
||||
msgid "Item added successfully"
|
||||
msgstr "Regel succesvol toegevoegd"
|
||||
|
||||
#: apps/users/views.py:182
|
||||
#, fuzzy
|
||||
#| msgid "Rule updated successfully"
|
||||
msgid "Item updated successfully"
|
||||
msgstr "Regel succesvol bijgewerkt"
|
||||
|
||||
#: templates/account_groups/fragments/add.html:5
|
||||
msgid "Add account group"
|
||||
msgstr "Rekeningsgroep toevoegen"
|
||||
@@ -1761,6 +1856,7 @@ msgstr "Rekeningsgroep bewerken"
|
||||
#: templates/recurring_transactions/fragments/table.html:25
|
||||
#: templates/rules/fragments/list.html:33
|
||||
#: templates/tags/fragments/table.html:23
|
||||
#: templates/users/fragments/list.html:38
|
||||
msgid "Actions"
|
||||
msgstr "Acties"
|
||||
|
||||
@@ -1783,6 +1879,7 @@ msgstr "Acties"
|
||||
#: templates/rules/fragments/transaction_rule/view.html:47
|
||||
#: templates/rules/fragments/transaction_rule/view.html:80
|
||||
#: templates/tags/fragments/table.html:28
|
||||
#: templates/users/fragments/list.html:43
|
||||
msgid "Edit"
|
||||
msgstr "Bewerken"
|
||||
|
||||
@@ -2005,7 +2102,7 @@ msgid "Muted"
|
||||
msgstr "Gedempt"
|
||||
|
||||
#: templates/categories/fragments/table.html:75
|
||||
#: templates/insights/fragments/category_overview/index.html:67
|
||||
#: templates/insights/fragments/category_overview/index.html:225
|
||||
msgid "No categories"
|
||||
msgstr "Geen categorieën"
|
||||
|
||||
@@ -2504,35 +2601,56 @@ msgstr "Beheer"
|
||||
msgid "Automation"
|
||||
msgstr "Automatisatie"
|
||||
|
||||
#: templates/includes/navbar.html:150
|
||||
#: templates/includes/navbar.html:145
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:154
|
||||
msgid "Only use this if you know what you're doing"
|
||||
msgstr "Gebruik dit alleen als je weet wat je doet"
|
||||
|
||||
#: templates/includes/navbar.html:151
|
||||
#: templates/includes/navbar.html:155
|
||||
msgid "Django Admin"
|
||||
msgstr "Django Beheerder"
|
||||
|
||||
#: templates/includes/navbar.html:160
|
||||
#: templates/includes/navbar.html:165
|
||||
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:19
|
||||
#, fuzzy
|
||||
#| msgid "Edit import profile"
|
||||
msgid "Edit profile"
|
||||
msgstr "Importprofiel bewerken"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:46
|
||||
msgid "Clear cache"
|
||||
msgstr "Leegmaken"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:43
|
||||
#: templates/includes/navbar/user_menu.html:50
|
||||
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 "Toegang geweigerd"
|
||||
|
||||
#: templates/includes/scripts/hyperscript/htmx_error_handler.html:9
|
||||
msgid ""
|
||||
"You do not have permission to perform this action or access this resource."
|
||||
msgstr ""
|
||||
"Je hebt geen toestemming om deze actie uit te voeren of toegang te krijgen "
|
||||
"tot deze bron."
|
||||
|
||||
#: 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 "
|
||||
@@ -2567,11 +2685,15 @@ msgstr "Inkomsten/uitgaven per rekening"
|
||||
msgid "Income/Expense by Currency"
|
||||
msgstr "Inkomsten/uitgaven per Munteenheid"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
#: templates/insights/fragments/category_overview/index.html:13
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Totaal"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:202
|
||||
msgid "Final Total"
|
||||
msgstr "Eindtotaal"
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:15
|
||||
msgid "You've spent an average of"
|
||||
msgstr "Je bestede gemiddeld"
|
||||
@@ -2703,6 +2825,15 @@ 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 "Dit is een demo!"
|
||||
|
||||
#: templates/layouts/base.html:40
|
||||
msgid "Any data you add here will be wiped in 24hrs or less"
|
||||
msgstr ""
|
||||
"Alle gegevens die je hier toevoegt, worden binnen 24 uur of minder gewist"
|
||||
|
||||
#: templates/mini_tools/currency_converter/currency_converter.html:58
|
||||
msgid "Invert"
|
||||
msgstr "Omdraaien"
|
||||
@@ -3003,6 +3134,38 @@ msgstr "Verwijderde verrichtingen"
|
||||
msgid "Unchanged"
|
||||
msgstr "Ongewijzigd"
|
||||
|
||||
#: templates/users/fragments/add.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Add new"
|
||||
msgid "Add user"
|
||||
msgstr "Nieuwe toevoegen"
|
||||
|
||||
#: templates/users/fragments/edit.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Edit category"
|
||||
msgid "Edit user"
|
||||
msgstr "Categorie bewerken"
|
||||
|
||||
#: templates/users/fragments/list.html:30
|
||||
#, fuzzy
|
||||
#| msgid "E-mail"
|
||||
msgid "Email"
|
||||
msgstr "E-mailadres"
|
||||
|
||||
#: templates/users/fragments/list.html:31
|
||||
msgid "Superuser"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:51
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:80
|
||||
#, fuzzy
|
||||
#| msgid "Users"
|
||||
msgid "No users"
|
||||
msgstr "Gebruikers"
|
||||
|
||||
#: templates/users/generic/hide_amounts.html:2
|
||||
msgid "Hide amounts"
|
||||
msgstr "Bedragen verbergen"
|
||||
@@ -3019,6 +3182,14 @@ msgstr "Geluiden afspelen"
|
||||
msgid "Show amounts"
|
||||
msgstr "Bedragen tonen"
|
||||
|
||||
#: templates/users/login.html:17
|
||||
msgid "Welcome to WYGIWYH's demo!"
|
||||
msgstr "Welkom bij de demo van WYGIWYH!"
|
||||
|
||||
#: templates/users/login.html:18
|
||||
msgid "Use the credentials below to login"
|
||||
msgstr "Gebruik de onderstaande gegevens om in te loggen"
|
||||
|
||||
#: templates/yearly_overview/pages/overview_by_account.html:7
|
||||
#: templates/yearly_overview/pages/overview_by_currency.html:9
|
||||
msgid "Yearly Overview"
|
||||
|
||||
3411
app/locale/pt/LC_MESSAGES/django.po
Normal file
3411
app/locale/pt/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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-04-13 22:01+0000\n"
|
||||
"PO-Revision-Date: 2025-04-13 08:16+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"
|
||||
@@ -31,6 +31,7 @@ msgstr "Nome do grupo"
|
||||
#: apps/transactions/forms.py:269 apps/transactions/forms.py:629
|
||||
#: apps/transactions/forms.py:672 apps/transactions/forms.py:704
|
||||
#: apps/transactions/forms.py:739 apps/transactions/forms.py:891
|
||||
#: apps/users/forms.py:210 apps/users/forms.py:372
|
||||
msgid "Update"
|
||||
msgstr "Atualizar"
|
||||
|
||||
@@ -42,8 +43,8 @@ msgstr "Atualizar"
|
||||
#: apps/transactions/forms.py:187 apps/transactions/forms.py:211
|
||||
#: apps/transactions/forms.py:637 apps/transactions/forms.py:680
|
||||
#: apps/transactions/forms.py:712 apps/transactions/forms.py:747
|
||||
#: apps/transactions/forms.py:899
|
||||
#: templates/account_groups/fragments/list.html:9
|
||||
#: apps/transactions/forms.py:899 apps/users/forms.py:218
|
||||
#: apps/users/forms.py:380 templates/account_groups/fragments/list.html:9
|
||||
#: templates/accounts/fragments/list.html:9
|
||||
#: templates/categories/fragments/list.html:9
|
||||
#: templates/currencies/fragments/list.html:9
|
||||
@@ -58,6 +59,7 @@ msgstr "Atualizar"
|
||||
#: templates/mini_tools/unit_price_calculator.html:162
|
||||
#: templates/recurring_transactions/fragments/list.html:9
|
||||
#: templates/rules/fragments/list.html:9 templates/tags/fragments/list.html:9
|
||||
#: templates/users/fragments/list.html:10
|
||||
msgid "Add"
|
||||
msgstr "Adicionar"
|
||||
|
||||
@@ -75,8 +77,9 @@ msgstr "Novo saldo"
|
||||
#: apps/transactions/forms.py:40 apps/transactions/forms.py:303
|
||||
#: apps/transactions/forms.py:310 apps/transactions/forms.py:510
|
||||
#: apps/transactions/forms.py:771 apps/transactions/models.py:305
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:686
|
||||
#: templates/insights/fragments/category_overview/index.html:9
|
||||
#: apps/transactions/models.py:488 apps/transactions/models.py:688
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:215
|
||||
msgid "Category"
|
||||
msgstr "Categoria"
|
||||
|
||||
@@ -87,7 +90,7 @@ msgstr "Categoria"
|
||||
#: apps/transactions/forms.py:48 apps/transactions/forms.py:319
|
||||
#: apps/transactions/forms.py:327 apps/transactions/forms.py:503
|
||||
#: apps/transactions/forms.py:764 apps/transactions/models.py:311
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:690
|
||||
#: apps/transactions/models.py:490 apps/transactions/models.py:692
|
||||
#: templates/includes/navbar.html:108 templates/tags/fragments/list.html:5
|
||||
#: templates/tags/pages/index.html:4
|
||||
msgid "Tags"
|
||||
@@ -108,6 +111,7 @@ msgstr "Tags"
|
||||
#: templates/recurring_transactions/fragments/table.html:18
|
||||
#: templates/rules/fragments/list.html:26
|
||||
#: templates/tags/fragments/table.html:16
|
||||
#: templates/users/fragments/list.html:29
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
@@ -162,7 +166,7 @@ msgstr ""
|
||||
#: apps/rules/models.py:30 apps/rules/models.py:242
|
||||
#: apps/transactions/forms.py:60 apps/transactions/forms.py:495
|
||||
#: apps/transactions/forms.py:756 apps/transactions/models.py:278
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:668
|
||||
#: apps/transactions/models.py:448 apps/transactions/models.py:670
|
||||
msgid "Account"
|
||||
msgstr "Conta"
|
||||
|
||||
@@ -188,7 +192,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 +207,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 +218,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"
|
||||
@@ -284,7 +288,11 @@ msgstr "Erro criando nova instância"
|
||||
msgid "Ungrouped"
|
||||
msgstr "Não agrupado"
|
||||
|
||||
#: apps/common/fields/month_year.py:23 apps/common/fields/month_year.py:51
|
||||
#: apps/common/fields/month_year.py:30
|
||||
msgid "Invalid date format. Use YYYY-MM or YYYY-MM-DD."
|
||||
msgstr "Formato de data inválido. Use AAAA-MM ou AAAA-MM-DD."
|
||||
|
||||
#: apps/common/fields/month_year.py:59
|
||||
msgid "Invalid date format. Use YYYY-MM."
|
||||
msgstr "Formato de data inválido. Use AAAA-MM."
|
||||
|
||||
@@ -321,7 +329,7 @@ msgstr ""
|
||||
"Somente editável pelo proprietário.<br/>Público: Exibido para todos os "
|
||||
"usuários. Somente editável pelo proprietário."
|
||||
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:131
|
||||
#: apps/common/forms.py:79 apps/users/forms.py:135
|
||||
msgid "Save"
|
||||
msgstr "Salvar"
|
||||
|
||||
@@ -412,7 +420,7 @@ msgstr "Erro"
|
||||
msgid "Info"
|
||||
msgstr "Informação"
|
||||
|
||||
#: apps/common/views.py:110
|
||||
#: apps/common/views.py:111
|
||||
msgid "Cache cleared successfully"
|
||||
msgstr "Cache limpo com sucesso"
|
||||
|
||||
@@ -537,7 +545,7 @@ msgstr "Tipo de Serviço"
|
||||
#: templates/categories/fragments/list.html:21
|
||||
#: templates/entities/fragments/list.html:21
|
||||
#: templates/recurring_transactions/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21
|
||||
#: templates/tags/fragments/list.html:21 templates/users/fragments/list.html:28
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
@@ -643,19 +651,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"
|
||||
|
||||
@@ -712,7 +720,7 @@ msgstr "Moeda de pagamento"
|
||||
#: apps/dca/models.py:26 apps/dca/models.py:181 apps/rules/forms.py:173
|
||||
#: apps/rules/forms.py:188 apps/rules/models.py:37 apps/rules/models.py:270
|
||||
#: apps/transactions/forms.py:347 apps/transactions/models.py:301
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:696
|
||||
#: apps/transactions/models.py:497 apps/transactions/models.py:698
|
||||
msgid "Notes"
|
||||
msgstr "Notas"
|
||||
|
||||
@@ -769,6 +777,8 @@ msgid "Entry deleted successfully"
|
||||
msgstr "Entrada apagada com sucesso"
|
||||
|
||||
#: apps/export_app/forms.py:14 apps/export_app/forms.py:131
|
||||
#: templates/includes/navbar.html:147 templates/users/fragments/list.html:6
|
||||
#: templates/users/pages/index.html:4
|
||||
msgid "Users"
|
||||
msgstr "Usuários"
|
||||
|
||||
@@ -793,13 +803,13 @@ msgstr "Categorias"
|
||||
#: apps/transactions/forms.py:56 apps/transactions/forms.py:518
|
||||
#: apps/transactions/forms.py:779 apps/transactions/models.py:261
|
||||
#: apps/transactions/models.py:316 apps/transactions/models.py:493
|
||||
#: apps/transactions/models.py:693 templates/entities/fragments/list.html:5
|
||||
#: apps/transactions/models.py:695 templates/entities/fragments/list.html:5
|
||||
#: templates/entities/pages/index.html:4 templates/includes/navbar.html:110
|
||||
msgid "Entities"
|
||||
msgstr "Entidades"
|
||||
|
||||
#: apps/export_app/forms.py:56 apps/export_app/forms.py:140
|
||||
#: apps/transactions/models.py:730 templates/includes/navbar.html:74
|
||||
#: apps/transactions/models.py:732 templates/includes/navbar.html:74
|
||||
#: templates/recurring_transactions/fragments/list.html:5
|
||||
#: templates/recurring_transactions/pages/index.html:4
|
||||
msgid "Recurring Transactions"
|
||||
@@ -870,15 +880,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,29 +949,31 @@ 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"
|
||||
msgstr "Perfil de Importação apagado 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"
|
||||
|
||||
#: apps/insights/forms.py:119 apps/insights/utils/sankey.py:36
|
||||
#: apps/insights/utils/sankey.py:167
|
||||
#: templates/insights/fragments/category_overview/index.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:19
|
||||
#: templates/insights/fragments/category_overview/index.html:87
|
||||
#: templates/insights/fragments/category_overview/index.html:116
|
||||
msgid "Uncategorized"
|
||||
msgstr "Sem categoria"
|
||||
|
||||
@@ -1044,7 +1056,7 @@ msgstr "Operador"
|
||||
|
||||
#: apps/rules/forms.py:167 apps/rules/forms.py:180 apps/rules/models.py:31
|
||||
#: apps/rules/models.py:246 apps/transactions/models.py:285
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:674
|
||||
#: apps/transactions/models.py:453 apps/transactions/models.py:676
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
@@ -1061,20 +1073,20 @@ msgstr "Pago"
|
||||
#: apps/rules/models.py:258 apps/transactions/forms.py:68
|
||||
#: apps/transactions/forms.py:334 apps/transactions/forms.py:524
|
||||
#: apps/transactions/models.py:289 apps/transactions/models.py:471
|
||||
#: apps/transactions/models.py:698
|
||||
#: apps/transactions/models.py:700
|
||||
msgid "Reference Date"
|
||||
msgstr "Data de Referência"
|
||||
|
||||
#: apps/rules/forms.py:171 apps/rules/forms.py:184 apps/rules/models.py:35
|
||||
#: apps/rules/models.py:262 apps/transactions/models.py:294
|
||||
#: apps/transactions/models.py:679 templates/insights/fragments/sankey.html:95
|
||||
#: apps/transactions/models.py:681 templates/insights/fragments/sankey.html:95
|
||||
msgid "Amount"
|
||||
msgstr "Quantia"
|
||||
|
||||
#: apps/rules/forms.py:172 apps/rules/forms.py:185 apps/rules/models.py:14
|
||||
#: apps/rules/models.py:36 apps/rules/models.py:266
|
||||
#: apps/transactions/forms.py:338 apps/transactions/models.py:299
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:682
|
||||
#: apps/transactions/models.py:455 apps/transactions/models.py:684
|
||||
msgid "Description"
|
||||
msgstr "Descrição"
|
||||
|
||||
@@ -1172,43 +1184,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"
|
||||
|
||||
@@ -1332,7 +1344,7 @@ msgstr "Entidade"
|
||||
#: templates/calendar_view/fragments/list.html:52
|
||||
#: templates/calendar_view/fragments/list.html:54
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:10
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:39
|
||||
msgid "Income"
|
||||
msgstr "Renda"
|
||||
@@ -1343,7 +1355,7 @@ msgstr "Renda"
|
||||
#: templates/calendar_view/fragments/list.html:56
|
||||
#: templates/calendar_view/fragments/list.html:58
|
||||
#: templates/cotton/ui/quick_transactions_buttons.html:18
|
||||
#: templates/insights/fragments/category_overview/index.html:11
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
msgid "Expense"
|
||||
msgstr "Despesa"
|
||||
|
||||
@@ -1351,7 +1363,7 @@ msgstr "Despesa"
|
||||
msgid "Installment Plan"
|
||||
msgstr "Parcelamento"
|
||||
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:729
|
||||
#: apps/transactions/models.py:336 apps/transactions/models.py:731
|
||||
msgid "Recurring Transaction"
|
||||
msgstr "Transação Recorrente"
|
||||
|
||||
@@ -1408,11 +1420,11 @@ msgstr "Parcela inicial"
|
||||
msgid "The installment number to start counting from"
|
||||
msgstr "O número da parcela a partir do qual se inicia a contagem"
|
||||
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:702
|
||||
#: apps/transactions/models.py:469 apps/transactions/models.py:704
|
||||
msgid "Start Date"
|
||||
msgstr "Data de Início"
|
||||
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:703
|
||||
#: apps/transactions/models.py:473 apps/transactions/models.py:705
|
||||
msgid "End Date"
|
||||
msgstr "Data Final"
|
||||
|
||||
@@ -1424,48 +1436,48 @@ msgstr "Recorrência"
|
||||
msgid "Installment Amount"
|
||||
msgstr "Valor da Parcela"
|
||||
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:719
|
||||
#: apps/transactions/models.py:500 apps/transactions/models.py:721
|
||||
msgid "Add description to transactions"
|
||||
msgstr "Adicionar descrição às transações"
|
||||
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:722
|
||||
#: apps/transactions/models.py:503 apps/transactions/models.py:724
|
||||
msgid "Add notes to transactions"
|
||||
msgstr "Adicionar notas às transações"
|
||||
|
||||
#: apps/transactions/models.py:661
|
||||
#: apps/transactions/models.py:663
|
||||
msgid "day(s)"
|
||||
msgstr "dia(s)"
|
||||
|
||||
#: apps/transactions/models.py:662
|
||||
#: apps/transactions/models.py:664
|
||||
msgid "week(s)"
|
||||
msgstr "semana(s)"
|
||||
|
||||
#: apps/transactions/models.py:663
|
||||
#: apps/transactions/models.py:665
|
||||
msgid "month(s)"
|
||||
msgstr "mês(es)"
|
||||
|
||||
#: apps/transactions/models.py:664
|
||||
#: apps/transactions/models.py:666
|
||||
msgid "year(s)"
|
||||
msgstr "ano(s)"
|
||||
|
||||
#: apps/transactions/models.py:666
|
||||
#: apps/transactions/models.py:668
|
||||
#: templates/recurring_transactions/fragments/list.html:24
|
||||
msgid "Paused"
|
||||
msgstr "Pausado"
|
||||
|
||||
#: apps/transactions/models.py:705
|
||||
#: apps/transactions/models.py:707
|
||||
msgid "Recurrence Type"
|
||||
msgstr "Tipo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:708
|
||||
#: apps/transactions/models.py:710
|
||||
msgid "Recurrence Interval"
|
||||
msgstr "Intervalo de recorrência"
|
||||
|
||||
#: apps/transactions/models.py:712
|
||||
#: apps/transactions/models.py:714
|
||||
msgid "Last Generated Date"
|
||||
msgstr "Última data gerada"
|
||||
|
||||
#: apps/transactions/models.py:715
|
||||
#: apps/transactions/models.py:717
|
||||
msgid "Last Generated Reference Date"
|
||||
msgstr "Última data de referência gerada"
|
||||
|
||||
@@ -1642,40 +1654,111 @@ msgstr "Permissões"
|
||||
msgid "Important dates"
|
||||
msgstr "Datas importantes"
|
||||
|
||||
#: apps/users/forms.py:19 apps/users/models.py:13
|
||||
#: apps/users/forms.py:23 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:29 templates/users/login.html:20
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: apps/users/forms.py:33
|
||||
#: apps/users/forms.py:37
|
||||
msgid "Invalid e-mail or password"
|
||||
msgstr "E-mail ou senha inválidos"
|
||||
|
||||
#: apps/users/forms.py:34
|
||||
#: apps/users/forms.py:38
|
||||
msgid "This account is deactivated"
|
||||
msgstr "Essa conta está desativada"
|
||||
|
||||
#: apps/users/forms.py:50 apps/users/forms.py:63 apps/users/forms.py:85
|
||||
#: apps/users/forms.py:54 apps/users/forms.py:67 apps/users/forms.py:89
|
||||
#: templates/monthly_overview/pages/overview.html:153
|
||||
#: templates/transactions/pages/transactions.html:35
|
||||
msgid "Default"
|
||||
msgstr "Padrão"
|
||||
|
||||
#: apps/users/forms.py:91 apps/users/models.py:41
|
||||
#: apps/users/forms.py:95 apps/users/models.py:41
|
||||
msgid "Date Format"
|
||||
msgstr "Formato de Data"
|
||||
|
||||
#: apps/users/forms.py:96 apps/users/models.py:46
|
||||
#: apps/users/forms.py:100 apps/users/models.py:46
|
||||
msgid "Datetime Format"
|
||||
msgstr "Formato de Data e Hora"
|
||||
|
||||
#: apps/users/forms.py:102 apps/users/models.py:49
|
||||
#: apps/users/forms.py:106 apps/users/models.py:49
|
||||
msgid "Number Format"
|
||||
msgstr "Formato de Número"
|
||||
|
||||
#: apps/users/forms.py:141
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This changes the language (if available) and how numbers and dates are "
|
||||
"displayed\n"
|
||||
"Consider helping translate WYGIWYH to your language at %(translation_link)s"
|
||||
msgstr ""
|
||||
"Isso altera o idioma (se disponível) e a forma como os números e as datas "
|
||||
"são exibidos\n"
|
||||
"Considere ajudar a traduzir WYGIWYH para seu idioma em %(translation_link)s"
|
||||
|
||||
#: apps/users/forms.py:150
|
||||
#, fuzzy
|
||||
#| msgid "Password"
|
||||
msgid "New Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: apps/users/forms.py:153
|
||||
msgid "Leave blank to keep the current password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:156
|
||||
msgid "Confirm New Password"
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:168 apps/users/forms.py:329
|
||||
msgid ""
|
||||
"Designates whether this user should be treated as active. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:171 apps/users/forms.py:332
|
||||
msgid ""
|
||||
"Designates that this user has all permissions without explicitly assigning "
|
||||
"them."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:242
|
||||
msgid "This email address is already in use by another account."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:250
|
||||
msgid "The two password fields didn't match."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:252
|
||||
msgid "Please confirm your new password."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:254
|
||||
msgid "Please enter the new password first."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:274
|
||||
msgid "You cannot deactivate your own account using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:287
|
||||
msgid "Cannot remove status from the last superuser."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:293
|
||||
msgid "You cannot remove your own superuser status using this form."
|
||||
msgstr ""
|
||||
|
||||
#: apps/users/forms.py:390
|
||||
#, fuzzy
|
||||
#| msgid "A value for this field already exists in the rule."
|
||||
msgid "A user with this email address already exists."
|
||||
msgstr "Já existe um valor para esse campo na regra."
|
||||
|
||||
#: apps/users/models.py:27 templates/includes/navbar.html:28
|
||||
msgid "Yearly by currency"
|
||||
msgstr "Anual por moeda"
|
||||
@@ -1716,26 +1799,38 @@ msgstr "Fuso horário"
|
||||
msgid "Start page"
|
||||
msgstr "Página inicial"
|
||||
|
||||
#: apps/users/views.py:62
|
||||
#: apps/users/views.py:67
|
||||
msgid "Transaction amounts are now hidden"
|
||||
msgstr "Os valores das transações agora estão ocultos"
|
||||
|
||||
#: apps/users/views.py:65
|
||||
#: apps/users/views.py:70
|
||||
msgid "Transaction amounts are now displayed"
|
||||
msgstr "Os valores das transações agora estão sendo exibidos"
|
||||
|
||||
#: apps/users/views.py:83
|
||||
#: apps/users/views.py:88
|
||||
msgid "Sounds are now muted"
|
||||
msgstr "Os sons agora estão silenciados"
|
||||
|
||||
#: apps/users/views.py:86
|
||||
#: apps/users/views.py:91
|
||||
msgid "Sounds will now play"
|
||||
msgstr "Os sons agora serão reproduzidos"
|
||||
|
||||
#: apps/users/views.py:102
|
||||
#: apps/users/views.py:107
|
||||
msgid "Your settings have been updated"
|
||||
msgstr "Suas configurações foram atualizadas"
|
||||
|
||||
#: apps/users/views.py:151
|
||||
#, fuzzy
|
||||
#| msgid "Rule added successfully"
|
||||
msgid "Item added successfully"
|
||||
msgstr "Regra adicionada com sucesso"
|
||||
|
||||
#: apps/users/views.py:182
|
||||
#, fuzzy
|
||||
#| msgid "Rule updated successfully"
|
||||
msgid "Item updated successfully"
|
||||
msgstr "Regra atualizada com sucesso"
|
||||
|
||||
#: templates/account_groups/fragments/add.html:5
|
||||
msgid "Add account group"
|
||||
msgstr "Adicionar grupo de conta"
|
||||
@@ -1758,6 +1853,7 @@ msgstr "Editar grupo de conta"
|
||||
#: templates/recurring_transactions/fragments/table.html:25
|
||||
#: templates/rules/fragments/list.html:33
|
||||
#: templates/tags/fragments/table.html:23
|
||||
#: templates/users/fragments/list.html:38
|
||||
msgid "Actions"
|
||||
msgstr "Ações"
|
||||
|
||||
@@ -1780,6 +1876,7 @@ msgstr "Ações"
|
||||
#: templates/rules/fragments/transaction_rule/view.html:47
|
||||
#: templates/rules/fragments/transaction_rule/view.html:80
|
||||
#: templates/tags/fragments/table.html:28
|
||||
#: templates/users/fragments/list.html:43
|
||||
msgid "Edit"
|
||||
msgstr "Editar"
|
||||
|
||||
@@ -2002,7 +2099,7 @@ msgid "Muted"
|
||||
msgstr "Silenciada"
|
||||
|
||||
#: templates/categories/fragments/table.html:75
|
||||
#: templates/insights/fragments/category_overview/index.html:67
|
||||
#: templates/insights/fragments/category_overview/index.html:225
|
||||
msgid "No categories"
|
||||
msgstr "Nenhum categoria"
|
||||
|
||||
@@ -2503,35 +2600,55 @@ msgstr "Gerenciar"
|
||||
msgid "Automation"
|
||||
msgstr "Automação"
|
||||
|
||||
#: templates/includes/navbar.html:150
|
||||
#: templates/includes/navbar.html:145
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/includes/navbar.html:154
|
||||
msgid "Only use this if you know what you're doing"
|
||||
msgstr "Só use isso se você souber o que está fazendo"
|
||||
|
||||
#: templates/includes/navbar.html:151
|
||||
#: templates/includes/navbar.html:155
|
||||
msgid "Django Admin"
|
||||
msgstr "Django Admin"
|
||||
|
||||
#: templates/includes/navbar.html:160
|
||||
#: templates/includes/navbar.html:165
|
||||
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:19
|
||||
#, fuzzy
|
||||
#| msgid "Edit import profile"
|
||||
msgid "Edit profile"
|
||||
msgstr "Editar perfil de importação"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:46
|
||||
msgid "Clear cache"
|
||||
msgstr "Limpar cache"
|
||||
|
||||
#: templates/includes/navbar/user_menu.html:43
|
||||
#: templates/includes/navbar/user_menu.html:50
|
||||
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."
|
||||
@@ -2565,11 +2682,15 @@ msgstr "Gasto/Despesa por Conta"
|
||||
msgid "Income/Expense by Currency"
|
||||
msgstr "Gasto/Despesa por Moeda"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:12
|
||||
#: templates/insights/fragments/category_overview/index.html:13
|
||||
#: templates/monthly_overview/fragments/monthly_summary.html:167
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: templates/insights/fragments/category_overview/index.html:202
|
||||
msgid "Final Total"
|
||||
msgstr "Total Final"
|
||||
|
||||
#: templates/insights/fragments/emergency_fund.html:15
|
||||
msgid "You've spent an average of"
|
||||
msgstr "Você gastou em média"
|
||||
@@ -2701,6 +2822,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"
|
||||
@@ -2998,6 +3128,38 @@ msgstr "Transações apagadas"
|
||||
msgid "Unchanged"
|
||||
msgstr "Inalterado"
|
||||
|
||||
#: templates/users/fragments/add.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Add new"
|
||||
msgid "Add user"
|
||||
msgstr "Adicionar novo"
|
||||
|
||||
#: templates/users/fragments/edit.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Edit category"
|
||||
msgid "Edit user"
|
||||
msgstr "Editar categoria"
|
||||
|
||||
#: templates/users/fragments/list.html:30
|
||||
#, fuzzy
|
||||
#| msgid "E-mail"
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: templates/users/fragments/list.html:31
|
||||
msgid "Superuser"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:51
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: templates/users/fragments/list.html:80
|
||||
#, fuzzy
|
||||
#| msgid "Users"
|
||||
msgid "No users"
|
||||
msgstr "Usuários"
|
||||
|
||||
#: templates/users/generic/hide_amounts.html:2
|
||||
msgid "Hide amounts"
|
||||
msgstr "Esconder valores"
|
||||
@@ -3014,6 +3176,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"
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
{% load i18n %}
|
||||
<div class="progress-stacked">
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_projected|floatformat:0 }}%">
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_projected|floatformat:"2u" }}%">
|
||||
<div class="progress-bar progress-bar-striped !tw-bg-green-300"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{% trans 'Projected Income' %} ({{ percentage.percentages.income_projected|floatformat:2 }}%)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Income' %} ({{ percentage.percentages.income_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_current|floatformat:0 }}%">
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Income' %} ({{ percentage.percentages.income_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.income_current|floatformat:"2u" }}%">
|
||||
<div class="progress-bar !tw-bg-green-400"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{% trans 'Current Income' %} ({{ p.percentages.income_current|floatformat:2 }}%)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_projected|floatformat:0 }}%">
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_projected|floatformat:"2u" }}%">
|
||||
<div class="progress-bar progress-bar-striped !tw-bg-red-300"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{% trans 'Projected Expenses' %} ({{ percentage.percentages.expense_projected|floatformat:2 }}%)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_current|floatformat:0 }}%">
|
||||
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Expenses' %} ({{ percentage.percentages.expense_current|floatformat:2 }}%)" aria-valuenow="{{ percentage.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ percentage.percentages.expense_current|floatformat:"2u" }}%">
|
||||
<div class="progress-bar !tw-bg-red-400"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
|
||||
@@ -138,9 +138,13 @@
|
||||
{% endif %}
|
||||
<li><a class="dropdown-item {% active_link views='automatic_exchange_rates_index' %}"
|
||||
href="{% url 'automatic_exchange_rates_index' %}">{% translate 'Automatic Exchange Rates' %}</a></li>
|
||||
{% if user.is_superuser %}
|
||||
<li>
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li><h6 class="dropdown-header">{% trans 'Admin' %}</h6></li>
|
||||
<li><a class="dropdown-item {% active_link views='users_index' %}"
|
||||
href="{% url 'users_index' %}">{% translate 'Users' %}</a></li>
|
||||
<li>
|
||||
<a class="dropdown-item"
|
||||
href="{% url 'admin:index' %}"
|
||||
@@ -151,6 +155,7 @@
|
||||
{% translate 'Django Admin' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -5,11 +5,18 @@
|
||||
<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"
|
||||
role="button">
|
||||
<i class="fa-solid fa-gear me-2 fa-fw"></i>{% translate 'Settings' %}</a></li>
|
||||
<li><a class="dropdown-item"
|
||||
hx-get="{% url 'user_edit' pk=request.user.id %}"
|
||||
hx-target="#generic-offcanvas"
|
||||
role="button">
|
||||
<i class="fa-solid fa-user me-2 fa-fw"></i>{% translate 'Edit profile' %}</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
{% spaceless %}
|
||||
<li>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,68 +1,226 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div hx-get="{% url 'category_overview' %}" hx-trigger="updated from:window" class="show-loading" hx-swap="outerHTML" hx-include="#picker-form, #picker-type">
|
||||
<div hx-get="{% url 'category_overview' %}" hx-trigger="updated from:window" class="show-loading" hx-swap="outerHTML"
|
||||
hx-include="#picker-form, #picker-type">
|
||||
{% if total_table %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans 'Category' %}</th>
|
||||
<th scope="col">{% trans 'Income' %}</th>
|
||||
<th scope="col">{% trans 'Expense' %}</th>
|
||||
<th scope="col">{% trans 'Total' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in total_table.values %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% if category.name %}{{ category.name }}{% else %}{% trans 'Uncategorized' %}{% endif %}</th>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_income != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_income"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_expense != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_expense"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_final != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_final"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<th scope="col">{% trans 'Category' %}</th>
|
||||
<th scope="col">{% trans 'Income' %}</th>
|
||||
<th scope="col">{% trans 'Expense' %}</th>
|
||||
<th scope="col">{% trans 'Total' %}</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in total_table.values %}
|
||||
<tr>
|
||||
<th>{% if category.name %}{{ category.name }}{% else %}{% trans 'Uncategorized' %}{% endif %}</th>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_income != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_income"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="green"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_expense != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_expense"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="red"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for currency in category.currencies.values %}
|
||||
{% if currency.total_final != 0 %}
|
||||
<c-amount.display
|
||||
:amount="currency.total_final"
|
||||
:prefix="currency.currency.prefix"
|
||||
:suffix="currency.currency.suffix"
|
||||
:decimal_places="currency.currency.decimal_places"
|
||||
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
||||
{% else %}
|
||||
<div>-</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<div class="chart-container" _="init call setupChart() end" style="position: relative; height:90vh; width:100%">
|
||||
<canvas id="categoryChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ total_table|json_script:"categoryOverviewData" }}
|
||||
|
||||
<script>
|
||||
function setupChart() {
|
||||
var rawData = JSON.parse(document.getElementById('categoryOverviewData').textContent);
|
||||
|
||||
// --- Dynamic Data Processing ---
|
||||
var categories = [];
|
||||
var currencyDetails = {}; // Stores details like { BRL: {code: 'BRL', name: 'Real', ...}, ... }
|
||||
var currencyData = {}; // Stores data arrays like { BRL: [val1, null, val3,...], ... }
|
||||
|
||||
// Pass 1: Collect categories and currency details
|
||||
Object.values(rawData).forEach(cat => {
|
||||
var categoryName = cat.name === null ? "{% trans 'Uncategorized' %}" : cat.name;
|
||||
if (!categories.includes(categoryName)) {
|
||||
categories.push(categoryName);
|
||||
}
|
||||
if (cat.currencies) {
|
||||
Object.values(cat.currencies).forEach(curr => {
|
||||
var details = curr.currency;
|
||||
if (details && details.code && !currencyDetails[details.code]) {
|
||||
var decimals = parseInt(details.decimal_places, 10);
|
||||
currencyDetails[details.code] = {
|
||||
code: details.code,
|
||||
name: details.name || details.code,
|
||||
prefix: details.prefix || '',
|
||||
suffix: details.suffix || '',
|
||||
// Ensure decimal_places is a non-negative integer
|
||||
decimal_places: !isNaN(decimals) && decimals >= 0 ? decimals : 2
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize data structure for each currency with nulls
|
||||
Object.keys(currencyDetails).forEach(code => {
|
||||
currencyData[code] = new Array(categories.length).fill(null);
|
||||
});
|
||||
|
||||
// Pass 2: Populate data arrays (store all valid numbers now)
|
||||
Object.values(rawData).forEach(cat => {
|
||||
var categoryName = cat.name === null ? "{% trans 'Uncategorized' %}" : cat.name;
|
||||
var catIndex = categories.indexOf(categoryName);
|
||||
if (catIndex === -1) return;
|
||||
|
||||
if (cat.currencies) {
|
||||
Object.values(cat.currencies).forEach(curr => {
|
||||
var code = curr.currency?.code;
|
||||
if (code && currencyData[code]) {
|
||||
var value = parseFloat(curr.total_final);
|
||||
// Store the number if it's valid, otherwise keep null
|
||||
currencyData[code][catIndex] = !isNaN(value) ? value : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// --- Dynamic Chart Configuration ---
|
||||
var datasets = Object.keys(currencyDetails).map((code, index) => {
|
||||
return {
|
||||
label: currencyDetails[code].name, // Use currency name for the legend label
|
||||
data: currencyData[code],
|
||||
currencyCode: code, // Store code for easy lookup in tooltip
|
||||
borderWidth: 1
|
||||
};
|
||||
});
|
||||
|
||||
new Chart(document.getElementById('categoryChart'),
|
||||
{
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: categories,
|
||||
datasets: datasets
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
axis: "y"
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function (context) {
|
||||
const dataset = context.dataset;
|
||||
const currencyCode = dataset.currencyCode;
|
||||
const details = currencyDetails[currencyCode];
|
||||
const value = context.parsed.x; // Use 'x' because indexAxis is 'y'
|
||||
|
||||
if (value === null || value === undefined || !details) {
|
||||
// Display the category name if the value is null/undefined
|
||||
return null;
|
||||
}
|
||||
|
||||
let formattedValue = '';
|
||||
try {
|
||||
// Use Intl.NumberFormat for ALL values, configured with locale and exact decimal places
|
||||
formattedValue = new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: details.decimal_places,
|
||||
maximumFractionDigits: details.decimal_places,
|
||||
// Do NOT use style: 'currency' here, as we add prefix/suffix manually
|
||||
}).format(value);
|
||||
} catch (e) {
|
||||
formattedValue = value.toFixed(details.decimal_places);
|
||||
}
|
||||
|
||||
// Return label with currency name and formatted value including prefix/suffix
|
||||
return `${details.prefix}${formattedValue}${details.suffix}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
position: 'top',
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
type: 'linear',
|
||||
title: {
|
||||
display: true,
|
||||
text: '{% trans 'Final Total' %}'
|
||||
},
|
||||
ticks: {
|
||||
// Format ticks using the detected locale
|
||||
callback: function (value, index, ticks) {
|
||||
return value.toLocaleString();
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
title: {
|
||||
display: false,
|
||||
text: '{% trans 'Category' %}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No categories" %}"></c-msg.empty>
|
||||
{% endif %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
11
app/templates/users/fragments/add.html
Normal file
11
app/templates/users/fragments/add.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends 'extends/offcanvas.html' %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}{% translate 'Add user' %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form hx-post="{% url 'user_add' %}" hx-target="#generic-offcanvas" novalidate>
|
||||
{% crispy form %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
11
app/templates/users/fragments/edit.html
Normal file
11
app/templates/users/fragments/edit.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends 'extends/offcanvas.html' %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}{% translate 'Edit user' %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<form hx-post="{% url 'user_edit' pk=user.id %}" hx-target="#generic-offcanvas" novalidate>
|
||||
{% crispy form %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
85
app/templates/users/fragments/list.html
Normal file
85
app/templates/users/fragments/list.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% load hijack %}
|
||||
{% load i18n %}
|
||||
<div class="container px-md-3 py-3 column-gap-5">
|
||||
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
|
||||
{% spaceless %}
|
||||
<div>{% translate 'Users' %}<span>
|
||||
<a class="text-decoration-none tw-text-2xl p-1 category-action"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Add" %}"
|
||||
hx-get="{% url 'user_add' %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
|
||||
</span></div>
|
||||
{% endspaceless %}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div id="tags-table">
|
||||
{% if users %}
|
||||
<div class="table-responsive">
|
||||
<c-config.search></c-config.search>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="col-auto"></th>
|
||||
<th scope="col" class="col">{% translate 'Active' %}</th>
|
||||
<th scope="col" class="col">{% translate 'Name' %}</th>
|
||||
<th scope="col" class="col">{% translate 'Email' %}</th>
|
||||
<th scope="col" class="col">{% translate 'Superuser' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr class="tag">
|
||||
<td class="col-auto">
|
||||
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
role="button"
|
||||
hx-swap="innerHTML"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Edit" %}"
|
||||
hx-get="{% url 'user_edit' pk=user.id %}"
|
||||
hx-target="#generic-offcanvas">
|
||||
<i class="fa-solid fa-pencil fa-fw"></i></a>
|
||||
{% if request.user|can_hijack:user and request.user != user %}
|
||||
<a class="btn btn-info btn-sm"
|
||||
role="button"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-title="{% translate "Impersonate" %}"
|
||||
hx-post="{% url 'hijack:acquire' %}"
|
||||
hx-vals='{"user_pk":"{{user.id}}"}'
|
||||
hx-swap="none"
|
||||
_="on htmx:afterRequest(event) from me
|
||||
if event.detail.successful
|
||||
go to url '/'">
|
||||
<i class="fa-solid fa-mask fa-fw"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="col">
|
||||
{% if user.is_active %}
|
||||
<i class="fa-solid fa-solid fa-check text-success"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="col">{{ user.first_name }} {{ user.last_name }}</td>
|
||||
<td class="col">{{ user.email }}</td>
|
||||
<td class="col">
|
||||
{% if user.is_superuser %}
|
||||
<i class="fa-solid fa-solid fa-check text-success"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<c-msg.empty title="{% translate "No users" %}" remove-padding></c-msg.empty>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 %}
|
||||
|
||||
8
app/templates/users/pages/index.html
Normal file
8
app/templates/users/pages/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% extends "layouts/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% translate 'Users' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div hx-get="{% url 'users_list' %}" hx-trigger="load, updated from:window" class="show-loading"></div>
|
||||
{% endblock %}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@ window.TomSelect = function createDynamicTomSelect(element) {
|
||||
// Basic configuration
|
||||
const config = {
|
||||
plugins: {},
|
||||
maxOptions: null,
|
||||
|
||||
// Extract 'create' option from data attribute
|
||||
create: element.dataset.create === 'true',
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
Django~=5.1
|
||||
psycopg[binary]==3.2.3
|
||||
python-webpack-boilerplate==1.0.3
|
||||
psycopg[binary]==3.2.6
|
||||
python-webpack-boilerplate==1.0.4
|
||||
django-crispy-forms==2.3
|
||||
crispy-bootstrap5==2024.10
|
||||
django-browser-reload==1.12.1
|
||||
django-hijack==3.4.5
|
||||
django-filter==24.3
|
||||
django-debug-toolbar==4.3.0
|
||||
django-cachalot~=2.6.3
|
||||
django-cotton~=1.2.1
|
||||
crispy-bootstrap5==2025.4
|
||||
django-browser-reload==1.18.0
|
||||
django-hijack==3.7.1
|
||||
django-filter==25.1
|
||||
django-debug-toolbar==4.4.6
|
||||
django-cachalot~=2.7.0
|
||||
django-cotton~=1.5.2
|
||||
django-pwa~=2.0.1
|
||||
djangorestframework~=3.15.2
|
||||
drf-spectacular~=0.27.2
|
||||
django-import-export~=4.3.5
|
||||
djangorestframework~=3.16.0
|
||||
drf-spectacular~=0.28.0
|
||||
django-import-export~=4.3.7
|
||||
|
||||
gunicorn==23.0.0
|
||||
whitenoise[brotli]==6.6.0
|
||||
whitenoise[brotli]==6.9.0
|
||||
|
||||
watchfiles==0.24.0 # https://github.com/samuelcolvin/watchfiles
|
||||
procrastinate[django]~=2.14
|
||||
procrastinate[django]~=2.15.1
|
||||
|
||||
requests~=2.32.3
|
||||
|
||||
pytz~=2024.2
|
||||
pytz
|
||||
python-dateutil~=2.9.0.post0
|
||||
simpleeval~=1.0.0
|
||||
pydantic~=2.10.5
|
||||
simpleeval~=1.0.3
|
||||
pydantic~=2.11.3
|
||||
PyYAML~=6.0.2
|
||||
mistune~=3.1.1
|
||||
openpyxl~=3.1
|
||||
xlrd~=2.0
|
||||
mistune~=3.1.3
|
||||
openpyxl~=3.1.5
|
||||
xlrd~=2.0.1
|
||||
|
||||
Reference in New Issue
Block a user