Compare commits

...
Author SHA1 Message Date
Lukas Bockstaller f1103856eb convert remaining parser usages as well 2026-05-11 08:40:24 +02:00
Lukas Bockstaller 6408db42e4 use datetime.fromisoformat instead of dateutil.parser 2026-05-11 08:33:55 +02:00
corentin-specandRaphael Michel 71edfa8e1a Translations: Update French
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-05-08 09:48:04 +02:00
Daniel MusketaandRaphael Michel 8303ba7808 Translations: Update German
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-05-08 09:48:04 +02:00
pajowuandGitHub 5bbbf0334d sendmail: Do not copy rules with subevent when closing an event (Z#23233683) (#6156) 2026-05-06 15:56:06 +02:00
sweenuandGitHub 14708eef80 Invoice: fix issuer details rendering when address missing (#6139) 2026-05-05 17:58:02 +02:00
Ruud HendrickxandRaphael Michel 952f121008 Translations: Update Dutch (Belgium)
Currently translated at 83.0% (5228 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl_BE/

powered by weblate
2026-05-05 17:36:25 +02:00
Ruud HendrickxandRaphael Michel 074d26cff3 Translations: Update Dutch
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2026-05-05 17:36:25 +02:00
Mie FrydensbjergandRaphael Michel 6a9815ea5f Translations: Update Danish
Currently translated at 58.4% (3677 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-05-05 17:36:25 +02:00
Daniel MusketaandRaphael Michel 01bd81a3cd Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-05-05 17:36:25 +02:00
Martin GrossandRaphael Michel 6ae8cfe6f0 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (256 of 256 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/de_Informal/

powered by weblate
2026-05-05 17:36:25 +02:00
Martin GrossandRaphael Michel b60c8165c2 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-05-05 17:36:25 +02:00
Daniel MusketaandRaphael Michel e460bf8bae Translations: Update Norwegian Bokmål
Currently translated at 83.3% (5247 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nb_NO/

powered by weblate
2026-05-05 17:36:25 +02:00
Daniel MusketaandRaphael Michel b4f3d5c435 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-05-05 17:36:25 +02:00
Daniel MusketaandRaphael Michel 4bc8caae73 Translations: Update German
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-05-05 17:36:25 +02:00
Paul BerschickandRaphael Michel 9183034c15 Translations: Update Spanish
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-05-05 17:36:25 +02:00
Paul BerschickandRaphael Michel 33ccd4342f Translations: Update Catalan
Currently translated at 29.7% (1875 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ca/

powered by weblate
2026-05-05 17:36:25 +02:00
Paul BerschickandRaphael Michel 301c47b761 Translations: Update Spanish
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-05-05 17:36:25 +02:00
CVZ-esandRaphael Michel b0d1c93fd9 Translations: Update Spanish
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-05-05 17:36:25 +02:00
CVZ-esandRaphael Michel 70d59a960c Translations: Update French
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2026-05-05 17:36:25 +02:00
Daniel MusketaandGitHub e87b030427 Stripe: Add missing word in help text (#6146) 2026-05-05 17:15:34 +02:00
Daniel MusketaandGitHub 994e4b410a Fix gettext singular forms in cart error_messages (#6147) 2026-05-05 17:15:14 +02:00
Daniel MusketaandGitHub bd6abbc280 Docs: Update link to Django style guide (#6140) 2026-05-05 17:14:22 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ca7c982abd Bump @babel/preset-env from 7.29.0 to 7.29.3 in /src/pretix/static/npm_dir (#6136)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.29.0 to 7.29.3.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.3/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-version: 7.29.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 17:13:40 +02:00
Raphael MichelandGitHub 6010d7f9e5 Order details: Link to subevent details (Z#23227664) (#6148) 2026-05-05 14:56:02 +02:00
Richard SchreiberandGitHub ac08359a0e Widget: Raise BadRequest when GET-offset is not an int (#6143) 2026-05-04 16:19:02 +02:00
0aee73a9bd Quotas: Add bulk-edit, bulk-delete and filter form (#6080)
* Quotas: Add bulk-edit, bulk-delete and filter form

* Fix GroupConcat

* Apply suggestions from code review

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>

* Review notes

* Fix handling of required fields

---------

Co-authored-by: Richard Schreiber <wiffbi@gmail.com>
2026-05-04 12:44:22 +02:00
luelistaandGitHub 27183a26ee Respect per-event plugin availability in OrganizerPluginEvents view (#5983)
* Allow plugins to declare their availability per event

* Fix message type

* small optimization of PluginsField serializer
2026-05-04 11:34:05 +02:00
Thomas GöttgensandGitHub 0acaed41be Fix Dockerfile syntax for chmod command (#6145) 2026-05-04 11:23:44 +02:00
Raphael MichelandGitHub 993acce05a Settings: Fix typo in class path to mail backend (#6144) 2026-05-04 11:22:47 +02:00
luelistaandGitHub fe2132435c Fix permissions of /pretix in docker container (#6133) 2026-05-04 11:13:38 +02:00
Raphael MichelandGitHub f4fcca19a4 Orders API: Fix race condition in voucher redemption (Z#23230391) (#6067)
The old code relied on the `Voucher.redeemed` value obtained *before*
the lock was taken, not afterwards.

The change in services/orders.py is functionally pointless, but it makes
the pattern of "fill availability only after lock" clearer and might
avoid introducing similar bugs in the future.
2026-04-29 19:57:08 +02:00
Raphael MichelandGitHub 24d26a9455 Badges: Add export layout for 4x3" on letter (Z#23232464) (#6128)
* Badges: Add export layout for 4x3" on letter (Z#23232464)

* Consistent naming
2026-04-29 15:31:54 +02:00
Phin WolkwitzandGitHub 589f51454e Add locations to program times (Z#23221129)
Add location for program time slots and extend .ical and PDF placeholder
2026-04-29 11:59:06 +02:00
Raphael Michel bda27d72e7 Bump version to 2026.5.0.dev0 2026-04-28 16:48:33 +02:00
Raphael Michel f67690bc56 Bump version to 2025.5.0.dev0 2026-04-28 16:47:51 +02:00
Raphael Michel 75c8f97080 Bump version to 2026.4.0 2026-04-28 16:47:33 +02:00
Raphael Michel 10789f097d Bump version to 2025.5.0.dev0 2026-04-28 16:39:29 +02:00
Raphael Michel 1adec102e6 Bump version to 2025.4.0 2026-04-28 16:39:24 +02:00
Raphael MichelandGitHub 921fd801e5 Thumbnails: Perform color space transform before resizing (Z#23232101) (#6120) 2026-04-28 15:35:27 +02:00
Kara Engelhardtandpajowu 448d2e70d5 AddOnsStep: Expand selected variants 2026-04-28 14:50:35 +02:00
Kara Engelhardtandpajowu 49f692c666 AddOnsStep: Use post data as initial data if exists (Z#23232311) 2026-04-28 14:50:35 +02:00
Kara Engelhardtandpajowu 2d31c62812 Allow dash character in pdf placeholders 2026-04-28 13:10:08 +02:00
Raphael MichelandRaphael Michel 08df3d828d Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2026-04-28 12:20:37 +02:00
Raphael MichelandRaphael Michel 96e10bcd71 Translations: Update German
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2026-04-28 12:20:37 +02:00
Raphael Michel ff434f4384 Translations: Update wordlist 2026-04-28 12:17:11 +02:00
dependabot[bot]andRaphael Michel 653f83fc90 Update cryptography requirement from >=46.0.7 to >=47.0.0
Updates the requirements on [cryptography](https://github.com/pyca/cryptography) to permit the latest version.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/46.0.7...47.0.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 47.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-28 11:22:54 +02:00
Raphael Michel d6fe29210a Update po files
[CI skip]

Signed-off-by: Raphael Michel <michel@pretix.eu>
2026-04-28 11:04:18 +02:00
NikolaiandRaphael Michel a13bb630d5 Translations: Update Danish
Currently translated at 58.4% (3676 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel fd0b3bac3c Translations: Update Danish
Currently translated at 58.9% (151 of 256 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/da/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel 7f6b5d7331 Translations: Update Danish
Currently translated at 56.3% (3542 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel 27398c08c7 Translations: Update Danish
Currently translated at 54.5% (3428 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
Sandra Rial PérezandRaphael Michel c061179f37 Translations: Update Galician
Currently translated at 19.1% (1207 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/gl/

powered by weblate
2026-04-28 11:03:23 +02:00
Sandra Rial PérezandRaphael Michel bd90badc54 Translations: Update Galician
Currently translated at 19.0% (1196 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/gl/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel 90800f219b Translations: Update Danish
Currently translated at 54.3% (3414 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
Sandra Rial PérezandRaphael Michel 4767cb38fc Translations: Update Galician
Currently translated at 17.6% (1111 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/gl/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel 8fd366be76 Translations: Update Danish
Currently translated at 52.2% (3284 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
NikolaiandRaphael Michel 75660600f4 Translations: Update Danish
Currently translated at 50.1% (3153 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-28 11:03:23 +02:00
Richard SchreiberandGitHub 217744a9f2 Remove unused download of all tickets of an order in pretix-control (#6086)
* Remove unused code for ticket download of whole order in pretix-control

* fix flake8

* fix isort
2026-04-28 09:45:35 +02:00
Richard SchreiberandGitHub 1c7ce4b1ca Validate id for async tasks 2026-04-28 08:56:32 +02:00
Raphael MichelandGitHub 8426a68760 Prevent nullbytes in input data globally (#6071)
* Prevent nullbytes in input data globally

* Only on urlencoded POST

* Split middleware
2026-04-27 17:28:36 +02:00
Raphael MichelandGitHub 1157e2aeed Events/subevents: Fix missing logging for meta changes (Z#23232443) (#6110)
* Events/subevents: Fix missing logging for meta changes (Z#23232443)

* Fix logging
2026-04-27 15:12:21 +02:00
771f4f5d1e Turn attendee emails on by default for new events (Z#23213656) (#5598)
* Turn attendee emails on by default for new events (Z#23213656)

I think the thing that makes me most unhappy is that *most* organizers will
probably want to turn off mail_send_order_paid_attendee when they set
ticket_download_pending and I don't think organizers will remember that, but
it also seems complex and weird to create an automatism for it?

* Update src/pretix/base/models/event.py

Co-authored-by: Martin Gross <gross@rami.io>

---------

Co-authored-by: Martin Gross <gross@rami.io>
2026-04-27 15:00:48 +02:00
Raphael MichelandGitHub 496591bb3b Navigation: suggest event or organizer by domain (Z#23231404) (#6107) 2026-04-27 14:55:59 +02:00
88165c098e Subevents: Allow to skip conflicting dates in bulk-creation (Z#23217384) (#6079)
* Subevents: Allow to skip conflicting dates in bulk-creation

* Update src/pretix/control/templates/pretixcontrol/subevents/bulk.html

* Fix overlap calc for consecutive subevents

* Add test for skipping conflicting dates in bulk-creation

---------

Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
Co-authored-by: Richard Schreiber <schreiber@rami.io>
Co-authored-by: Kara Engelhardt <engelhardt@pretix.eu>
2026-04-27 14:52:49 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
82a14a4f83 Update pytest-asyncio requirement from >=0.24 to >=1.3.0 (#6108)
Updates the requirements on [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.24.0...v1.3.0)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-version: 1.3.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-27 12:39:36 +02:00
Kara Engelhardtandpajowu ff77a2125a Limit widget frame inner height to 100dvh (Z#23231969)
Fixes a bug where the submit buttons were obscured by the browsers elements on some ios devices
2026-04-27 12:38:32 +02:00
Raphael MichelandGitHub 97904d8567 Backend: Support are-you-sure for dynamically added form parts (Z#23232506) (#6109) 2026-04-27 12:24:55 +02:00
Raphael MichelandGitHub a6a9eb6a6a Subevent selection: Order by date before name (Z#23231460) (#6111) 2026-04-27 12:23:17 +02:00
Raphael MichelandGitHub b000dff134 Invoices: Allow to use currency rates from National Bank of Poland (#6100) 2026-04-21 15:14:10 +02:00
Kara Engelhardtandpajowu ba75de7e7d Handle existing cart with empty session in presale views (PRETIXEU-D9Y) 2026-04-21 13:05:42 +02:00
Raphael MichelandGitHub 35e1df28d9 Overhaul contribution guide & add a AI policy (#6038)
* Overhaul contribution guide & add a AI policy

* Fix broken links
2026-04-21 11:32:56 +02:00
Martin GrossandMartin Gross 7e457f7430 Set max_length to 70 but for all name fields together and not only every single one. 2026-04-21 10:45:00 +02:00
Martin GrossandMartin Gross 5faa85ed40 isort 2026-04-21 10:45:00 +02:00
Martin GrossandMartin Gross 1b88a84a83 Move validation into form field. 2026-04-21 10:45:00 +02:00
Martin GrossandMartin Gross 447cffa7a8 Customer Accounts: Limit length; reject URLs in name 2026-04-21 10:45:00 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6d255bb9cc Update defusedcsv requirement from >=1.1.0 to >=3.0.0 (#6105)
Updates the requirements on [defusedcsv](https://github.com/raphaelm/defusedcsv) to permit the latest version.
- [Commits](https://github.com/raphaelm/defusedcsv/compare/v1.1.0...v3.0.0)

---
updated-dependencies:
- dependency-name: defusedcsv
  dependency-version: 3.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 23:50:50 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4fe405886e Update tlds requirement from >=2026021400 to >=2026041800 (#6104)
Updates the requirements on [tlds](https://github.com/kichik/tlds) to permit the latest version.
- [Commits](https://github.com/kichik/tlds/commits)

---
updated-dependencies:
- dependency-name: tlds
  dependency-version: '2026041800'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 22:44:03 +02:00
Richard SchreiberandGitHub b7d3e8a80a Add invoice numbers to paymentlist export (Z#23227966) (#6097) 2026-04-20 17:55:44 +02:00
Raphael MichelandGitHub d0d76ffddc Delete unused code (#6026)
* Delete unused code

* Delete template
2026-04-20 16:56:50 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c04be5c0d9 Update cryptography requirement from >=44.0.0 to >=46.0.7 (#6084)
Updates the requirements on [cryptography](https://github.com/pyca/cryptography) to permit the latest version.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/44.0.0...46.0.7)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 46.0.7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 15:09:49 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ee1a8420a5 Update sentry-sdk requirement from ==2.57.* to ==2.58.* (#6095)
Updates the requirements on [sentry-sdk](https://github.com/getsentry/sentry-python) to permit the latest version.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.57.0...2.58.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.58.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 15:09:33 +02:00
dependabot[bot]andGitHub d9000c2a66 Update tlds requirement from >=2020041600 to >=2026021400 (#6088) 2026-04-20 15:09:04 +02:00
Yasunobu YesNo KawaguchiandRaphael Michel 4530d864d3 Translations: Update Japanese
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-04-20 10:09:50 +02:00
Yasunobu YesNo KawaguchiandRaphael Michel b968266611 Translations: Update Japanese
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-04-20 10:09:50 +02:00
Yasunobu YesNo KawaguchiandRaphael Michel 640518c1b3 Translations: Update Japanese
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-04-20 10:09:50 +02:00
NikolaiandRaphael Michel 0715144a31 Translations: Update Danish
Currently translated at 48.5% (3055 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-20 10:09:50 +02:00
TimandRaphael Michel 58ea7c8656 Translations: Update Spanish
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-04-20 10:09:50 +02:00
TimandRaphael Michel a8fe6f505e Translations: Update Spanish
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-04-20 10:09:50 +02:00
NikolaiandRaphael Michel baeec92203 Translations: Update Danish
Currently translated at 47.7% (3004 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-20 10:09:50 +02:00
TimandRaphael Michel 2f9ac05184 Translations: Update Spanish
Currently translated at 100.0% (6287 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/es/

powered by weblate
2026-04-20 10:09:50 +02:00
Mie FrydensbjergandMartin Gross 4beea63b49 Translations: Update Danish
Currently translated at 46.5% (2925 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-16 11:01:56 +02:00
NikolaiandMartin Gross 5e49df0ef6 Translations: Update Danish
Currently translated at 46.1% (2904 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-16 11:01:56 +02:00
pajowuandMartin Gross b3bb9fccb5 Translations: Update Danish
Currently translated at 44.2% (2784 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-16 11:01:56 +02:00
Lukas BockstallerandGitHub e3ffd66691 Giftcard/Reusable Media API: fix expand permission check (Z#23230608) (#6091)
* add failing tests

* add permission checks in to_representation

* only overwrite final representation not the serializer

* styling

* include review
2026-04-15 15:59:08 +02:00
Martin Gross 0f2ebb8687 PPv2: Fix permission-check for ISU (event.settings.general:write to event.settings.payment:write) 2026-04-14 17:02:47 +02:00
Richard Schreiber efd887b439 API: fix PDF-download name (Z#23231496) 2026-04-14 14:13:14 +02:00
pajowuandGitHub 8690d65e99 Do not show payment text of canceled and failed payments on invoice (Z#23231070) (#6075) 2026-04-14 13:02:12 +02:00
5682d3ed56 Do not force PDFs to be downloaded (Z#23225892) (#5994)
* Display invoice and tickets inline in browser (Z#23225892)

* Use FileResponse filename for AnswerDownload

* Use inline for PDF-view in pretix-control editor

* use as_attachment for API FileResponses

* do not ignore csp even for disposition=inline

* use as_attachment for file responses in control

* remove unused code

* improve code style

* Invoice preview inline

* do not force download on tickets in backend

* do not force download on AnswerDownload

* imrpove code style

* improve code style

* fix missing int str conversion

* Apply suggestions from code review

Co-authored-by: luelista <mira@teamwiki.de>

---------

Co-authored-by: luelista <mira@teamwiki.de>
2026-04-14 09:12:09 +02:00
pajowuandGitHub 059ff6c99b Allow buttons to reuse cart (Z#23226853) (#6047)
* Allow buttons to reuse cart (Z#23226853)

* Always keep cart of buttons with items set
2026-04-13 19:32:33 +02:00
Mie FrydensbjergandMartin Gross f46fc7fa69 Translations: Update Danish
Currently translated at 44.2% (2784 of 6287 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-04-13 16:02:34 +02:00
194 changed files with 66575 additions and 62473 deletions
+10 -5
View File
@@ -1,11 +1,16 @@
Contributing to pretix Contributing to pretix
====================== ======================
Hey there and welcome to pretix! Welcome to pretix, we are happy that you would like to contribute.
Before you do so, please make sure to read the following documents:
* We've got a contributors guide in [our documentation](https://docs.pretix.eu/dev/development/contribution/) together with notes on the [development setup](https://docs.pretix.eu/dev/development/setup.html). - [Contribution workflow](https://docs.pretix.eu/dev/development/contribution/general.html)
- [AI-assisted contribution policy](https://docs.pretix.eu/dev/development/contribution/ai.html)
- [Coding style and quality](https://docs.pretix.eu/dev/development/contribution/style.html)
- [Development setup](https://docs.pretix.eu/dev/development/setup.html)
- [Code of Conduct](https://docs.pretix.eu/dev/development/contribution/codeofconduct.html)
* Please note that we have a [Code of Conduct](https://docs.pretix.eu/dev/development/contribution/codeofconduct.html) in place that applies to all project contributions, including issues, pull requests, etc. Before we can accept your first PR we'll need you to sign [our **Contributor License Agreement** (CLA)](https://pretix.eu/about/en/cla).
You can find more information about the how and why in our [License FAQ](https://docs.pretix.eu/trust/licensing/faq/) and in our [license change blog post](https://pretix.eu/about/en/blog/20210412-license/).
* Before we can accept a PR from you we'll need you to sign [our CLA](https://pretix.eu/about/en/cla). You can find more information about the how and why in our [License FAQ](https://docs.pretix.eu/trust/licensing/faq/) and in our [license change blog post](https://pretix.eu/about/en/blog/20210412-license/).
**Before contributing new functionality, always open a discussion first.**
+1
View File
@@ -31,6 +31,7 @@ RUN apt-get update && \
mkdir /etc/pretix && \ mkdir /etc/pretix && \
mkdir /data && \ mkdir /data && \
useradd -ms /bin/bash -d /pretix -u 15371 pretixuser && \ useradd -ms /bin/bash -d /pretix -u 15371 pretixuser && \
chmod 0755 /pretix && \
echo 'pretixuser ALL=(ALL) NOPASSWD:SETENV: /usr/bin/supervisord' >> /etc/sudoers && \ echo 'pretixuser ALL=(ALL) NOPASSWD:SETENV: /usr/bin/supervisord' >> /etc/sudoers && \
mkdir /static && \ mkdir /static && \
mkdir /etc/supervisord mkdir /etc/supervisord
+13 -6
View File
@@ -16,6 +16,7 @@ Field Type Description
id integer Internal ID of the program time id integer Internal ID of the program time
start datetime The start date time for this program time slot. start datetime The start date time for this program time slot.
end datetime The end date time for this program time slot. end datetime The end date time for this program time slot.
location multi-lingual string The program time slot's location (or ``null``)
===================================== ========================== ======================================================= ===================================== ========================== =======================================================
.. versionchanged:: TODO .. versionchanged:: TODO
@@ -54,17 +55,20 @@ Endpoints
{ {
"id": 2, "id": 2,
"start": "2025-08-14T22:00:00Z", "start": "2025-08-14T22:00:00Z",
"end": "2025-08-15T00:00:00Z" "end": "2025-08-15T00:00:00Z",
"location": null
}, },
{ {
"id": 3, "id": 3,
"start": "2025-08-12T22:00:00Z", "start": "2025-08-12T22:00:00Z",
"end": "2025-08-13T22:00:00Z" "end": "2025-08-13T22:00:00Z",
"location": null
}, },
{ {
"id": 14, "id": 14,
"start": "2025-08-15T22:00:00Z", "start": "2025-08-15T22:00:00Z",
"end": "2025-08-17T22:00:00Z" "end": "2025-08-17T22:00:00Z",
"location": null
} }
] ]
} }
@@ -99,7 +103,8 @@ Endpoints
{ {
"id": 1, "id": 1,
"start": "2025-08-15T22:00:00Z", "start": "2025-08-15T22:00:00Z",
"end": "2025-10-27T23:00:00Z" "end": "2025-10-27T23:00:00Z",
"location": null
} }
:param organizer: The ``slug`` field of the organizer to fetch :param organizer: The ``slug`` field of the organizer to fetch
@@ -125,7 +130,8 @@ Endpoints
{ {
"start": "2025-08-15T10:00:00Z", "start": "2025-08-15T10:00:00Z",
"end": "2025-08-15T22:00:00Z" "end": "2025-08-15T22:00:00Z",
"location": null
} }
**Example response**: **Example response**:
@@ -139,7 +145,8 @@ Endpoints
{ {
"id": 17, "id": 17,
"start": "2025-08-15T10:00:00Z", "start": "2025-08-15T10:00:00Z",
"end": "2025-08-15T22:00:00Z" "end": "2025-08-15T22:00:00Z",
"location": null
} }
:param organizer: The ``slug`` field of the organizer of the event/item to create a program time for :param organizer: The ``slug`` field of the organizer of the event/item to create a program time for
+24
View File
@@ -0,0 +1,24 @@
.. _`aipolicy`:
AI-assisted contribution policy
===============================
pretix is maintained by humans.
Every discussion, issue, and pull request is read and reviewed by humans (and sometimes machines, too).
We ask you to respect the time and effort put in by these humans by not sending low-effort, unqualified work, since it puts the burden of validation on the maintainer.
Therefore, the pretix project has strict rules for AI usage:
- **All AI usage in any form must be disclosed.** You must state the tool you used (e.g. Claude Code, Cursor, Amp) along with the extent that the work was AI-assisted.
- **The human-in-the-loop must fully understand all code.** If you can't explain what your changes do and how they interact with the greater system without the aid of AI tools, do not contribute to this project.
- **Issues and discussions can use AI assistance but must have a full human-in-the-loop.** This means that any content generated with AI must have been reviewed and edited by a human before submission. AI is very good at being overly verbose and including noise that distracts from the main point. Humans must do their research and trim this down.
- **No AI-generated media is allowed (art, images, videos, audio, etc.).** Text and code are the only acceptable AI-generated content, per the other rules in this policy.
- **Bad AI drivers will be excluded from the project.** People who produce bad contributions that are clearly AI (slop) will be blocked from our organization without warning.
This policy was inspired by the `ghostty project`_.
.. _ghostty project: https://github.com/ghostty-org/ghostty/blob/main/AI_POLICY.md
+30 -11
View File
@@ -1,23 +1,39 @@
General remarks Contribution workflow
=============== =====================
You are interested in contributing to pretix? That is awesome! You are interested in contributing to pretix? That is awesome!
If youre new to contributing to open source software, dont be afraid. Well happily review your code and give you If youre new to contributing to open source software, dont be afraid. Well happily review your code and give you
constructive and friendly feedback on your changes. constructive and friendly feedback on your changes. Every contribution should go through the following steps.
First of all, you'll need pretix running locally on your machine. Head over to :ref:`devsetup` to learn how to do this. Discussion & Design
-------------------
pretix is a large and mature project with more of a decade of history and hopefully many more decades to come.
Keeping pretix in good shape over long timeframes is first and foremost a fight against complexity.
With every additional feature, complexity grows, and both features and complexity are hard to remove.
Even if you are doing the initial work of the contribution, accepting the contribution is not free for us.
Not only will we need to maintain the feature, but every feature adds cost to the maintenance of every other feature it interacts with, and every feature adds effort for users to understand how pretix works.
Therefore, we must carefully select what features we add, based on how well they fit the system in general and of how much use they will be to our larger user base.
We strongly ask you to **create a discussion on GitHub for every new feature idea** outlining the use case and the proposed implementation design.
Pull requests without prior discussion will likely just be closed.
For bug fixes and very minor changes, you can skip this step and open a PR right away.
Development
-----------
To develop your contribution, you'll need pretix running locally on your machine. Head over to :ref:`devsetup` to learn how to do this.
If you run into any problems on your way, please do not hesitate to ask us anytime! If you run into any problems on your way, please do not hesitate to ask us anytime!
Please note that we bound ourselves to a :ref:`coc` that applies to all communication around the project. You can be While developing, please have a look at our :ref:`aipolicy` and our guidelines on :ref:`codestyle`.
assured that we will not tolerate any form of harassment.
Sending a patch Sending a patch
--------------- ---------------
If you improved pretix in any way, we'd be very happy if you contribute it Once you have a first draft of your changes, please `create a pull request`_ on our `GitHub repository`_.
back to the main code base! The easiest way to do so is to `create a pull request`_
on our `GitHub repository`_.
We recommend that you create a feature branch for every issue you work on so the changes can We recommend that you create a feature branch for every issue you work on so the changes can
be reviewed individually. be reviewed individually.
@@ -25,14 +41,17 @@ Please use the test suite to check whether your changes break any existing featu
the code style checks to confirm you are consistent with pretix's coding style. You'll the code style checks to confirm you are consistent with pretix's coding style. You'll
find instructions on this in the :ref:`checksandtests` section of the development setup guide. find instructions on this in the :ref:`checksandtests` section of the development setup guide.
We automatically run the tests and the code style check on every pull request on Travis CI and we wont We automatically run the tests and the code style check on every pull request through GitHub Actions and we wont
accept any pull requests without all tests passing. However, if you don't find out *why* they are not passing, accept any pull requests without all tests passing. However, if you don't find out *why* they are not passing,
just send the pull request and tell us we'll be glad to help. just send the pull request and tell us we'll be glad to help.
If you add a new feature, please include appropriate documentation into your patch. If you fix a bug, If you add a new feature, please include appropriate documentation into your patch. If you fix a bug,
please include a regression test, i.e. a test that fails without your changes and passes after applying your changes. please include a regression test, i.e. a test that fails without your changes and passes after applying your changes.
Again: If you get stuck, do not hesitate to contact any of us, or Raphael personally at mail@raphaelmichel.de. Again: If you get stuck, do not hesitate to contact us through GitHub discussions.
Please note that we bound ourselves to a :ref:`coc` that applies to all communication around the project. You can be
assured that we will not tolerate any form of harassment.
.. _create a pull request: https://help.github.com/articles/creating-a-pull-request/ .. _create a pull request: https://help.github.com/articles/creating-a-pull-request/
.. _GitHub repository: https://github.com/pretix/pretix .. _GitHub repository: https://github.com/pretix/pretix
+1
View File
@@ -6,4 +6,5 @@ Contributing to pretix
general general
style style
ai
codeofconduct codeofconduct
+4 -4
View File
@@ -1,5 +1,7 @@
.. spelling:word-list:: Rebase rebasing .. spelling:word-list:: Rebase rebasing
.. _`codestyle`:
Coding style and quality Coding style and quality
======================== ========================
@@ -28,8 +30,6 @@ Code
Commits and Pull Requests Commits and Pull Requests
------------------------- -------------------------
Most commits should start as pull requests, therefore this applies to the titles of pull requests as well since Most commits should start as pull requests, therefore this applies to the titles of pull requests as well since
the pull request title will become the commit message on merge. We prefer merging with GitHub's "Squash and merge" the pull request title will become the commit message on merge. We prefer merging with GitHub's "Squash and merge"
feature if the PR contains multiple commits that do not carry value to keep. If there is value in keeping the feature if the PR contains multiple commits that do not carry value to keep. If there is value in keeping the
@@ -86,7 +86,7 @@ individual commits, we use "Rebase and merge" instead. Merge commits should be a
.. _PEP 8: https://legacy.python.org/dev/peps/pep-0008/ .. _PEP 8: https://legacy.python.org/dev/peps/pep-0008/
.. _flake8: https://pypi.python.org/pypi/flake8 .. _flake8: https://pypi.python.org/pypi/flake8
.. _Django Coding Style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/ .. _Django Coding Style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
.. _translation: https://docs.djangoproject.com/en/1.11/topics/i18n/translation/ .. _translation: https://docs.djangoproject.com/en/6.0/topics/i18n/translation/
.. _class-based views: https://docs.djangoproject.com/en/1.11/topics/class-based-views/ .. _class-based views: https://docs.djangoproject.com/en/6.0/topics/class-based-views/
.. _pytest-style: https://docs.pytest.org/en/latest/assert.html .. _pytest-style: https://docs.pytest.org/en/latest/assert.html
.. _fixtures: https://docs.pytest.org/en/latest/fixture.html .. _fixtures: https://docs.pytest.org/en/latest/fixture.html
+5 -5
View File
@@ -33,9 +33,9 @@ dependencies = [
"bleach==6.3.*", "bleach==6.3.*",
"celery==5.6.*", "celery==5.6.*",
"chardet==5.2.*", "chardet==5.2.*",
"cryptography>=44.0.0", "cryptography>=47.0.0",
"css-inline==0.20.*", "css-inline==0.20.*",
"defusedcsv>=1.1.0", "defusedcsv>=3.0.0",
"dnspython==2.*", "dnspython==2.*",
"Django[argon2]==5.2.*", "Django[argon2]==5.2.*",
"django-bootstrap3==26.1", "django-bootstrap3==26.1",
@@ -93,11 +93,11 @@ dependencies = [
"redis==7.4.*", "redis==7.4.*",
"reportlab==4.4.*", "reportlab==4.4.*",
"requests==2.32.*", "requests==2.32.*",
"sentry-sdk==2.57.*", "sentry-sdk==2.58.*",
"sepaxml==2.7.*", "sepaxml==2.7.*",
"stripe==7.9.*", "stripe==7.9.*",
"text-unidecode==1.*", "text-unidecode==1.*",
"tlds>=2020041600", "tlds>=2026041800",
"tqdm==4.*", "tqdm==4.*",
"ua-parser==1.0.*", "ua-parser==1.0.*",
"vobject==0.9.*", "vobject==0.9.*",
@@ -117,7 +117,7 @@ dev = [
"isort==8.0.*", "isort==8.0.*",
"pep8-naming==0.15.*", "pep8-naming==0.15.*",
"potypo", "potypo",
"pytest-asyncio>=0.24", "pytest-asyncio>=1.3.0",
"pytest-cache", "pytest-cache",
"pytest-cov", "pytest-cov",
"pytest-django==4.*", "pytest-django==4.*",
+1 -1
View File
@@ -19,4 +19,4 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
__version__ = "2026.4.0.dev0" __version__ = "2026.5.0.dev0"
+2 -2
View File
@@ -115,10 +115,10 @@ class PluginsField(serializers.Field):
def to_representation(self, obj): def to_representation(self, obj):
from pretix.base.plugins import get_all_plugins from pretix.base.plugins import get_all_plugins
active_plugins = set(obj.get_plugins())
return sorted([ return sorted([
p.module for p in get_all_plugins() p.module for p in get_all_plugins()
if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in obj.get_plugins() if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in active_plugins
]) ])
def to_internal_value(self, data): def to_internal_value(self, data):
+2 -2
View File
@@ -191,7 +191,7 @@ class InlineItemAddOnSerializer(serializers.ModelSerializer):
class InlineItemProgramTimeSerializer(serializers.ModelSerializer): class InlineItemProgramTimeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ItemProgramTime model = ItemProgramTime
fields = ('start', 'end') fields = ('start', 'end', 'location')
class ItemBundleSerializer(serializers.ModelSerializer): class ItemBundleSerializer(serializers.ModelSerializer):
@@ -222,7 +222,7 @@ class ItemBundleSerializer(serializers.ModelSerializer):
class ItemProgramTimeSerializer(serializers.ModelSerializer): class ItemProgramTimeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ItemProgramTime model = ItemProgramTime
fields = ('id', 'start', 'end') fields = ('id', 'start', 'end', 'location')
def validate(self, data): def validate(self, data):
data = super().validate(data) data = super().validate(data)
+25 -3
View File
@@ -31,7 +31,9 @@ from pretix.api.serializers.order import OrderPositionSerializer
from pretix.api.serializers.organizer import ( from pretix.api.serializers.organizer import (
CustomerSerializer, GiftCardSerializer, CustomerSerializer, GiftCardSerializer,
) )
from pretix.base.models import Order, OrderPosition, ReusableMedium from pretix.base.models import (
Device, Order, OrderPosition, ReusableMedium, TeamAPIToken,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -80,8 +82,7 @@ class ReusableMediaSerializer(I18nAwareModelSerializer):
) )
if 'linked_orderposition' in self.context['request'].query_params.getlist('expand'): if 'linked_orderposition' in self.context['request'].query_params.getlist('expand'):
# No additional permission check performed, documented limitation of the permission system # Permission Check performed in to_representation
# Would get to complex/unusable otherwise since the permission depends on the event
self.fields['linked_orderposition'] = NestedOrderPositionSerializer(read_only=True) self.fields['linked_orderposition'] = NestedOrderPositionSerializer(read_only=True)
else: else:
self.fields['linked_orderposition'] = serializers.PrimaryKeyRelatedField( self.fields['linked_orderposition'] = serializers.PrimaryKeyRelatedField(
@@ -117,6 +118,27 @@ class ReusableMediaSerializer(I18nAwareModelSerializer):
) )
return data return data
def to_representation(self, instance):
r = super().to_representation(instance)
request = self.context.get('request')
# late permission evaluations for checks that depend on the actual linked events
expand_nested = self.context['request'].query_params.getlist('expand')
perm_holder = request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user
if 'linked_orderposition' in expand_nested:
if instance.linked_orderposition is not None:
event = instance.linked_orderposition.order.event
if not perm_holder.has_event_permission(event.organizer, event, 'event.orders:read', request):
r['linked_orderposition'] = {'id': instance.linked_orderposition.id}
if 'linked_giftcard.owner_ticket' in expand_nested:
gc = instance.linked_giftcard
if gc is not None and gc.owner_ticket is not None:
event = gc.owner_ticket.order.event
if not perm_holder.has_event_permission(event.organizer, event, 'event.orders:read', request):
r['linked_giftcard']['owner_ticket'] = {'id': instance.linked_giftcard.owner_ticket.id}
return r
class Meta: class Meta:
model = ReusableMedium model = ReusableMedium
fields = ( fields = (
+8 -5
View File
@@ -1416,6 +1416,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
qa = QuotaAvailability() qa = QuotaAvailability()
qa.queue(*[q for q, d in quota_diff_for_locking.items() if d > 0]) qa.queue(*[q for q, d in quota_diff_for_locking.items() if d > 0])
qa.compute() qa.compute()
v_avail = {}
# These are not technically correct as diff use due to the time offset applied above, so let's prevent accidental # These are not technically correct as diff use due to the time offset applied above, so let's prevent accidental
# use further down # use further down
@@ -1445,11 +1446,13 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
voucher_usage[v] += 1 voucher_usage[v] += 1
if voucher_usage[v] > 0: if voucher_usage[v] > 0:
redeemed_in_carts = CartPosition.objects.filter( if v not in v_avail:
Q(voucher=pos_data['voucher']) & Q(event=self.context['event']) & Q(expires__gte=now_dt) v.refresh_from_db(fields=['redeemed'])
).exclude(pk__in=[cp.pk for cp in delete_cps]) redeemed_in_carts = CartPosition.objects.filter(
v_avail = v.max_usages - v.redeemed - redeemed_in_carts.count() Q(voucher=v) & Q(event=self.context['event']) & Q(expires__gte=now_dt)
if v_avail < voucher_usage[v]: ).exclude(pk__in=[cp.pk for cp in delete_cps])
v_avail[v] = v.max_usages - v.redeemed - redeemed_in_carts.count()
if v_avail[v] < voucher_usage[v]:
errs[i]['voucher'] = [ errs[i]['voucher'] = [
'The voucher has already been used the maximum number of times.' 'The voucher has already been used the maximum number of times.'
] ]
+13
View File
@@ -286,6 +286,19 @@ class GiftCardSerializer(I18nAwareModelSerializer):
) )
return data return data
def to_representation(self, instance):
r = super().to_representation(instance)
request = self.context.get('request')
# late permission evaluations for checks that depend on the actual linked events
if 'owner_ticket' in self.context['request'].query_params.getlist('expand'):
owner_ticket = instance.owner_ticket
if owner_ticket:
event = owner_ticket.order.event
perm_holder = request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user
if not perm_holder.has_event_permission(event.organizer, event, 'event.orders:read', request):
r['owner_ticket'] = {'id': instance.owner_ticket.id}
return r
class Meta: class Meta:
model = GiftCard model = GiftCard
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions', 'owner_ticket', fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions', 'owner_ticket',
+43 -28
View File
@@ -381,12 +381,15 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
resp = HttpResponse(ct.file.file.read(), content_type='text/uri-list') resp = HttpResponse(ct.file.file.read(), content_type='text/uri-list')
return resp return resp
else: else:
resp = FileResponse(ct.file.file, content_type=ct.type) return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format( ct.file.file,
self.request.event.slug.upper(), order.code, filename='{}-{}-{}{}'.format(
provider.identifier, ct.extension self.request.event.slug.upper(), order.code,
provider.identifier, ct.extension
),
as_attachment=True,
content_type=ct.type
) )
return resp
@action(detail=True, methods=['POST']) @action(detail=True, methods=['POST'])
def mark_paid(self, request, **kwargs): def mark_paid(self, request, **kwargs):
@@ -1303,14 +1306,17 @@ class EventOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ModelViewSet
raise NotFound() raise NotFound()
ftype, ignored = mimetypes.guess_type(answer.file.name) ftype, ignored = mimetypes.guess_type(answer.file.name)
resp = FileResponse(answer.file, content_type=ftype or 'application/binary') return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}"'.format( answer.file,
self.request.event.slug.upper(), filename='{}-{}-{}-{}'.format(
pos.order.code, self.request.event.slug.upper(),
pos.positionid, pos.order.code,
os.path.basename(answer.file.name).split('.', 1)[1] pos.positionid,
os.path.basename(answer.file.name).split('.', 1)[1]
),
as_attachment=True,
content_type=ftype or 'application/binary'
) )
return resp
@action(detail=True, url_name="printlog", url_path="printlog", methods=["POST"]) @action(detail=True, url_name="printlog", url_path="printlog", methods=["POST"])
def printlog(self, request, **kwargs): def printlog(self, request, **kwargs):
@@ -1365,15 +1371,18 @@ class EventOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ModelViewSet
if hasattr(image_file, 'seek'): if hasattr(image_file, 'seek'):
image_file.seek(0) image_file.seek(0)
resp = FileResponse(image_file, content_type=ftype or 'application/binary') return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}.{}"'.format( image_file,
self.request.event.slug.upper(), filename='{}-{}-{}-{}.{}'.format(
pos.order.code, self.request.event.slug.upper(),
pos.positionid, pos.order.code,
key, pos.positionid,
extension, key,
extension,
),
as_attachment=True,
content_type=ftype or 'application/binary'
) )
return resp
@action(detail=True, url_name='download', url_path='download/(?P<output>[^/]+)') @action(detail=True, url_name='download', url_path='download/(?P<output>[^/]+)')
def download(self, request, output, **kwargs): def download(self, request, output, **kwargs):
@@ -1399,12 +1408,15 @@ class EventOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ModelViewSet
resp = HttpResponse(ct.file.file.read(), content_type='text/uri-list') resp = HttpResponse(ct.file.file.read(), content_type='text/uri-list')
return resp return resp
else: else:
resp = FileResponse(ct.file.file, content_type=ct.type) return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format( ct.file.file,
self.request.event.slug.upper(), pos.order.code, pos.positionid, filename='{}-{}-{}-{}{}'.format(
provider.identifier, ct.extension self.request.event.slug.upper(), pos.order.code, pos.positionid,
provider.identifier, ct.extension
),
as_attachment=True,
content_type=ct.type
) )
return resp
@action(detail=True, methods=['POST']) @action(detail=True, methods=['POST'])
def regenerate_secrets(self, request, **kwargs): def regenerate_secrets(self, request, **kwargs):
@@ -1986,9 +1998,12 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
if not invoice.file: if not invoice.file:
raise RetryException() raise RetryException()
resp = FileResponse(invoice.file.file, content_type='application/pdf') return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number) invoice.file.file,
return resp filename='{}.pdf'.format(invoice.number),
as_attachment=True,
content_type='application/pdf'
)
@action(detail=True, methods=['POST']) @action(detail=True, methods=['POST'])
def transmit(self, request, **kwargs): def transmit(self, request, **kwargs):
+14
View File
@@ -1103,13 +1103,25 @@ class PaymentListExporter(ListExporter):
def iterate_list(self, form_data): def iterate_list(self, form_data):
provider_names = dict(get_all_payment_providers()) provider_names = dict(get_all_payment_providers())
i_numbers = Invoice.objects.filter(
order=OuterRef('order_id'),
).values('order').annotate(
m=GroupConcat('full_invoice_no', delimiter=', ')
).values(
'm'
).order_by()
payments = OrderPayment.objects.filter( payments = OrderPayment.objects.filter(
order__event__in=self.events, order__event__in=self.events,
state__in=form_data.get('payment_states', []) state__in=form_data.get('payment_states', [])
).annotate(
order_invoice_numbers=Subquery(i_numbers, output_field=CharField()),
).select_related('order').prefetch_related('order__event').order_by('created') ).select_related('order').prefetch_related('order__event').order_by('created')
refunds = OrderRefund.objects.filter( refunds = OrderRefund.objects.filter(
order__event__in=self.events, order__event__in=self.events,
state__in=form_data.get('refund_states', []) state__in=form_data.get('refund_states', [])
).annotate(
order_invoice_numbers=Subquery(i_numbers, output_field=CharField()),
).select_related('order').prefetch_related('order__event').order_by('created') ).select_related('order').prefetch_related('order__event').order_by('created')
if form_data.get('end_date_range'): if form_data.get('end_date_range'):
@@ -1135,6 +1147,7 @@ class PaymentListExporter(ListExporter):
headers = [ headers = [
_('Event slug'), _('Order'), _('Payment ID'), _('Creation date'), _('Completion date'), _('Status'), _('Event slug'), _('Order'), _('Payment ID'), _('Creation date'), _('Completion date'), _('Status'),
_('Status code'), _('Amount'), _('Payment method'), _('Comment'), _('Matching ID'), _('Payment details'), _('Status code'), _('Amount'), _('Payment method'), _('Comment'), _('Matching ID'), _('Payment details'),
_('Invoice numbers'),
] ]
yield headers yield headers
@@ -1172,6 +1185,7 @@ class PaymentListExporter(ListExporter):
obj.comment if isinstance(obj, OrderRefund) else "", obj.comment if isinstance(obj, OrderRefund) else "",
matching_id, matching_id,
payment_details, payment_details,
obj.order_invoice_numbers,
] ]
yield row yield row
+8 -2
View File
@@ -90,7 +90,7 @@ from pretix.base.settings import (
COUNTRIES_WITH_STATE_IN_ADDRESS, COUNTRY_STATE_LABEL, COUNTRIES_WITH_STATE_IN_ADDRESS, COUNTRY_STATE_LABEL,
PERSON_NAME_SALUTATIONS, PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, PERSON_NAME_SALUTATIONS, PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS,
) )
from pretix.base.templatetags.rich_text import rich_text from pretix.base.templatetags.rich_text import URL_RE, rich_text
from pretix.base.timemachine import time_machine_now from pretix.base.timemachine import time_machine_now
from pretix.control.forms import ( from pretix.control.forms import (
ExtFileField, ExtValidationMixin, SizeValidationMixin, SplitDateTimeField, ExtFileField, ExtValidationMixin, SizeValidationMixin, SplitDateTimeField,
@@ -227,9 +227,15 @@ class NamePartsFormField(forms.MultiValueField):
# bots. # bots.
r'^[^$€/%§{}<>~]*$', r'^[^$€/%§{}<>~]*$',
message=_('Please do not use special characters in names.') message=_('Please do not use special characters in names.')
),
RegexValidator(
URL_RE,
inverse_match=True,
message=_('Please do not use special characters in names.')
) )
] ]
} }
self.max_length = defaults['max_length']
self.scheme_name = kwargs.pop('scheme') self.scheme_name = kwargs.pop('scheme')
self.titles = kwargs.pop('titles') self.titles = kwargs.pop('titles')
self.scheme = PERSON_NAME_SCHEMES.get(self.scheme_name) self.scheme = PERSON_NAME_SCHEMES.get(self.scheme_name)
@@ -287,7 +293,7 @@ class NamePartsFormField(forms.MultiValueField):
if self.require_all_fields and not all(v for v in value): if self.require_all_fields and not all(v for v in value):
raise forms.ValidationError(self.error_messages['incomplete'], code='required') raise forms.ValidationError(self.error_messages['incomplete'], code='required')
if sum(len(v) for v in value.values() if v) > 250: if sum(len(v) for v in value.values() if v) > (self.max_length or 250):
raise forms.ValidationError(_('Please enter a shorter name.'), code='max_length') raise forms.ValidationError(_('Please enter a shorter name.'), code='max_length')
if value.get("salutation") == "empty": if value.get("salutation") == "empty":
+1 -1
View File
@@ -1160,7 +1160,7 @@ class Modern1Renderer(ClassicInvoiceRenderer):
return stylesheet return stylesheet
def _draw_invoice_from(self, canvas): def _draw_invoice_from(self, canvas):
if not self.invoice.invoice_from: if not self.invoice.address_invoice_from:
return return
c = [ c = [
self._clean_text(l) self._clean_text(l)
+13
View File
@@ -24,6 +24,7 @@ from urllib.parse import urlparse, urlsplit
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
from django.conf import settings from django.conf import settings
from django.core.exceptions import BadRequest
from django.http import Http404, HttpRequest, HttpResponse from django.http import Http404, HttpRequest, HttpResponse
from django.middleware.common import CommonMiddleware from django.middleware.common import CommonMiddleware
from django.urls import get_script_prefix, resolve from django.urls import get_script_prefix, resolve
@@ -347,6 +348,18 @@ class SecurityMiddleware(MiddlewareMixin):
return resp return resp
class RejectInvalidInputMiddleware(MiddlewareMixin):
def process_request(self, request):
# Nullbytes in GET/POST parameters are mostly harmless, as they will later fail on database insertion, but it
# keeps spamming our error logs whenever someone tries to run a vulnerability scanner.
if "\x00" in request.META['QUERY_STRING'] or "%00" in request.META['QUERY_STRING']:
raise BadRequest("Invalid characters in input.")
if request.method in ('POST', 'PUT', 'PATCH') and request.content_type == "application/x-www-form-urlencoded":
if any("\x00" in value for key, value_list in request.POST.lists() for value in value_list):
raise BadRequest("Invalid characters in input.")
class CustomCommonMiddleware(CommonMiddleware): class CustomCommonMiddleware(CommonMiddleware):
def get_full_path_with_slash(self, request): def get_full_path_with_slash(self, request):
@@ -0,0 +1,19 @@
# Generated by Django 4.2.27 on 2026-01-21 12:06
import i18nfield.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("pretixbase", "0298_pluggable_permissions"),
]
operations = [
migrations.AddField(
model_name="itemprogramtime",
name="location",
field=i18nfield.fields.I18nTextField(max_length=200, null=True),
)
]
+6
View File
@@ -715,6 +715,12 @@ class Event(EventMixin, LoggedModel):
self.settings.name_scheme = 'given_family' self.settings.name_scheme = 'given_family'
self.settings.payment_banktransfer_invoice_immediately = True self.settings.payment_banktransfer_invoice_immediately = True
self.settings.low_availability_percentage = 10 self.settings.low_availability_percentage = 10
self.settings.mail_send_order_free_attendee = True
self.settings.mail_send_order_placed_attendee = True
self.settings.mail_send_order_paid_attendee = True
self.settings.mail_send_order_approved_attendee = True
self.settings.mail_send_order_approved_free_attendee = True
self.settings.mail_text_download_reminder_attendee = True
@property @property
def social_image(self): def social_image(self):
+7
View File
@@ -2306,10 +2306,17 @@ class ItemProgramTime(models.Model):
:type start: datetime :type start: datetime
:param end: The date and time this program time ends :param end: The date and time this program time ends
:type end: datetime :type end: datetime
:param location: venue
:type location: str
""" """
item = models.ForeignKey('Item', related_name='program_times', on_delete=models.CASCADE) item = models.ForeignKey('Item', related_name='program_times', on_delete=models.CASCADE)
start = models.DateTimeField(verbose_name=_("Start")) start = models.DateTimeField(verbose_name=_("Start"))
end = models.DateTimeField(verbose_name=_("End")) end = models.DateTimeField(verbose_name=_("End"))
location = I18nTextField(
null=True, blank=True,
max_length=200,
verbose_name=_("Location"),
)
def clean(self): def clean(self):
if hasattr(self, 'item') and self.item and self.item.event.has_subevents: if hasattr(self, 'item') and self.item and self.item.event.has_subevents:
+16 -10
View File
@@ -498,9 +498,9 @@ DEFAULT_VARIABLES = OrderedDict((
) if op.valid_until else "" ) if op.valid_until else ""
}), }),
("program_times", { ("program_times", {
"label": _("Program times: date and time"), "label": _("Program times"),
"editor_sample": _( "editor_sample": _(
"2017-05-31 10:00 12:00\n2017-05-31 14:00 16:00\n2017-05-31 14:00 2017-06-01 14:00"), "2017-05-31 10:00 12:00, Room 1\n2017-05-31 14:00 16:00, Room 2\n2017-05-31 14:00 2017-06-01 14:00, Building A"),
"evaluate": lambda op, order, ev: get_program_times(op, ev) "evaluate": lambda op, order, ev: get_program_times(op, ev)
}), }),
("medium_identifier", { ("medium_identifier", {
@@ -748,13 +748,19 @@ def get_seat(op: OrderPosition):
def get_program_times(op: OrderPosition, ev: Event): def get_program_times(op: OrderPosition, ev: Event):
return '\n'.join([ ptstr = []
datetimerange( for pt in op.item.program_times.all():
pt.start.astimezone(ev.timezone), ptstr.append([
pt.end.astimezone(ev.timezone), datetimerange(
as_html=False pt.start.astimezone(ev.timezone),
) for pt in op.item.program_times.all() pt.end.astimezone(ev.timezone),
]) as_html=False
),
(', ' + ', '.join(
l.strip() for l in str(pt.location).splitlines() if l.strip())
) if str(pt.location).strip() else ''
])
return '\n'.join(''.join(l) for l in ptstr)
def generate_compressed_addon_list(op, order, event, only_checked_in=False): def generate_compressed_addon_list(op, order, event, only_checked_in=False):
@@ -923,7 +929,7 @@ class Renderer:
# We do not use str.format like in emails so we (a) can evaluate lazily and (b) can re-implement this # We do not use str.format like in emails so we (a) can evaluate lazily and (b) can re-implement this
# 1:1 on other platforms that render PDFs through our API (libpretixprint) # 1:1 on other platforms that render PDFs through our API (libpretixprint)
return re.sub(r'\{([a-zA-Z0-9:_]+)\}', replace, text) return re.sub(r'\{([-a-zA-Z0-9:_]+)\}', replace, text)
elif o['content'].startswith('itemmeta:'): elif o['content'].startswith('itemmeta:'):
if op.variation_id: if op.variation_id:
+29 -24
View File
@@ -49,14 +49,39 @@ class PluginType(Enum):
EXPORT = 4 EXPORT = 4
def plugin_is_available(meta, event=None, organizer=None):
if not hasattr(meta.app, 'is_available'):
return True
level = getattr(meta, "level", PLUGIN_LEVEL_EVENT)
if level == PLUGIN_LEVEL_EVENT:
if event:
return meta.app.is_available(event)
elif organizer:
if not hasattr(organizer, '_plugin_availability_fallback_event'):
with scope(organizer=organizer):
setattr(organizer, '_plugin_availability_fallback_event', organizer.events.first())
return (
organizer._plugin_availability_fallback_event
and meta.app.is_available(organizer._plugin_availability_fallback_event)
)
elif level == PLUGIN_LEVEL_ORGANIZER:
if organizer:
return meta.app.is_available(organizer)
elif event:
return meta.app.is_available(event.organizer)
elif level == PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID and (event or organizer):
return meta.app.is_available(event or organizer)
return True
def get_all_plugins(*, event=None, organizer=None) -> List[type]: def get_all_plugins(*, event=None, organizer=None) -> List[type]:
""" """
Returns the PretixPluginMeta classes of all plugins found in the installed Django apps. Returns the PretixPluginMeta classes of all plugins found in the installed Django apps.
""" """
assert not event or not organizer assert not event or not organizer
plugins = [] plugins = []
event_fallback = None
event_fallback_used = False
for app in apps.get_app_configs(): for app in apps.get_app_configs():
if hasattr(app, 'PretixPluginMeta'): if hasattr(app, 'PretixPluginMeta'):
meta = app.PretixPluginMeta meta = app.PretixPluginMeta
@@ -65,28 +90,8 @@ def get_all_plugins(*, event=None, organizer=None) -> List[type]:
if app.name in settings.PRETIX_PLUGINS_EXCLUDE: if app.name in settings.PRETIX_PLUGINS_EXCLUDE:
continue continue
level = getattr(meta, "level", PLUGIN_LEVEL_EVENT) if not plugin_is_available(meta, event, organizer):
if level == PLUGIN_LEVEL_EVENT: continue
if event and hasattr(app, 'is_available'):
if not app.is_available(event):
continue
elif organizer and hasattr(app, 'is_available'):
if not event_fallback_used:
with scope(organizer=organizer):
event_fallback = organizer.events.first()
event_fallback_used = True
if not event_fallback or not app.is_available(event_fallback):
continue
elif level == PLUGIN_LEVEL_ORGANIZER:
if organizer and hasattr(app, 'is_available'):
if not app.is_available(organizer):
continue
elif event and hasattr(app, 'is_available'):
if not app.is_available(event.organizer):
continue
elif level == PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID and (event or organizer) and hasattr(app, 'is_available'):
if not app.is_available(event or organizer):
continue
plugins.append(meta) plugins.append(meta)
return sorted( return sorted(
+2 -2
View File
@@ -162,12 +162,12 @@ error_messages = {
'price_too_high': gettext_lazy('The entered price is to high.'), 'price_too_high': gettext_lazy('The entered price is to high.'),
'voucher_invalid': gettext_lazy('This voucher code is not known in our database.'), 'voucher_invalid': gettext_lazy('This voucher code is not known in our database.'),
'voucher_min_usages': ngettext_lazy( 'voucher_min_usages': ngettext_lazy(
'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products.', 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching product.',
'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products.', 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products.',
'number' 'number'
), ),
'voucher_min_usages_removed': ngettext_lazy( 'voucher_min_usages_removed': ngettext_lazy(
'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products. ' 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching product. '
'We have therefore removed some positions from your cart that can no longer be purchased like this.', 'We have therefore removed some positions from your cart that can no longer be purchased like this.',
'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products. ' 'The voucher code "%(voucher)s" can only be used if you select at least %(number)s matching products. '
'We have therefore removed some positions from your cart that can no longer be purchased like this.', 'We have therefore removed some positions from your cart that can no longer be purchased like this.',
+28
View File
@@ -38,6 +38,7 @@ SOURCE_NAMES = {
None: _('European Central Bank'), # backwards-compatibility None: _('European Central Bank'), # backwards-compatibility
'eu:ecb:eurofxref-daily': _('European Central Bank'), 'eu:ecb:eurofxref-daily': _('European Central Bank'),
'cz:cnb:rate-fixing-daily': _('Czech National Bank'), 'cz:cnb:rate-fixing-daily': _('Czech National Bank'),
'pl:nbp:table-a': _('National Bank of Poland'),
} }
@@ -49,6 +50,7 @@ def fetch_rates(sender, **kwargs):
source_tasks = { source_tasks = {
'eu:ecb:eurofxref-daily': fetch_ecb_rates, 'eu:ecb:eurofxref-daily': fetch_ecb_rates,
'cz:cnb:rate-fixing-daily': fetch_cnb_cz_rates, 'cz:cnb:rate-fixing-daily': fetch_cnb_cz_rates,
'pl:nbp:table-a': fetch_nbp_pl_rates,
} }
for source_name, task in source_tasks.items(): for source_name, task in source_tasks.items():
@@ -144,3 +146,29 @@ def fetch_cnb_cz_rates():
rate=rate, rate=rate,
) )
) )
@app.task()
def fetch_nbp_pl_rates():
"""
Fetches currency rates from the Polish National Bank.
"""
r = requests.get("https://api.nbp.pl/api/exchangerates/tables/A/", headers={
"Accept": "application/json",
})
r.raise_for_status()
data = r.json()[0]
source_date = datetime.strptime(data["effectiveDate"], "%Y-%m-%d").date()
for r in data["rates"]:
rate = Decimal(r["mid"]).quantize(Decimal('0.000001'))
ExchangeRate.objects.update_or_create(
source='pl:nbp:table-a',
source_currency=r["code"],
other_currency='PLN',
defaults=dict(
source_date=source_date,
rate=rate,
)
)
+15 -1
View File
@@ -58,6 +58,7 @@ from pretix.base.invoicing.transmission import (
from pretix.base.models import ( from pretix.base.models import (
ExchangeRate, Invoice, InvoiceAddress, InvoiceLine, Order, OrderFee, ExchangeRate, Invoice, InvoiceAddress, InvoiceLine, Order, OrderFee,
) )
from pretix.base.models.orders import OrderPayment
from pretix.base.models.tax import EU_CURRENCIES from pretix.base.models.tax import EU_CURRENCIES
from pretix.base.services.tasks import ( from pretix.base.services.tasks import (
TransactionAwareProfiledEventTask, TransactionAwareTask, TransactionAwareProfiledEventTask, TransactionAwareTask,
@@ -102,7 +103,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
introductory = invoice.event.settings.get('invoice_introductory_text', as_type=LazyI18nString) introductory = invoice.event.settings.get('invoice_introductory_text', as_type=LazyI18nString)
additional = invoice.event.settings.get('invoice_additional_text', as_type=LazyI18nString) additional = invoice.event.settings.get('invoice_additional_text', as_type=LazyI18nString)
footer = invoice.event.settings.get('invoice_footer_text', as_type=LazyI18nString) footer = invoice.event.settings.get('invoice_footer_text', as_type=LazyI18nString)
if lp and lp.payment_provider: if lp and lp.payment_provider and lp.state not in (OrderPayment.PAYMENT_STATE_FAILED, OrderPayment.PAYMENT_STATE_CANCELED):
if 'payment' in inspect.signature(lp.payment_provider.render_invoice_text).parameters: if 'payment' in inspect.signature(lp.payment_provider.render_invoice_text).parameters:
payment = str(lp.payment_provider.render_invoice_text(invoice.order, lp)) payment = str(lp.payment_provider.render_invoice_text(invoice.order, lp))
else: else:
@@ -204,6 +205,19 @@ def build_invoice(invoice: Invoice) -> Invoice:
invoice.foreign_currency_rate = rate.rate.quantize(Decimal('0.0001'), ROUND_HALF_UP) invoice.foreign_currency_rate = rate.rate.quantize(Decimal('0.0001'), ROUND_HALF_UP)
invoice.foreign_currency_rate_date = rate.source_date invoice.foreign_currency_rate_date = rate.source_date
invoice.foreign_currency_source = 'cz:cnb:rate-fixing-daily' invoice.foreign_currency_source = 'cz:cnb:rate-fixing-daily'
elif invoice.event.settings.invoice_eu_currencies == 'PLN' and invoice.event.currency != 'PLN':
invoice.foreign_currency_display = 'PLN'
if settings.FETCH_ECB_RATES:
rate = ExchangeRate.objects.filter(
source='pl:nbp:table-a',
source_currency=invoice.event.currency,
other_currency=invoice.foreign_currency_display,
source_date__gt=now().date() - timedelta(days=7)
).first()
if rate:
invoice.foreign_currency_rate = rate.rate.quantize(Decimal('0.0001'), ROUND_HALF_UP)
invoice.foreign_currency_rate_date = rate.source_date
invoice.foreign_currency_source = 'pl:nbp:table-a'
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
ia = None ia = None
+3 -2
View File
@@ -727,8 +727,6 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
_check_date(event, time_machine_now_dt) _check_date(event, time_machine_now_dt)
products_seen = Counter() products_seen = Counter()
q_avail = Counter()
v_avail = Counter()
v_usages = Counter() v_usages = Counter()
v_budget = {} v_budget = {}
deleted_positions = set() deleted_positions = set()
@@ -793,6 +791,9 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
shared_lock_objects=[event] shared_lock_objects=[event]
) )
q_avail = Counter()
v_avail = Counter()
# Check maximum order size # Check maximum order size
limit = min(int(event.settings.max_items_per_order), settings.PRETIX_MAX_ORDER_SIZE) limit = min(int(event.settings.max_items_per_order), settings.PRETIX_MAX_ORDER_SIZE)
if sum(1 for cp in sorted_positions if not cp.addon_to) > limit: if sum(1 for cp in sorted_positions if not cp.addon_to) > limit:
+2
View File
@@ -574,6 +574,7 @@ DEFAULTS = {
('True', _('Based on European Central Bank daily rates, whenever the invoice recipient is in an EU ' ('True', _('Based on European Central Bank daily rates, whenever the invoice recipient is in an EU '
'country that uses a different currency.')), 'country that uses a different currency.')),
('CZK', _('Based on Czech National Bank daily rates, whenever the invoice amount is not in CZK.')), ('CZK', _('Based on Czech National Bank daily rates, whenever the invoice amount is not in CZK.')),
('PLN', _('Based on National Bank of Poland daily rates, whenever the invoice amount is not in PLN.')),
), ),
), ),
'serializer_kwargs': dict( 'serializer_kwargs': dict(
@@ -582,6 +583,7 @@ DEFAULTS = {
('True', _('Based on European Central Bank daily rates, whenever the invoice recipient is in an EU ' ('True', _('Based on European Central Bank daily rates, whenever the invoice recipient is in an EU '
'country that uses a different currency.')), 'country that uses a different currency.')),
('CZK', _('Based on Czech National Bank daily rates, whenever the invoice amount is not in CZK.')), ('CZK', _('Based on Czech National Bank daily rates, whenever the invoice amount is not in CZK.')),
('PLN', _('Based on National Bank of Poland daily rates, whenever the invoice amount is not in PLN.')),
), ),
), ),
}, },
+4
View File
@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
import logging import logging
import re
from collections import defaultdict from collections import defaultdict
from datetime import timedelta from datetime import timedelta
from importlib import import_module from importlib import import_module
@@ -52,6 +53,7 @@ from pretix.celery_app import app
from pretix.helpers.http import redirect_to_url from pretix.helpers.http import redirect_to_url
logger = logging.getLogger('pretix.base.tasks') logger = logging.getLogger('pretix.base.tasks')
RE_ASYNC_ID = re.compile(r"^[a-zA-Z0-9\-]+$")
class AsyncMixin: class AsyncMixin:
@@ -133,6 +135,8 @@ class AsyncMixin:
def get_result(self, request): def get_result(self, request):
if not request.GET.get('async_id'): if not request.GET.get('async_id'):
raise BadRequest("No async_id given") raise BadRequest("No async_id given")
if not RE_ASYNC_ID.match(request.GET.get('async_id')):
raise BadRequest("Invalid async_id given")
res = AsyncResult(request.GET.get('async_id')) res = AsyncResult(request.GET.get('async_id'))
if 'ajax' in self.request.GET: if 'ajax' in self.request.GET:
return JsonResponse(self._return_ajax_result(res, timeout=0.25)) return JsonResponse(self._return_ajax_result(res, timeout=0.25))
+127
View File
@@ -1528,6 +1528,133 @@ class SubEventFilterForm(FilterForm):
return self.event.organizer.meta_properties.filter(filter_allowed=True) return self.event.organizer.meta_properties.filter(filter_allowed=True)
class QuotaFilterForm(FilterForm):
orders = {
'-date': ('-subevent__date_from', 'name', 'pk'),
'date': ('subevent__date_from', '-name', '-pk'),
'size': ('size', 'name', 'pk'),
'-size': ('-size', '-name', '-pk'),
'name': ('name', 'pk'),
'-name': ('-name', '-pk'),
}
subevent = forms.ModelChoiceField(
label=pgettext_lazy('subevent', 'Date'),
queryset=SubEvent.objects.none(),
required=False,
empty_label=pgettext_lazy('subevent', 'All dates')
)
date_from = forms.DateField(
label=_('Date from'),
required=False,
widget=DatePickerWidget({
'placeholder': _('Date from'),
}),
)
date_until = forms.DateField(
label=_('Date until'),
required=False,
widget=DatePickerWidget({
'placeholder': _('Date until'),
}),
)
time_from = forms.TimeField(
label=_('Start time from'),
required=False,
widget=TimePickerWidget({}),
)
time_until = forms.TimeField(
label=_('Start time until'),
required=False,
widget=TimePickerWidget({}),
)
weekday = forms.MultipleChoiceField(
label=_('Weekday'),
choices=(
('2', _('Monday')),
('3', _('Tuesday')),
('4', _('Wednesday')),
('5', _('Thursday')),
('6', _('Friday')),
('7', _('Saturday')),
('1', _('Sunday')),
),
widget=forms.CheckboxSelectMultiple,
required=False
)
query = forms.CharField(
label=_('Quota name'),
widget=forms.TextInput(),
required=False
)
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event')
super().__init__(*args, **kwargs)
if self.event.has_subevents:
self.fields['date_from'].widget = DatePickerWidget()
self.fields['date_until'].widget = DatePickerWidget()
self.fields['subevent'].queryset = self.event.subevents.all()
self.fields['subevent'].widget = Select2(
attrs={
'data-model-select2': 'event',
'data-select2-url': reverse('control:event.subevents.select2', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
}),
'data-placeholder': pgettext_lazy('subevent', 'All dates')
}
)
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
else:
del self.fields['subevent']
del self.fields['date_from']
del self.fields['date_until']
del self.fields['time_from']
del self.fields['time_until']
del self.fields['weekday']
def filter_qs(self, qs):
fdata = self.cleaned_data
if fdata.get('weekday'):
qs = qs.annotate(wday=ExtractWeekDay('subevent__date_from')).filter(wday__in=fdata.get('weekday'))
if fdata.get('subevent'):
qs = qs.filter(subevent=fdata["subevent"])
if fdata.get('query'):
query = fdata.get('query')
qs = qs.filter(name__icontains=query)
if fdata.get('date_until'):
date_end = make_aware(datetime.combine(
fdata.get('date_until') + timedelta(days=1),
time(hour=0, minute=0, second=0, microsecond=0)
), get_current_timezone())
qs = qs.filter(
Q(subevent__date_to__isnull=True, subevent__date_from__lt=date_end) |
Q(subevent__date_to__isnull=False, subevent__date_to__lt=date_end)
)
if fdata.get('date_from'):
date_start = make_aware(datetime.combine(
fdata.get('date_from'),
time(hour=0, minute=0, second=0, microsecond=0)
), get_current_timezone())
qs = qs.filter(subevent__date_from__gte=date_start)
if fdata.get('time_until'):
qs = qs.filter(subevent__date_from__time__lte=fdata.get('time_until'))
if fdata.get('time_from'):
qs = qs.filter(subevent__date_from__time__gte=fdata.get('time_from'))
if fdata.get('ordering'):
qs = qs.order_by(*get_deterministic_ordering(Quota, self.get_order_by()))
else:
qs = qs.order_by('-subevent__date_from', 'name', 'pk')
return qs
class OrganizerFilterForm(FilterForm): class OrganizerFilterForm(FilterForm):
orders = { orders = {
'slug': 'slug', 'slug': 'slug',
+61 -1
View File
@@ -43,6 +43,7 @@ from django.core.exceptions import ValidationError
from django.db.models import Max, Q from django.db.models import Max, Q
from django.forms import ChoiceField, RadioSelect from django.forms import ChoiceField, RadioSelect
from django.forms.formsets import DELETION_FIELD_NAME from django.forms.formsets import DELETION_FIELD_NAME
from django.forms.utils import ErrorDict
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import escape, format_html from django.utils.html import escape, format_html
@@ -375,6 +376,60 @@ class QuotaForm(I18nModelForm):
return inst return inst
class QuotaBulkEditForm(QuotaForm):
def __init__(self, *args, **kwargs):
self.mixed_values = kwargs.pop('mixed_values')
self.queryset = kwargs.pop('queryset')
super().__init__(**kwargs)
self.fields.pop("subevent", None) # Would add extra complexity and it's hard to imagine a use case for that
self.fields["name"].required = False
self.fields["itemvars"].required = False
def clean(self):
d = super().clean()
if self.prefix + "name" in self.data.getlist('_bulk') and not d.get("name"):
raise ValidationError({"name": _("This field is required.")})
if self.prefix + "itemvars" in self.data.getlist('_bulk') and not d.get("itemvars"):
raise ValidationError({"itemvars": _("This field is required.")})
return d
def save(self, commit=True):
objs = list(self.queryset)
fields = set()
for k in self.fields:
cb_val = self.prefix + k
if cb_val not in self.data.getlist('_bulk'):
continue
fields.add(k)
if k == 'itemvars':
selected_items = set(list(self.event.items.filter(id__in=[
i.split('-')[0] for i in self.cleaned_data['itemvars']
])))
selected_variations = list(ItemVariation.objects.filter(item__event=self.event, id__in=[
i.split('-')[1] for i in self.cleaned_data['itemvars'] if '-' in i
]))
for obj in objs:
obj.items.set(selected_items)
obj.variations.set(selected_variations)
else:
for obj in objs:
setattr(obj, k, self.cleaned_data[k])
fields = [f for f in fields if f != 'itemvars']
if fields:
Quota.objects.bulk_update(objs, fields, 200)
def full_clean(self):
if len(self.data) == 0:
# form wasn't submitted
self._errors = ErrorDict()
return
super().full_clean()
class ItemCreateForm(I18nModelForm): class ItemCreateForm(I18nModelForm):
NONE = 'none' NONE = 'none'
EXISTING = 'existing' EXISTING = 'existing'
@@ -574,7 +629,7 @@ class ItemCreateForm(I18nModelForm):
instance.bundles.create(bundled_item=b.bundled_item, bundled_variation=b.bundled_variation, instance.bundles.create(bundled_item=b.bundled_item, bundled_variation=b.bundled_variation,
count=b.count, designated_price=b.designated_price) count=b.count, designated_price=b.designated_price)
for pt in self.cleaned_data['copy_from'].program_times.all(): for pt in self.cleaned_data['copy_from'].program_times.all():
instance.program_times.create(start=pt.start, end=pt.end) instance.program_times.create(start=pt.start, end=pt.end, location=pt.location)
item_copy_data.send(sender=self.event, source=self.cleaned_data['copy_from'], target=instance) item_copy_data.send(sender=self.event, source=self.cleaned_data['copy_from'], target=instance)
@@ -1354,6 +1409,10 @@ class ItemProgramTimeForm(I18nModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['end'].widget.attrs['data-date-after'] = '#id_{prefix}-start_0'.format(prefix=self.prefix) self.fields['end'].widget.attrs['data-date-after'] = '#id_{prefix}-start_0'.format(prefix=self.prefix)
self.fields['location'].widget.attrs['rows'] = '3'
self.fields['location'].widget.attrs['placeholder'] = _(
'Sample Conference Center, Heidelberg, Germany'
)
class Meta: class Meta:
model = ItemProgramTime model = ItemProgramTime
@@ -1361,6 +1420,7 @@ class ItemProgramTimeForm(I18nModelForm):
fields = [ fields = [
'start', 'start',
'end', 'end',
'location'
] ]
field_classes = { field_classes = {
'start': forms.SplitDateTimeField, 'start': forms.SplitDateTimeField,
+11 -1
View File
@@ -28,7 +28,7 @@ from django.forms import formset_factory
from django.forms.utils import ErrorDict from django.forms.utils import ErrorDict
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _, pgettext_lazy
from i18nfield.forms import I18nInlineFormSet from i18nfield.forms import I18nInlineFormSet
from pretix.base.forms import I18nModelForm from pretix.base.forms import I18nModelForm
@@ -102,6 +102,16 @@ class SubEventBulkForm(SubEventForm):
required=False, required=False,
limit_choices=('date_from', 'date_to'), limit_choices=('date_from', 'date_to'),
) )
skip_if_overlap = forms.BooleanField(
label=pgettext_lazy('subevent', 'Skip dates that overlap with any existing date'),
help_text=pgettext_lazy(
'subevent',
'This can be useful if all your dates happen in the same location and no repeated dates should '
'be created in conflict with existing special events. This respects even inactive dates and works best if '
'all dates have both a start and end time.'
),
required=False,
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.event = kwargs['event'] self.event = kwargs['event']
+6 -6
View File
@@ -34,11 +34,11 @@
# License for the specific language governing permissions and limitations under the License. # License for the specific language governing permissions and limitations under the License.
from collections import defaultdict from collections import defaultdict
from datetime import datetime
from decimal import Decimal from decimal import Decimal
from typing import Optional from typing import Optional
import bleach import bleach
import dateutil.parser
from django.dispatch import receiver from django.dispatch import receiver
from django.urls import reverse from django.urls import reverse
from django.utils.formats import date_format from django.utils.formats import date_format
@@ -248,7 +248,7 @@ class OrderValidFromChanged(OrderChangeLogEntryType):
def display_prefixed(self, event: Event, logentry: LogEntry, data): def display_prefixed(self, event: Event, logentry: LogEntry, data):
return _('The validity start date for position #{posid} has been changed to {value}.').format( return _('The validity start date for position #{posid} has been changed to {value}.').format(
posid=data.get('positionid', '?'), posid=data.get('positionid', '?'),
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get( value=date_format(datetime.fromisoformat(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get(
'new_value') else '' 'new_value') else ''
) )
@@ -260,7 +260,7 @@ class OrderValidUntilChanged(OrderChangeLogEntryType):
def display_prefixed(self, event: Event, logentry: LogEntry, data): def display_prefixed(self, event: Event, logentry: LogEntry, data):
return _('The validity end date for position #{posid} has been changed to {value}.').format( return _('The validity end date for position #{posid} has been changed to {value}.').format(
posid=data.get('positionid', '?'), posid=data.get('positionid', '?'),
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get('new_value') else '' value=date_format(datetime.fromisoformat(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get('new_value') else ''
) )
@@ -364,7 +364,7 @@ class CheckinErrorLogEntryType(OrderLogEntryType):
data['posid'] = logentry.parsed_data.get('positionid', '?') data['posid'] = logentry.parsed_data.get('positionid', '?')
if 'datetime' in data: if 'datetime' in data:
dt = dateutil.parser.parse(data.get('datetime')) dt = datetime.fromisoformat(data.get('datetime'))
if abs((logentry.datetime - dt).total_seconds()) > 5 or data.get('forced'): if abs((logentry.datetime - dt).total_seconds()) > 5 or data.get('forced'):
if event: if event:
data['datetime'] = date_format(dt.astimezone(event.timezone), "SHORT_DATETIME_FORMAT") data['datetime'] = date_format(dt.astimezone(event.timezone), "SHORT_DATETIME_FORMAT")
@@ -430,7 +430,7 @@ class OrderPrintLogEntryType(OrderLogEntryType):
return _('Position #{posid} has been printed at {datetime} with type "{type}".').format( return _('Position #{posid} has been printed at {datetime} with type "{type}".').format(
posid=data.get('positionid'), posid=data.get('positionid'),
datetime=date_format( datetime=date_format(
dateutil.parser.parse(data["datetime"]).astimezone(logentry.event.timezone), datetime.fromisoformat(data["datetime"]).astimezone(logentry.event.timezone),
"SHORT_DATETIME_FORMAT" "SHORT_DATETIME_FORMAT"
) if logentry.event else data["datetime"], ) if logentry.event else data["datetime"],
type=dict(PrintLog.PRINT_TYPES)[data["type"]], type=dict(PrintLog.PRINT_TYPES)[data["type"]],
@@ -985,7 +985,7 @@ class LegacyCheckinLogEntryType(OrderLogEntryType):
def display(self, logentry, data): def display(self, logentry, data):
# deprecated # deprecated
dt = dateutil.parser.parse(data.get('datetime')) dt = datetime.fromisoformat(data.get('datetime'))
tz = logentry.event.timezone tz = logentry.event.timezone
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT") dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
if 'list' in data: if 'list' in data:
@@ -34,6 +34,7 @@
{% bootstrap_form_errors form %} {% bootstrap_form_errors form %}
{% bootstrap_field form.start layout="control" %} {% bootstrap_field form.start layout="control" %}
{% bootstrap_field form.end layout="control" %} {% bootstrap_field form.end layout="control" %}
{% bootstrap_field form.location layout="control" %}
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@@ -59,6 +60,7 @@
<div class="panel-body form-horizontal"> <div class="panel-body form-horizontal">
{% bootstrap_field formset.empty_form.start layout="control" %} {% bootstrap_field formset.empty_form.start layout="control" %}
{% bootstrap_field formset.empty_form.end layout="control" %} {% bootstrap_field formset.empty_form.end layout="control" %}
{% bootstrap_field formset.empty_form.location layout="control" %}
</div> </div>
</div> </div>
{% endescapescript %} {% endescapescript %}
@@ -0,0 +1,49 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block content %}
<h1>
{% trans "Change multiple quotas" %}
<small>
{% blocktrans trimmed with number=quotas.count %}
{{ number }} selected
{% endblocktrans %}
</small>
</h1>
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% bootstrap_form_errors form %}
<div class="hidden">
{% for d in quotas %}
<input type="hidden" name="quota" value="{{ d.pk }}">
{% endfor %}
</div>
<fieldset>
<legend>{% trans "General information" %}</legend>
{% bootstrap_field form.name layout="bulkedit" %}
{% bootstrap_field form.size layout="bulkedit" %}
</fieldset>
<fieldset>
<legend>{% trans "Items" %}</legend>
<p>
{% blocktrans trimmed %}
Please select the products or product variations this quota should be applied to. If you apply two
quotas to the same product, it will only be available if <strong>both</strong> quotas have capacity
left.
{% endblocktrans %}
</p>
{% bootstrap_field form.itemvars layout="bulkedit" %}
</fieldset>
<fieldset>
<legend>{% trans "Advanced options" %}</legend>
{% bootstrap_field form.close_when_sold_out layout="bulkedit" %}
{% bootstrap_field form.release_after_exit layout="bulkedit" %}
{% bootstrap_field form.ignore_for_event_availability layout="bulkedit" %}
</fieldset>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
{% endblock %}
@@ -0,0 +1,34 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Delete quotas" %}{% endblock %}
{% block content %}
<h1>{% trans "Delete quotas" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% if allowed %}
<p>{% blocktrans trimmed count num=allowed|length %}
Are you sure you want to delete the following quota?
{% plural %}
Are you sure you want to delete the following {{ num }} quotas?
{% endblocktrans %}</p>
<ul>
{% for q in allowed %}
<li>
{{ q }} {% if q.subevent %}({{ q.subevent }}){% endif %}
<input type="hidden" name="quota" value="{{ q.pk }}">
</li>
{% endfor %}
</ul>
{% endif %}
<div class="form-group submit-group">
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}"
class="btn btn-default btn-cancel">
{% trans "Cancel" %}
</a>
<button type="submit" class="btn btn-danger btn-save" value="delete_confirm" name="action">
{% trans "Delete" %}
</button>
</div>
</form>
{% endblock %}
@@ -1,6 +1,7 @@
{% extends "pretixcontrol/items/base.html" %} {% extends "pretixcontrol/items/base.html" %}
{% load i18n %} {% load i18n %}
{% load urlreplace %} {% load urlreplace %}
{% load bootstrap3 %}
{% block title %}{% trans "Quotas" %}{% endblock %} {% block title %}{% trans "Quotas" %}{% endblock %}
{% block inside %} {% block inside %}
<h1>{% trans "Quotas" %}</h1> <h1>{% trans "Quotas" %}</h1>
@@ -13,21 +14,12 @@
number of a specific ticket type at the same time. number of a specific ticket type at the same time.
{% endblocktrans %} {% endblocktrans %}
</p> </p>
{% if request.event.has_subevents %} {% if quotas|length == 0 and not filter_form.filtered %}
<form class="form-inline helper-display-inline" action="" method="get">
{% include "pretixcontrol/event/fragment_subevent_choice_simple.html" %}
</form>
{% endif %}
{% if quotas|length == 0 %}
<div class="empty-collection"> <div class="empty-collection">
<p> <p>
{% if request.GET.subevent %} {% blocktrans trimmed %}
{% trans "Your search did not match any quotas." %} You haven't created any quotas yet.
{% else %} {% endblocktrans %}
{% blocktrans trimmed %}
You haven't created any quotas yet.
{% endblocktrans %}
{% endif %}
</p> </p>
{% if 'event.items:write' in request.eventpermset %} {% if 'event.items:write' in request.eventpermset %}
@@ -36,79 +28,160 @@
{% endif %} {% endif %}
</div> </div>
{% else %} {% else %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
{% trans "Filter" %}
</h3>
</div>
<form class="panel-body filter-form" action="" method="get">
<div class="row">
<div class="{% if not filter_form.subevent %}col-lg-6{% else %}col-lg-2{% endif %} col-md-6 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.query %}
</div>
{% if filter_form.subevent %}
<div class="col-lg-2 col-md-6 col-md-2 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.subevent %}
</div>
<div class="col-lg-2 col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.date_from %}
</div>
<div class="col-lg-2 col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.date_until %}
</div>
<div class="col-lg-2 col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.time_from %}
</div>
<div class="col-lg-2 col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.time_until %}
</div>
<div class="col-xs-12 one-line-checkboxes">
{% bootstrap_field filter_form.weekday %}
</div>
{% endif %}
</div>
<div class="text-right flip">
<button class="btn btn-primary btn-lg" type="submit">
<span class="fa fa-filter"></span>
{% trans "Filter" %}
</button>
</div>
</form>
</div>
{% if 'event.items:write' in request.eventpermset %} {% if 'event.items:write' in request.eventpermset %}
<p> <p>
<a href="{% url "control:event.items.quotas.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new quota" %} <a href="{% url "control:event.items.quotas.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new quota" %}
</a> </a>
</p> </p>
{% endif %} {% endif %}
<div class="table-responsive"> <form action="{% url "control:event.items.quotas.bulkaction" organizer=request.event.organizer.slug event=request.event.slug %}" method="post">
<table class="table table-hover table-quotas"> {% csrf_token %}
<thead> {% for field in filter_form %}
<tr> {{ field.as_hidden }}
<th>{% trans "Quota name" %} {% endfor %}
<a href="?{% url_replace request 'ordering' '-name' %}"><i class="fa fa-caret-down"></i></a> <div class="table-responsive">
<a href="?{% url_replace request 'ordering' 'name' %}"><i class="fa fa-caret-up"></i></a> <table class="table table-hover table-quotas">
</th> <thead>
<th>{% trans "Products" %}</th>
{% if request.event.has_subevents %}
<th>{% trans "Date" context "subevent" %}
<a href="?{% url_replace request 'ordering' '-date' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'date' %}"><i class="fa fa-caret-up"></i></a>
</th>
{% endif %}
<th>{% trans "Total capacity" %}
<a href="?{% url_replace request 'ordering' '-size' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'size' %}"><i class="fa fa-caret-up"></i></a>
</th>
<th>{% trans "Capacity left" %}</th>
<th class="action-col-2"></th>
</tr>
</thead>
<tbody>
{% for q in quotas %}
<tr> <tr>
<td> {% if "event.items:write" in request.eventpermset %}
<strong><a href="{% url "control:event.items.quotas.show" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}">{{ q.name }}</a></strong> <th>
{% if q.ignore_for_event_availability %} <label aria-label="{% trans "select all rows for batch-operation" %}" class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
<span class="fa fa-eye-slash text-muted" data-toggle="tooltip" title="{% trans "Ignore this quota when determining event availability" %}"></span> </th>
{% endif %}
</td>
<td>
<ul>
{% for item in q.cached_items %}
{% if not item.has_variations %}
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.id %}">{{ item }}</a></li>
{% endif %}
{% endfor %}
{% for v in q.variations.all %}
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=v.item.id %}#tab-0-3-open">
{{ v.item }} {{ v }}</a></li>
{% endfor %}
</ul>
</td>
{% if request.event.has_subevents %}
<td>
{{ q.subevent.name }} {{ q.subevent.get_date_range_display_with_times }}
</td>
{% endif %} {% endif %}
<td>{% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}</td> <th>{% trans "Quota name" %}
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.cached_avail closed=q.closed %}</td> <a href="?{% url_replace request 'filter-ordering' '-name' %}"><i class="fa fa-caret-down"></i></a>
<td class="text-right flip"> <a href="?{% url_replace request 'filter-ordering' 'name' %}"><i class="fa fa-caret-up"></i></a>
{% if 'event.items:write' in request.eventpermset %} </th>
<a href="{% url "control:event.items.quotas.edit" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a> <th>{% trans "Products" %}</th>
<a href="{% url "control:event.items.quotas.add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ q.id }}" {% if request.event.has_subevents %}
class="btn btn-sm btn-default" title="{% trans "Clone" %}" data-toggle="tooltip"> <th>{% trans "Date" context "subevent" %}
<span class="fa fa-copy"></span> <a href="?{% url_replace request 'filter-ordering' '-date' %}"><i class="fa fa-caret-down"></i></a>
</a> <a href="?{% url_replace request 'filter-ordering' 'date' %}"><i class="fa fa-caret-up"></i></a>
<a href="{% url "control:event.items.quotas.delete" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a> </th>
{% endif %} {% endif %}
</td> <th>{% trans "Total capacity" %}
<a href="?{% url_replace request 'filter-ordering' '-size' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'filter-ordering' 'size' %}"><i class="fa fa-caret-up"></i></a>
</th>
<th>{% trans "Capacity left" %}</th>
<th class="action-col-2"></th>
</tr> </tr>
{% endfor %} {% if "event.items:write" in request.eventpermset and page_obj.paginator.num_pages > 1 %}
</tbody> <tr class="table-select-all warning hidden">
</table> <td>
</div> <input type="checkbox" name="__ALL" id="__all" data-results-total="{{ page_obj.paginator.count }}">
</td>
<td colspan="6">
<label for="__all">
{% trans "Select all results on other pages as well" %}
</label>
</td>
</tr>
{% endif %}
</thead>
<tbody>
{% for q in quotas %}
<tr>
{% if "event.items:write" in request.eventpermset %}
<td>
<label aria-label="{% trans "select row for batch-operation" %}" class="batch-select-label"><input type="checkbox" name="quota" class="batch-select-checkbox" value="{{ q.pk }}"/></label>
</td>
{% endif %}
<td>
<strong><a href="{% url "control:event.items.quotas.show" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}">{{ q.name }}</a></strong>
{% if q.ignore_for_event_availability %}
<span class="fa fa-eye-slash text-muted" data-toggle="tooltip" title="{% trans "Ignore this quota when determining event availability" %}"></span>
{% endif %}
</td>
<td>
<ul>
{% for item in q.cached_items %}
{% if not item.has_variations %}
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.id %}">{{ item }}</a></li>
{% endif %}
{% endfor %}
{% for v in q.variations.all %}
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=v.item.id %}#tab-0-3-open">
{{ v.item }} {{ v }}</a></li>
{% endfor %}
</ul>
</td>
{% if request.event.has_subevents %}
<td>
{{ q.subevent.name }} {{ q.subevent.get_date_range_display_with_times }}
</td>
{% endif %}
<td>{% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}</td>
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.cached_avail closed=q.closed %}</td>
<td class="text-right flip">
{% if 'event.items:write' in request.eventpermset %}
<a href="{% url "control:event.items.quotas.edit" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
<a href="{% url "control:event.items.quotas.add" organizer=request.event.organizer.slug event=request.event.slug %}?copy_from={{ q.id }}"
class="btn btn-sm btn-default" title="{% trans "Clone" %}" data-toggle="tooltip">
<span class="fa fa-copy"></span>
</a>
<a href="{% url "control:event.items.quotas.delete" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if "event.items:write" in request.eventpermset %}
<div class="batch-select-actions">
<button type="submit" class="btn btn-danger btn-save" name="action" value="delete">
<i class="fa fa-trash"></i>{% trans "Delete selected" %}
</button>
<button type="submit" class="btn btn-primary btn-save" name="action" value="edit"
formaction="{% url "control:event.items.quotas.bulkedit" organizer=request.event.organizer.slug event=request.event.slug %}">
<i class="fa fa-edit"></i>{% trans "Edit selected" %}
</button>
</div>
{% endif %}
</form>
{% endif %} {% endif %}
{% include "pretixcontrol/pagination.html" %} {% include "pretixcontrol/pagination.html" %}
{% endblock %} {% endblock %}
@@ -471,7 +471,9 @@
{% endif %} {% endif %}
{% if line.subevent %} {% if line.subevent %}
<br/> <br/>
<span class="fa fa-calendar fa-fw"></span> {{ line.subevent.name }} &middot; {{ line.subevent.get_date_range_display_with_times }} <span class="fa fa-calendar fa-fw"></span>
<a href="{% url "control:event.subevent" organizer=request.event.organizer.slug event=request.event.slug subevent=line.subevent_id %}">{{ line.subevent.name }}</a>
&middot; {{ line.subevent.get_date_range_display_with_times }}
{% endif %} {% endif %}
{% if line.used_membership %} {% if line.used_membership %}
<br /><span class="fa fa-id-card fa-fw" aria-hidden="true"></span> <br /><span class="fa fa-id-card fa-fw" aria-hidden="true"></span>
@@ -379,6 +379,8 @@
<i class="fa fa-calendar"></i> {% trans "Add many time slots" %}</button> <i class="fa fa-calendar"></i> {% trans "Add many time slots" %}</button>
</p> </p>
</div> </div>
<hr />
{% bootstrap_field form.skip_if_overlap layout="control" horizontal_label_class='sr-only' horizontal_field_class='col-md-12' %}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "General information" %}</legend> <legend>{% trans "General information" %}</legend>
+2
View File
@@ -349,6 +349,8 @@ urlpatterns = [
name='event.items.questions.edit'), name='event.items.questions.edit'),
re_path(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'), re_path(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'),
re_path(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'), re_path(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'),
re_path(r'^quotas/bulk_action$', item.QuotaBulkAction.as_view(), name='event.items.quotas.bulkaction'),
re_path(r'^quotas/bulk_edit$', item.QuotaBulkUpdateView.as_view(), name='event.items.quotas.bulkedit'),
re_path(r'^quotas/(?P<quota>\d+)/$', item.QuotaView.as_view(), name='event.items.quotas.show'), re_path(r'^quotas/(?P<quota>\d+)/$', item.QuotaView.as_view(), name='event.items.quotas.show'),
re_path(r'^quotas/select$', typeahead.quotas_select2, name='event.items.quotas.select2'), re_path(r'^quotas/select$', typeahead.quotas_select2, name='event.items.quotas.select2'),
re_path(r'^quotas/(?P<quota>\d+)/change$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'), re_path(r'^quotas/(?P<quota>\d+)/change$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'),
+16 -13
View File
@@ -234,13 +234,21 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
self.request.event.log_action('pretix.event.footerlinks.changed', user=self.request.user, data={ self.request.event.log_action('pretix.event.footerlinks.changed', user=self.request.user, data={
'data': self.footer_links_formset.cleaned_data 'data': self.footer_links_formset.cleaned_data
}) })
if form.has_changed():
self.request.event.log_action('pretix.event.changed', user=self.request.user, data={ change_data = {
k: (form.cleaned_data.get(k).name k: (form.cleaned_data.get(k).name
if isinstance(form.cleaned_data.get(k), File) if isinstance(form.cleaned_data.get(k), File)
else form.cleaned_data.get(k)) else form.cleaned_data.get(k))
for k in form.changed_data for k in form.changed_data
}) }
meta_changed = {}
for f in self.meta_forms:
if f.has_changed():
meta_changed[f.property.name] = f.cleaned_data["value"]
if meta_changed:
change_data['meta_data'] = meta_changed
if change_data:
self.request.event.log_action('pretix.event.changed', user=self.request.user, data=change_data)
tickets.invalidate_cache.apply_async(kwargs={'event': self.request.event.pk}) tickets.invalidate_cache.apply_async(kwargs={'event': self.request.event.pk})
messages.success(self.request, _('Your changes have been saved.')) messages.success(self.request, _('Your changes have been saved.'))
@@ -763,12 +771,7 @@ class InvoicePreview(EventPermissionRequiredMixin, View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
fname, ftype, fcontent = build_preview_invoice_pdf(request.event) fname, ftype, fcontent = build_preview_invoice_pdf(request.event)
resp = HttpResponse(fcontent, content_type=ftype) resp = HttpResponse(fcontent, content_type=ftype)
if settings.DEBUG: resp['Content-Disposition'] = 'inline; filename="{}"'.format(fname)
# attachment is more secure as we're dealing with user-generated stuff here, but inline is much more convenient during debugging
resp['Content-Disposition'] = 'inline; filename="{}"'.format(fname)
resp._csp_ignore = True
else:
resp['Content-Disposition'] = 'attachment; filename="{}"'.format(fname)
return resp return resp
@@ -300,5 +300,4 @@ class SysReportView(AdministratorPermissionRequiredMixin, TemplateView):
resp = HttpResponse(data) resp = HttpResponse(data)
resp['Content-Type'] = mime resp['Content-Type'] = mime
resp['Content-Disposition'] = 'inline; filename="{}"'.format(name) resp['Content-Disposition'] = 'inline; filename="{}"'.format(name)
resp._csp_ignore = True
return resp return resp
+201 -34
View File
@@ -41,21 +41,22 @@ from json.decoder import JSONDecodeError
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.files import File from django.core.files import File
from django.db import transaction from django.db import models, transaction
from django.db.models import ( from django.db.models import (
Count, Exists, F, OuterRef, Prefetch, ProtectedError, Q, Count, Exists, F, OuterRef, Prefetch, ProtectedError, Q, Subquery, Value,
) )
from django.db.models.functions import Cast, Concat
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
from django.http import ( from django.http import (
Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect, Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect,
) )
from django.shortcuts import redirect from django.shortcuts import redirect, render
from django.urls import resolve, reverse from django.urls import resolve, reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _ from django.utils.translation import gettext, gettext_lazy as _
from django.views.decorators.http import require_http_methods from django.views.decorators.http import require_http_methods
from django.views.generic import ListView from django.views.generic import FormView, ListView, View
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView, SingleObjectMixin
from django_countries.fields import Country from django_countries.fields import Country
@@ -65,7 +66,7 @@ from pretix.api.serializers.item import (
) )
from pretix.base.forms import I18nFormSet from pretix.base.forms import I18nFormSet
from pretix.base.models import ( from pretix.base.models import (
CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, LogEntry,
OrderPosition, Question, QuestionAnswer, QuestionOption, Quota, OrderPosition, Question, QuestionAnswer, QuestionOption, Quota,
SeatCategoryMapping, Voucher, SeatCategoryMapping, Voucher,
) )
@@ -74,12 +75,15 @@ from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue
from pretix.base.services.quotas import QuotaAvailability from pretix.base.services.quotas import QuotaAvailability
from pretix.base.services.tickets import invalidate_cache from pretix.base.services.tickets import invalidate_cache
from pretix.base.signals import quota_availability from pretix.base.signals import quota_availability
from pretix.control.forms.filter import QuestionAnswerFilterForm from pretix.control.forms.filter import (
QuestionAnswerFilterForm, QuotaFilterForm,
)
from pretix.control.forms.item import ( from pretix.control.forms.item import (
CategoryForm, ItemAddOnForm, ItemAddOnsFormSet, ItemBundleForm, CategoryForm, ItemAddOnForm, ItemAddOnsFormSet, ItemBundleForm,
ItemBundleFormSet, ItemCreateForm, ItemMetaValueForm, ItemProgramTimeForm, ItemBundleFormSet, ItemCreateForm, ItemMetaValueForm, ItemProgramTimeForm,
ItemProgramTimeFormSet, ItemUpdateForm, ItemVariationForm, ItemProgramTimeFormSet, ItemUpdateForm, ItemVariationForm,
ItemVariationsFormSet, QuestionForm, QuestionOptionForm, QuotaForm, ItemVariationsFormSet, QuestionForm, QuestionOptionForm, QuotaBulkEditForm,
QuotaForm,
) )
from pretix.control.permissions import ( from pretix.control.permissions import (
EventPermissionRequiredMixin, event_permission_required, EventPermissionRequiredMixin, event_permission_required,
@@ -87,6 +91,7 @@ from pretix.control.permissions import (
from pretix.control.signals import item_forms, item_formsets from pretix.control.signals import item_forms, item_formsets
from pretix.helpers.models import modelcopy from pretix.helpers.models import modelcopy
from ...helpers import GroupConcat
from ...helpers.compat import CompatDeleteView from ...helpers.compat import CompatDeleteView
from . import ChartContainingView, CreateView, PaginationMixin, UpdateView from . import ChartContainingView, CreateView, PaginationMixin, UpdateView
@@ -831,13 +836,38 @@ class QuestionCreate(EventPermissionRequiredMixin, QuestionMixin, CreateView):
return ret return ret
class QuotaList(PaginationMixin, ListView): class QuotaQueryMixin:
@cached_property
def request_data(self):
if self.request.method == "POST":
return self.request.POST
return self.request.GET
def get_queryset(self):
qs = self.request.event.quotas
if self.filter_form.is_valid():
qs = self.filter_form.filter_qs(qs)
if 'quota' in self.request_data and '__ALL' not in self.request_data:
qs = qs.filter(
id__in=self.request_data.getlist('quota')
)
return qs
@cached_property
def filter_form(self):
return QuotaFilterForm(data=self.request_data, prefix='filter', event=self.request.event)
class QuotaList(PaginationMixin, QuotaQueryMixin, ListView):
model = Quota model = Quota
context_object_name = 'quotas' context_object_name = 'quotas'
template_name = 'pretixcontrol/items/quotas.html' template_name = 'pretixcontrol/items/quotas.html'
def get_queryset(self): def get_queryset(self):
qs = self.request.event.quotas.prefetch_related( return super().get_queryset().prefetch_related(
Prefetch( Prefetch(
"items", "items",
queryset=Item.objects.annotate( queryset=Item.objects.annotate(
@@ -852,28 +882,10 @@ class QuotaList(PaginationMixin, ListView):
queryset=self.request.event.subevents.all() queryset=self.request.event.subevents.all()
) )
) )
if self.request.GET.get("subevent", "") != "":
s = self.request.GET.get("subevent", "")
qs = qs.filter(subevent_id=s)
valid_orders = {
'-date': ('-subevent__date_from', 'name', 'pk'),
'date': ('subevent__date_from', '-name', '-pk'),
'size': ('size', 'name', 'pk'),
'-size': ('-size', '-name', '-pk'),
'name': ('name', 'pk'),
'-name': ('-name', '-pk'),
}
if self.request.GET.get("ordering", "-date") in valid_orders:
qs = qs.order_by(*valid_orders[self.request.GET.get("ordering", "-date")])
else:
qs = qs.order_by('name', 'subevent__date_from', 'pk')
return qs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data() ctx = super().get_context_data()
ctx['filter_form'] = self.filter_form
qa = QuotaAvailability() qa = QuotaAvailability()
qa.queue(*ctx['quotas']) qa.queue(*ctx['quotas'])
@@ -884,6 +896,165 @@ class QuotaList(PaginationMixin, ListView):
return ctx return ctx
class QuotaBulkAction(QuotaQueryMixin, EventPermissionRequiredMixin, View):
permission = 'event.items:write'
@transaction.atomic
def post(self, request, *args, **kwargs):
if request.POST.get('action') == 'delete':
return render(request, 'pretixcontrol/items/quota_delete_bulk.html', {
'allowed': self.get_queryset().select_related("subevent"),
})
elif request.POST.get('action') == 'delete_confirm':
log_entries = []
to_delete = []
for obj in self.get_queryset():
log_entries.append(obj.log_action('pretix.event.quota.deleted', user=self.request.user, save=False))
to_delete.append(obj.pk)
if to_delete:
LogEntry.bulk_create_and_postprocess(log_entries)
Quota.objects.filter(pk__in=to_delete).delete()
messages.success(request, _('The selected quotas have been deleted or disabled.'))
return redirect(self.get_success_url())
def get_success_url(self) -> str:
return reverse('control:event.items.quotas', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
})
class QuotaBulkUpdateView(QuotaQueryMixin, EventPermissionRequiredMixin, FormView):
template_name = 'pretixcontrol/items/quota_bulk_edit.html'
permission = 'event.items:write'
context_object_name = 'quota'
form_class = QuotaBulkEditForm
def get_queryset(self):
return super().get_queryset().prefetch_related(None).order_by()
def get(self, request, *args, **kwargs):
return HttpResponse(status=405)
@cached_property
def is_submitted(self):
# Usually, django considers a form "bound" / "submitted" on every POST request. However, this view is always
# called with POST method, even if just to pass the selection of objects to work on, so we want to modify
# that behaviour
return '_bulk' in self.request.POST
def get_form_kwargs(self):
initial = {}
mixed_values = set()
qs = self.get_queryset().annotate(
items_list=Subquery(
Quota.items.through.objects.filter(
quota_id=OuterRef('pk'),
item__variations__isnull=True,
).order_by().values('quota_id').annotate(
g=GroupConcat('item_id', separator=',', ordered=True)
).values('g')
),
vars_list=Subquery(
Quota.variations.through.objects.filter(
quota_id=OuterRef('pk')
).order_by().values('quota_id').annotate(
g=GroupConcat(
Concat(
Cast(F('itemvariation__item_id'), output_field=models.TextField()),
Value('-', output_field=models.TextField()),
Cast(F('itemvariation_id'), output_field=models.TextField()),
),
separator=',',
ordered=True
)
).values('g')
),
)
fields = {
'name': 'name',
'size': 'size',
'subevent': 'subevent',
'close_when_sold_out': 'close_when_sold_out',
'release_after_exit': 'release_after_exit',
'ignore_for_event_availability': 'ignore_for_event_availability',
}
for k, f in fields.items():
existing_values = list(qs.order_by(f).values(f).annotate(c=Count('*')))
if len(existing_values) == 1:
initial[k] = existing_values[0][f]
elif len(existing_values) > 1:
mixed_values.add(k)
initial[k] = None
item_values = list(qs.order_by("items_list").values("items_list").annotate(c=Count('*')))
var_values = list(qs.order_by("vars_list").values("vars_list").annotate(c=Count('*')))
if len(item_values) > 1 or len(var_values) > 1:
mixed_values.add("itemvars")
else:
initial["itemvars"] = [iv for iv in (item_values[0]["items_list"] or "").split(",") + (var_values[0]["vars_list"] or "").split(",") if iv]
kwargs = super().get_form_kwargs()
kwargs['event'] = self.request.event
kwargs['prefix'] = 'bulkedit'
kwargs['initial'] = initial
kwargs['queryset'] = self.get_queryset()
kwargs['mixed_values'] = mixed_values
if not self.is_submitted:
kwargs['data'] = None
kwargs['files'] = None
return kwargs
def get_success_url(self):
return reverse('control:event.items.quotas', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug,
})
@transaction.atomic()
def form_valid(self, form):
log_entries = []
# Main form
form.save()
data = {
k: v
for k, v in form.cleaned_data.items()
if k in form.changed_data
}
data['_raw_bulk_data'] = self.request.POST.dict()
for obj in self.get_queryset():
log_entries.append(
obj.log_action('pretix.event.quota.changed', data=data, user=self.request.user, save=False)
)
LogEntry.bulk_create_and_postprocess(log_entries)
messages.success(self.request, _('Your changes have been saved.'))
return super().form_valid(form)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['quotas'] = self.get_queryset()
ctx['bulk_selected'] = self.request.POST.getlist("_bulk")
return ctx
def post(self, request, *args, **kwargs):
form = self.get_form()
is_valid = (
self.is_submitted and
form.is_valid()
)
if is_valid:
return self.form_valid(form)
else:
if self.is_submitted:
messages.error(self.request, _('We could not save your changes. See below for details.'))
return self.form_invalid(form)
class QuotaCreate(EventPermissionRequiredMixin, CreateView): class QuotaCreate(EventPermissionRequiredMixin, CreateView):
model = Quota model = Quota
form_class = QuotaForm form_class = QuotaForm
@@ -1447,12 +1618,8 @@ class ItemUpdateGeneral(ItemDetailMixin, EventPermissionRequiredMixin, MetaDataE
meta_changed = {} meta_changed = {}
for f in self.meta_forms: for f in self.meta_forms:
meta_changed.update({ if f.has_changed():
k: (f.cleaned_data.get(k).name meta_changed[f.property.name] = f.cleaned_data["value"]
if isinstance(f.cleaned_data.get(k), File)
else f.cleaned_data.get(k))
for k in f.changed_data
})
if meta_changed: if meta_changed:
change_data['meta_data'] = meta_changed change_data['meta_data'] = meta_changed
+18 -31
View File
@@ -79,9 +79,9 @@ from pretix.base.email import get_email_context
from pretix.base.exporter import MultiSheetListExporter from pretix.base.exporter import MultiSheetListExporter
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
CachedCombinedTicket, CachedFile, CachedTicket, Checkin, Invoice, CachedFile, CachedTicket, Checkin, Invoice, InvoiceAddress, Item,
InvoiceAddress, Item, ItemVariation, LogEntry, Order, QuestionAnswer, ItemVariation, LogEntry, Order, QuestionAnswer, Quota,
Quota, ScheduledEventExport, generate_secret, ScheduledEventExport, generate_secret,
) )
from pretix.base.models.orders import ( from pretix.base.models.orders import (
CancellationRequest, OrderFee, OrderPayment, OrderPosition, OrderRefund, CancellationRequest, OrderFee, OrderPayment, OrderPosition, OrderRefund,
@@ -710,34 +710,21 @@ class OrderDownload(AsyncAction, OrderView):
resp = HttpResponseRedirect(value.file.file.read()) resp = HttpResponseRedirect(value.file.file.read())
return resp return resp
else: else:
resp = FileResponse(value.file.file, content_type=value.type) return FileResponse(
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format( value.file.file,
self.request.event.slug.upper(), self.order.code, self.order_position.positionid, filename='{}-{}-{}-{}{}'.format(
self.output.identifier, value.extension self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, value.extension
),
content_type=value.type
) )
return resp
elif isinstance(value, CachedCombinedTicket):
if value.type == 'text/uri-list':
resp = HttpResponseRedirect(value.file.file.read())
return resp
else:
resp = FileResponse(value.file.file, content_type=value.type)
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, value.extension
)
return resp
else: else:
return redirect(self.get_self_url()) return redirect(self.get_self_url())
def get_last_ct(self): def get_last_ct(self):
if 'position' in self.kwargs: ct = CachedTicket.objects.filter(
ct = CachedTicket.objects.filter( order_position=self.order_position, provider=self.output.identifier, file__isnull=False
order_position=self.order_position, provider=self.output.identifier, file__isnull=False ).last()
).last()
else:
ct = CachedCombinedTicket.objects.filter(
order=self.order, provider=self.output.identifier, file__isnull=False
).last()
if not ct or not ct.file: if not ct or not ct.file:
return None return None
return ct return ct
@@ -1831,15 +1818,15 @@ class InvoiceDownload(EventPermissionRequiredMixin, View):
return redirect(self.get_order_url()) return redirect(self.get_order_url())
try: try:
resp = FileResponse(self.invoice.file.file, content_type='application/pdf') return FileResponse(
self.invoice.file.file,
filename='{}.pdf'.format(re.sub("[^a-zA-Z0-9-_.]+", "_", self.invoice.number)),
content_type='application/pdf'
)
except FileNotFoundError: except FileNotFoundError:
invoice_pdf_task.apply(args=(self.invoice.pk,)) invoice_pdf_task.apply(args=(self.invoice.pk,))
return self.get(request, *args, **kwargs) return self.get(request, *args, **kwargs)
resp['Content-Disposition'] = 'inline; filename="{}.pdf"'.format(re.sub("[^a-zA-Z0-9-_.]+", "_", self.invoice.number))
resp._csp_ignore = True # Some browser's PDF readers do not work with CSP
return resp
class OrderExtend(OrderView): class OrderExtend(OrderView):
permission = 'event.orders:write' permission = 'event.orders:write'
+16 -20
View File
@@ -102,7 +102,7 @@ from pretix.base.models.organizer import (
from pretix.base.payment import PaymentException from pretix.base.payment import PaymentException
from pretix.base.plugins import ( from pretix.base.plugins import (
PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID, PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID,
PLUGIN_LEVEL_ORGANIZER, PLUGIN_LEVEL_ORGANIZER, plugin_is_available,
) )
from pretix.base.services.export import ( from pretix.base.services.export import (
init_organizer_exporters, multiexport, scheduled_organizer_export, init_organizer_exporters, multiexport, scheduled_organizer_export,
@@ -597,6 +597,13 @@ class OrganizerCreate(CreateView):
}) })
def available_plugins(organizer):
from pretix.base.plugins import get_all_plugins
return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.')
and getattr(p, 'visible', True))
class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView, SingleObjectMixin): class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, TemplateView, SingleObjectMixin):
model = Organizer model = Organizer
context_object_name = 'organizer' context_object_name = 'organizer'
@@ -606,12 +613,6 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
def get_object(self, queryset=None) -> Organizer: def get_object(self, queryset=None) -> Organizer:
return self.request.organizer return self.request.organizer
def available_plugins(self, organizer):
from pretix.base.plugins import get_all_plugins
return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.')
and getattr(p, 'visible', True))
def prepare_links(self, pluginmeta, key): def prepare_links(self, pluginmeta, key):
links = getattr(pluginmeta, key, []) links = getattr(pluginmeta, key, [])
try: try:
@@ -637,7 +638,7 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
from pretix.base.plugins import CATEGORY_LABELS, CATEGORY_ORDER from pretix.base.plugins import CATEGORY_LABELS, CATEGORY_ORDER
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
plugins = list(self.available_plugins(self.object)) plugins = list(available_plugins(self.object))
active_counter = Counter() active_counter = Counter()
events_total = 0 events_total = 0
@@ -685,7 +686,7 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
self.object = self.get_object() self.object = self.get_object()
plugins_available = { plugins_available = {
p.module: p for p in self.available_plugins(self.object) p.module: p for p in available_plugins(self.object)
} }
choose_events_next = False choose_events_next = False
with transaction.atomic(): with transaction.atomic():
@@ -786,12 +787,6 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire
} }
return kwargs return kwargs
def available_plugins(self, organizer):
from pretix.base.plugins import get_all_plugins
return (p for p in get_all_plugins(organizer=organizer) if not p.name.startswith('.')
and getattr(p, 'visible', True))
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
return super().get_context_data( return super().get_context_data(
plugin=self.plugin, plugin=self.plugin,
@@ -799,12 +794,10 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire
) )
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
plugins_available = { try:
p.module: p for p in self.available_plugins(self.request.organizer) self.plugin = next(p for p in available_plugins(self.request.organizer) if p.module == kwargs["plugin"])
} except StopIteration:
if kwargs["plugin"] not in plugins_available:
raise Http404(_("Unknown plugin.")) raise Http404(_("Unknown plugin."))
self.plugin = plugins_available[kwargs["plugin"]]
level = getattr(self.plugin, "level", PLUGIN_LEVEL_EVENT) level = getattr(self.plugin, "level", PLUGIN_LEVEL_EVENT)
if level == PLUGIN_LEVEL_ORGANIZER: if level == PLUGIN_LEVEL_ORGANIZER:
raise Http404(_("This plugin can only be enabled for the entire organizer account.")) raise Http404(_("This plugin can only be enabled for the entire organizer account."))
@@ -835,6 +828,9 @@ class OrganizerPluginEvents(OrganizerDetailViewMixin, OrganizerPermissionRequire
logentries_to_save = [] logentries_to_save = []
for e in self.request.organizer.events.filter(pk__in=events_to_enable): for e in self.request.organizer.events.filter(pk__in=events_to_enable):
if not plugin_is_available(self.plugin, organizer=self.request.organizer, event=e):
messages.warning(self.request, _("This plugin cannot be activated for event {}.").format(e.name))
continue
logentries_to_save.append( logentries_to_save.append(
e.log_action('pretix.event.plugins.enabled', user=self.request.user, data={'plugin': self.plugin.module}, save=False) e.log_action('pretix.event.plugins.enabled', user=self.request.user, data={'plugin': self.plugin.module}, save=False)
) )
+2 -8
View File
@@ -263,12 +263,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
resp = HttpResponse(data, content_type=mimet) resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1] ftype = fname.split(".")[-1]
if settings.DEBUG: resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
# attachment is more secure as we're dealing with user-generated stuff here, but inline is much more convenient during debugging
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
resp._csp_ignore = True
else:
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
return resp return resp
elif "data" in request.POST: elif "data" in request.POST:
if cf: if cf:
@@ -309,6 +304,5 @@ class FontsCSSView(TemplateView):
class PdfView(TemplateView): class PdfView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
cf = get_object_or_404(CachedFile, id=kwargs.get("filename"), filename="background_preview.pdf") cf = get_object_or_404(CachedFile, id=kwargs.get("filename"), filename="background_preview.pdf")
resp = FileResponse(cf.file, content_type='application/pdf') resp = FileResponse(cf.file, filename=cf.filename, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment; filename="{}"'.format(cf.filename)
return resp return resp
+60 -12
View File
@@ -540,20 +540,31 @@ class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateVi
# TODO: LogEntry? # TODO: LogEntry?
messages.success(self.request, _('Your changes have been saved.')) messages.success(self.request, _('Your changes have been saved.'))
if form.has_changed() or any(f.has_changed() for f in self.plugin_forms):
data = { change_data = {
k: form.cleaned_data.get(k) for k in form.changed_data k: (form.cleaned_data.get(k).name
} if isinstance(form.cleaned_data.get(k), File)
for f in self.plugin_forms: else form.cleaned_data.get(k))
data.update({ for k in form.changed_data
k: (f.cleaned_data.get(k).name }
if isinstance(f.cleaned_data.get(k), File) meta_changed = {}
else f.cleaned_data.get(k)) for f in self.meta_forms:
for k in f.changed_data if f.has_changed():
}) meta_changed[f.property.name] = f.cleaned_data["value"]
if meta_changed:
change_data['meta_data'] = meta_changed
for f in self.plugin_forms:
change_data.update({
k: (f.cleaned_data.get(k).name
if isinstance(f.cleaned_data.get(k), File)
else f.cleaned_data.get(k))
for k in f.changed_data
})
if change_data:
self.object.log_action( self.object.log_action(
'pretix.subevent.changed', user=self.request.user, data=data 'pretix.subevent.changed', user=self.request.user, data=change_data
) )
for f in self.plugin_forms: for f in self.plugin_forms:
f.subevent = self.object f.subevent = self.object
f.save() f.save()
@@ -628,6 +639,14 @@ class SubEventCreate(SubEventEditorMixin, EventPermissionRequiredMixin, CreateVi
else f.cleaned_data.get(k)) else f.cleaned_data.get(k))
for k in f.cleaned_data for k in f.cleaned_data
}) })
meta_changed = {}
for f in self.meta_forms:
if f.has_changed():
meta_changed[f.property.name] = f.cleaned_data["value"]
if meta_changed:
data['meta_data'] = meta_changed
form.instance.log_action('pretix.subevent.added', data=dict(data), user=self.request.user) form.instance.log_action('pretix.subevent.added', data=dict(data), user=self.request.user)
self.save_formset(form.instance) self.save_formset(form.instance)
@@ -917,6 +936,35 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Asyn
if len(subevents) > 100_000: if len(subevents) > 100_000:
raise ValidationError(_('Please do not create more than 100.000 dates at once.')) raise ValidationError(_('Please do not create more than 100.000 dates at once.'))
if form.cleaned_data.get("skip_if_overlap") and subevents:
def overlaps(a_from, a_to, b_from, b_to):
if a_from == b_from:
return True
if a_from > b_from:
# a starts after b
# check if it starts before b ends
return b_to and a_from < b_to
# a starts before b
# check if it ends before b starts
return a_to and a_to > b_from
date_min = min(se.date_from for se in subevents)
date_max = max(se.date_to or se.date_from for se in subevents)
dates_existing = list(self.request.event.subevents.annotate(
date_fromto=Coalesce('date_to', 'date_from'),
).filter(
date_from__lte=date_max,
date_fromto__gte=date_min,
).values('date_from', 'date_to'))
subevents = [
se for se in subevents if not any(
overlaps(se.date_from, se.date_to, other['date_from'], other['date_to'])
for other in dates_existing
)
]
if not subevents:
raise ValidationError(_('All dates would be skipped because they conflict with existing dates.'))
for i, se in enumerate(subevents): for i, se in enumerate(subevents):
se.save(clear_cache=False) se.save(clear_cache=False)
if i % 100 == 0: if i % 100 == 0:
+3 -3
View File
@@ -316,7 +316,7 @@ def nav_context_list(request):
page = 1 page = 1
qs_events = request.user.get_events_with_any_permission(request).filter( qs_events = request.user.get_events_with_any_permission(request).filter(
Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query) Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query) | Q(domain__domainname__iexact=query)
).annotate( ).annotate(
min_from=Min('subevents__date_from'), min_from=Min('subevents__date_from'),
max_from=Max('subevents__date_from'), max_from=Max('subevents__date_from'),
@@ -331,7 +331,7 @@ def nav_context_list(request):
else: else:
qs_orga = Organizer.objects.filter(pk__in=request.user.teams.values_list('organizer', flat=True)) qs_orga = Organizer.objects.filter(pk__in=request.user.teams.values_list('organizer', flat=True))
if query: if query:
qs_orga = qs_orga.filter(Q(name__icontains=query) | Q(slug__icontains=query)) qs_orga = qs_orga.filter(Q(name__icontains=query) | Q(slug__icontains=query) | Q(domains__domainname__iexact=query))
qs_orga = qs_orga.annotate( qs_orga = qs_orga.annotate(
n_events=Count("events") n_events=Count("events")
).order_by("-n_events") ).order_by("-n_events")
@@ -619,7 +619,7 @@ def checkinlist_select2(request, **kwargs):
qs = request.event.checkin_lists.select_related('subevent').filter( qs = request.event.checkin_lists.select_related('subevent').filter(
qf qf
).order_by('name') ).order_by('subevent__date_from', 'name', 'pk')
total = qs.count() total = qs.count()
pagesize = 20 pagesize = 20
+6 -1
View File
@@ -117,12 +117,17 @@ class GroupConcat(Aggregate):
template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s' ORDER BY %(field)s::text ASC)" template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s' ORDER BY %(field)s::text ASC)"
else: else:
template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s')" template = "%(function)s(%(distinct)s%(field)s::text, '%(separator)s')"
return super().as_sql(
template, params = super().as_sql(
compiler, connection, compiler, connection,
function='string_agg', function='string_agg',
template=template, template=template,
**extra_context, **extra_context,
) )
if self.ordered:
# ordered statement requires field parameters twice
params = params + params
return template, params
class ReplicaRouter: class ReplicaRouter:
+5 -5
View File
@@ -173,6 +173,7 @@ def create_thumbnail(source, size, formats=None):
# filesystem path, this only works because _open() uses safe_join, which accepts absolute paths if they match the # filesystem path, this only works because _open() uses safe_join, which accepts absolute paths if they match the
# expected base dir. For NanoCDN Files, this works because source.name is set to the storage path. # expected base dir. For NanoCDN Files, this works because source.name is set to the storage path.
source_rb = default_storage.open(source_name, mode='rb') source_rb = default_storage.open(source_name, mode='rb')
source_ext = os.path.splitext(source_name)[1].lower()
image = Image.open(BytesIO(source_rb.read()), formats=formats or settings.PILLOW_FORMATS_QUESTIONS_IMAGE) image = Image.open(BytesIO(source_rb.read()), formats=formats or settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
try: try:
@@ -183,11 +184,14 @@ def create_thumbnail(source, size, formats=None):
frames = [] frames = []
durations = [] durations = []
for f in ImageSequence.Iterator(image): for f in ImageSequence.Iterator(image):
if f.mode in ("P", "PA") and source_ext == '.png':
f = f.convert('RGBA')
if f.mode not in ("1", "L", "RGB", "RGBA"):
f = f.convert('RGB')
durations.append(f.info.get("duration", 1000)) durations.append(f.info.get("duration", 1000))
frames.append(resize_image(f, size)) frames.append(resize_image(f, size))
image_out = frames[0] image_out = frames[0]
save_kwargs = {} save_kwargs = {}
source_ext = os.path.splitext(source_name)[1].lower()
if source_ext == '.jpg' or source_ext == '.jpeg': if source_ext == '.jpg' or source_ext == '.jpeg':
# Yields better file sizes for photos # Yields better file sizes for photos
@@ -211,10 +215,6 @@ def create_thumbnail(source, size, formats=None):
checksum = hashlib.md5(image.tobytes()).hexdigest() checksum = hashlib.md5(image.tobytes()).hexdigest()
name = checksum + '.' + size.replace('^', 'c') + '.' + target_ext name = checksum + '.' + size.replace('^', 'c') + '.' + target_ext
buffer = BytesIO() buffer = BytesIO()
if image_out.mode == "P" and source_ext == '.png':
image_out = image_out.convert('RGBA')
if image_out.mode not in ("1", "L", "RGB", "RGBA"):
image_out = image_out.convert('RGB')
image_out.save(fp=buffer, format=target_ext.upper(), quality=quality, **save_kwargs) image_out.save(fp=buffer, format=target_ext.upper(), quality=quality, **save_kwargs)
imgfile = ContentFile(buffer.getvalue()) imgfile = ContentFile(buffer.getvalue())
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,56 +632,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2021-09-15 11:22+0000\n" "PO-Revision-Date: 2021-09-15 11:22+0000\n"
"Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n" "Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -666,13 +666,13 @@ msgstr "توليد الرسائل …"
msgid "Unknown error." msgid "Unknown error."
msgstr "خطأ غير معروف." msgstr "خطأ غير معروف."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
#, fuzzy #, fuzzy
#| msgid "Your color has great contrast and is very easy to read!" #| msgid "Your color has great contrast and is very easy to read!"
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "اللون يتمتع بتباين كبير وتسهل قراءته!" msgstr "اللون يتمتع بتباين كبير وتسهل قراءته!"
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
#, fuzzy #, fuzzy
#| msgid "Your color has decent contrast and is probably good-enough to read!" #| msgid "Your color has decent contrast and is probably good-enough to read!"
msgid "" msgid ""
@@ -680,46 +680,46 @@ msgid ""
"requirements." "requirements."
msgstr "اللون يحظى بتباين معقول ويمكن أن يكون مناسب للقراءة!" msgstr "اللون يحظى بتباين معقول ويمكن أن يكون مناسب للقراءة!"
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "البحث في الاستفسارات" msgstr "البحث في الاستفسارات"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "الكل" msgstr "الكل"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "لا شيء" msgstr "لا شيء"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "المختارة فقط" msgstr "المختارة فقط"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "قم باستخدم اسم مختلف داخليا" msgstr "قم باستخدم اسم مختلف داخليا"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "اضغط لاغلاق الصفحة" msgstr "اضغط لاغلاق الصفحة"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "لم تقم بحفظ التعديلات!" msgstr "لم تقم بحفظ التعديلات!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,56 +632,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2025-10-31 17:00+0000\n" "PO-Revision-Date: 2025-10-31 17:00+0000\n"
"Last-Translator: Núria Masclans <nuriamasclansserrat@gmail.com>\n" "Last-Translator: Núria Masclans <nuriamasclansserrat@gmail.com>\n"
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -644,11 +644,11 @@ msgstr "Generant missatges…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Error desconegut." msgstr "Error desconegut."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "El teu color té molt contrast i garanteix bona accessibilitat." msgstr "El teu color té molt contrast i garanteix bona accessibilitat."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -656,7 +656,7 @@ msgstr ""
"El teu color té un contrast acceptable i compleix els requisits mínims " "El teu color té un contrast acceptable i compleix els requisits mínims "
"daccessibilitat." "daccessibilitat."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -664,40 +664,40 @@ msgstr ""
"El color no té prou contrast amb el blanc i pot afectar a l'accessibilitat " "El color no té prou contrast amb el blanc i pot afectar a l'accessibilitat "
"del lloc web." "del lloc web."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Consulta de cerca" msgstr "Consulta de cerca"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Tots" msgstr "Tots"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Cap" msgstr "Cap"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Només seleccionats" msgstr "Només seleccionats"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Introdueix un número de pàgina entre 1 i %(max)s." msgstr "Introdueix un número de pàgina entre 1 i %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Número de pàgina no vàlid." msgstr "Número de pàgina no vàlid."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Utilitza un nom diferent internament" msgstr "Utilitza un nom diferent internament"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Prem per tancar" msgstr "Prem per tancar"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Tens canvis sense desar!" msgstr "Tens canvis sense desar!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-01-08 04:00+0000\n" "PO-Revision-Date: 2026-01-08 04:00+0000\n"
"Last-Translator: Jiří Pastrňák <jiri@pastrnak.email>\n" "Last-Translator: Jiří Pastrňák <jiri@pastrnak.email>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -657,57 +657,57 @@ msgstr "Vytváření zpráv…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Neznámá chyba." msgstr "Neznámá chyba."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "Tato barva má velmi dobrý kontrast a je velmi dobře čitelná." msgstr "Tato barva má velmi dobrý kontrast a je velmi dobře čitelná."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
"Tato barva má slušný kontrast a pravděpodobně je dostatečně dobře čitelná." "Tato barva má slušný kontrast a pravděpodobně je dostatečně dobře čitelná."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Hledaný výraz" msgstr "Hledaný výraz"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Všechny" msgstr "Všechny"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Žádný" msgstr "Žádný"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Pouze vybrané" msgstr "Pouze vybrané"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Interně používat jiný název" msgstr "Interně používat jiný název"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Kliknutím zavřete" msgstr "Kliknutím zavřete"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Máte neuložené změny!" msgstr "Máte neuložené změny!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -633,56 +633,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -6,8 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2024-07-10 15:00+0000\n" "PO-Revision-Date: 2026-04-22 18:00+0000\n"
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n" "Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
"da/>\n" "da/>\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.1\n" "X-Generator: Weblate 5.17\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56 #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62 #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -682,56 +682,56 @@ msgstr "Opretter beskeder …"
msgid "Unknown error." msgid "Unknown error."
msgstr "Ukendt fejl." msgstr "Ukendt fejl."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr "Søgeforespørgsel"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Ingen" msgstr "Ingen"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Klik for at lukke" msgstr "Klik for at lukke"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Du har ændringer, der ikke er gemt!" msgstr "Du har ændringer, der ikke er gemt!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-17 14:27+0000\n" "PO-Revision-Date: 2026-03-17 14:27+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n" "Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -650,12 +650,12 @@ msgstr "Generiere Nachrichten…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Unbekannter Fehler." msgstr "Unbekannter Fehler."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"Diese Farbe hat einen sehr guten Kontrast und trägt zur Barrierefreiheit bei!" "Diese Farbe hat einen sehr guten Kontrast und trägt zur Barrierefreiheit bei!"
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -663,7 +663,7 @@ msgstr ""
"Diese Farbe hat einen ausreichenden Kontrast und genügt den " "Diese Farbe hat einen ausreichenden Kontrast und genügt den "
"Mindestanforderungen der Barrierefreiheit." "Mindestanforderungen der Barrierefreiheit."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -671,40 +671,40 @@ msgstr ""
"Diese Farbe hat keinen ausreichenden Kontrast zu weiß. Die Barrierefreiheit " "Diese Farbe hat keinen ausreichenden Kontrast zu weiß. Die Barrierefreiheit "
"der Seite ist eingeschränkt." "der Seite ist eingeschränkt."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Suchbegriff" msgstr "Suchbegriff"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Keine" msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Nur ausgewählte" msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Geben Sie eine Seitenzahl zwischen 1 und %(max)s ein." msgstr "Geben Sie eine Seitenzahl zwischen 1 und %(max)s ein."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Ungültige Seitenzahl." msgstr "Ungültige Seitenzahl."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden" msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Klicken zum Schließen" msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Sie haben ungespeicherte Änderungen!" msgstr "Sie haben ungespeicherte Änderungen!"
+1
View File
@@ -302,6 +302,7 @@ Personalisierung
P.IVA P.IVA
PKCE-Erweiterung PKCE-Erweiterung
Platzhalterzeichen Platzhalterzeichen
PLN
Play Play
Plugin Plugin
Plugins Plugins
File diff suppressed because it is too large Load Diff
@@ -7,9 +7,9 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-17 14:30+0000\n" "PO-Revision-Date: 2026-05-04 07:42+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n" "Last-Translator: Martin Gross <gross@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/" "Language-Team: German (informal) <https://translate.pretix.eu/projects/"
"pretix/pretix-js/de_Informal/>\n" "pretix/pretix-js/de_Informal/>\n"
"Language: de_Informal\n" "Language: de_Informal\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.16.2\n" "X-Generator: Weblate 5.17\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56 #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62 #: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -428,8 +428,7 @@ msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:276 #: pretix/static/pretixbase/js/asynctask.js:276
msgid "If this takes longer than a few minutes, please contact us." msgid "If this takes longer than a few minutes, please contact us."
msgstr "" msgstr "Wenn dies länger als einige Minuten dauert, kontaktiere uns bitte."
"Wenn dies länger als einige Minuten dauert, kontaktieren Sie uns bitte."
#: pretix/static/pretixbase/js/asynctask.js:331 #: pretix/static/pretixbase/js/asynctask.js:331
msgid "Close message" msgid "Close message"
@@ -650,12 +649,12 @@ msgstr "Generiere Nachrichten…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Unbekannter Fehler." msgstr "Unbekannter Fehler."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"Diese Farbe hat einen sehr guten Kontrast und trägt zur Barrierefreiheit bei!" "Diese Farbe hat einen sehr guten Kontrast und trägt zur Barrierefreiheit bei!"
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -663,7 +662,7 @@ msgstr ""
"Diese Farbe hat einen ausreichenden Kontrast und genügt den " "Diese Farbe hat einen ausreichenden Kontrast und genügt den "
"Mindestanforderungen der Barrierefreiheit." "Mindestanforderungen der Barrierefreiheit."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -671,40 +670,40 @@ msgstr ""
"Diese Farbe hat keinen ausreichenden Kontrast zu weiß. Die Barrierefreiheit " "Diese Farbe hat keinen ausreichenden Kontrast zu weiß. Die Barrierefreiheit "
"der Seite ist eingeschränkt." "der Seite ist eingeschränkt."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Suchbegriff" msgstr "Suchbegriff"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Keine" msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Nur ausgewählte" msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Gib eine Seitenzahl zwischen 1 und %(max)s ein." msgstr "Gib eine Seitenzahl zwischen 1 und %(max)s ein."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Ungültige Seitenzahl." msgstr "Ungültige Seitenzahl."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden" msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Klicken zum Schließen" msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Du hast ungespeicherte Änderungen!" msgstr "Du hast ungespeicherte Änderungen!"
@@ -302,6 +302,7 @@ Personalisierung
P.IVA P.IVA
PKCE-Erweiterung PKCE-Erweiterung
Platzhalterzeichen Platzhalterzeichen
PLN
Play Play
Plugin Plugin
Plugins Plugins
+1147 -1106
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-30 11:25+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,56 +632,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2024-12-22 00:00+0000\n" "PO-Revision-Date: 2024-12-22 00:00+0000\n"
"Last-Translator: Dimitris Tsimpidis <tsimpidisd@gmail.com>\n" "Last-Translator: Dimitris Tsimpidis <tsimpidisd@gmail.com>\n"
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -689,14 +689,14 @@ msgstr "Δημιουργία μηνυμάτων …"
msgid "Unknown error." msgid "Unknown error."
msgstr "Άγνωστο σφάλμα." msgstr "Άγνωστο σφάλμα."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
#, fuzzy #, fuzzy
#| msgid "Your color has great contrast and is very easy to read!" #| msgid "Your color has great contrast and is very easy to read!"
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"Το χρώμα σας έχει μεγάλη αντίθεση και είναι πολύ εύκολο να το διαβάσετε!" "Το χρώμα σας έχει μεγάλη αντίθεση και είναι πολύ εύκολο να το διαβάσετε!"
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
#, fuzzy #, fuzzy
#| msgid "Your color has decent contrast and is probably good-enough to read!" #| msgid "Your color has decent contrast and is probably good-enough to read!"
msgid "" msgid ""
@@ -706,46 +706,46 @@ msgstr ""
"Το χρώμα σας έχει αξιοπρεπή αντίθεση και είναι ίσως αρκετά καλό για να " "Το χρώμα σας έχει αξιοπρεπή αντίθεση και είναι ίσως αρκετά καλό για να "
"διαβάσετε!" "διαβάσετε!"
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Όλα" msgstr "Όλα"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Κανένας" msgstr "Κανένας"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά" msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Κάντε κλικ για να κλείσετε" msgstr "Κάντε κλικ για να κλείσετε"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,56 +632,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-30 03:00+0000\n" "PO-Revision-Date: 2026-03-30 03:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n" "Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -648,12 +648,12 @@ msgstr "Generando mensajes…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Error desconocido." msgstr "Error desconocido."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"El color tiene un gran contraste y proporcionará una excelente accesibilidad." "El color tiene un gran contraste y proporcionará una excelente accesibilidad."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -661,7 +661,7 @@ msgstr ""
"El color tiene un contraste decente y es suficiente para los requisitos " "El color tiene un contraste decente y es suficiente para los requisitos "
"mínimos de accesibilidad." "mínimos de accesibilidad."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -669,40 +669,40 @@ msgstr ""
"El color no tiene suficiente contraste con el blanco. La accesibilidad de su " "El color no tiene suficiente contraste con el blanco. La accesibilidad de su "
"sitio se verá afectada." "sitio se verá afectada."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Consulta de búsqueda" msgstr "Consulta de búsqueda"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Ninguno" msgstr "Ninguno"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Solamente seleccionados" msgstr "Solamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Introduce un número de página entre 1 y %(max)s." msgstr "Introduce un número de página entre 1 y %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Número de página inválido." msgstr "Número de página inválido."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Usar un nombre diferente internamente" msgstr "Usar un nombre diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Click para cerrar" msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "¡Tienes cambios sin guardar!" msgstr "¡Tienes cambios sin guardar!"
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2025-08-04 14:16+0200\n" "PO-Revision-Date: 2025-08-04 14:16+0200\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@@ -633,56 +633,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2025-12-24 00:00+0000\n" "PO-Revision-Date: 2025-12-24 00:00+0000\n"
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n" "Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
"Language-Team: Estonian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Estonian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -633,56 +633,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2024-09-06 08:47+0000\n" "PO-Revision-Date: 2024-09-06 08:47+0000\n"
"Last-Translator: Albizuri <oier@puntu.eus>\n" "Last-Translator: Albizuri <oier@puntu.eus>\n"
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -645,56 +645,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Guztiak" msgstr "Guztiak"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2021-11-10 05:00+0000\n" "PO-Revision-Date: 2021-11-10 05:00+0000\n"
"Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n" "Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n"
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -663,56 +663,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "Tuntematon virhe." msgstr "Tuntematon virhe."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Kaikki" msgstr "Kaikki"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Käytä toista nimeä sisäisesti" msgstr "Käytä toista nimeä sisäisesti"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Sulje klikkaamalla" msgstr "Sulje klikkaamalla"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Sinulla on tallentamattomia muutoksia!" msgstr "Sinulla on tallentamattomia muutoksia!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -632,56 +632,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: French\n" "Project-Id-Version: French\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-18 12:23+0000\n" "PO-Revision-Date: 2026-03-18 12:23+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n" "Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -650,12 +650,12 @@ msgstr "Création de messages …"
msgid "Unknown error." msgid "Unknown error."
msgstr "Erreur inconnue." msgstr "Erreur inconnue."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"Votre choix de couleur a un bon contraste et il est très facile à lire." "Votre choix de couleur a un bon contraste et il est très facile à lire."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -663,7 +663,7 @@ msgstr ""
"Votre choix de couleur est assez bon pour la lecture et offre un bon " "Votre choix de couleur est assez bon pour la lecture et offre un bon "
"contraste." "contraste."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -671,40 +671,40 @@ msgstr ""
"Votre choix de couleur n'est pas assez contrastée par rapport au blanc. " "Votre choix de couleur n'est pas assez contrastée par rapport au blanc. "
"L'accessibilité de votre site en sera affectée." "L'accessibilité de votre site en sera affectée."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Requête de recherche" msgstr "Requête de recherche"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Tous" msgstr "Tous"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Aucun" msgstr "Aucun"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Seuls les sélectionnés" msgstr "Seuls les sélectionnés"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Saisir le numéro de page entre 1 et %(max)s." msgstr "Saisir le numéro de page entre 1 et %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Numéro de page invalide." msgstr "Numéro de page invalide."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Utiliser un nom différent en interne" msgstr "Utiliser un nom différent en interne"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Cliquez pour fermer" msgstr "Cliquez pour fermer"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Vous avez des modifications non sauvegardées !" msgstr "Vous avez des modifications non sauvegardées !"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-02 21:00+0000\n" "PO-Revision-Date: 2026-03-02 21:00+0000\n"
"Last-Translator: Sandra Rial Pérez <sandrarial@gestiontickets.online>\n" "Last-Translator: Sandra Rial Pérez <sandrarial@gestiontickets.online>\n"
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -646,13 +646,13 @@ msgstr "Xerando mensaxes…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Erro descoñecido." msgstr "Erro descoñecido."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
"A túa cor ten un gran contraste e proporcionará unha excelente " "A túa cor ten un gran contraste e proporcionará unha excelente "
"accesibilidade." "accesibilidade."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
@@ -660,7 +660,7 @@ msgstr ""
"A túa cor ten un contraste decente e é suficiente para os requisitos mínimos " "A túa cor ten un contraste decente e é suficiente para os requisitos mínimos "
"de accesibilidade." "de accesibilidade."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
@@ -668,40 +668,40 @@ msgstr ""
"A túa cor non ten suficiente contraste co branco. A accesibilidade do teu " "A túa cor non ten suficiente contraste co branco. A accesibilidade do teu "
"sitio web verase afectada." "sitio web verase afectada."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "Consultar unha procura" msgstr "Consultar unha procura"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Ningún" msgstr "Ningún"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "Soamente seleccionados" msgstr "Soamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Introduza o número de páxina entre 1 e %(max)s." msgstr "Introduza o número de páxina entre 1 e %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Número de páxina non válido." msgstr "Número de páxina non válido."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Usar un nome diferente internamente" msgstr "Usar un nome diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Click para cerrar" msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Tes cambios sen gardar!" msgstr "Tes cambios sen gardar!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-02-09 21:00+0000\n" "PO-Revision-Date: 2026-02-09 21:00+0000\n"
"Last-Translator: roi belotsercovsky <rbelotsercovsky@gmail.com>\n" "Last-Translator: roi belotsercovsky <rbelotsercovsky@gmail.com>\n"
"Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -638,56 +638,56 @@ msgstr "יוצר הודעות…"
msgid "Unknown error." msgid "Unknown error."
msgstr "שגיאה לא ידועה." msgstr "שגיאה לא ידועה."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "לצבע שלך יש ניגודיות מצויינת ויאפשר נגישות טובה." msgstr "לצבע שלך יש ניגודיות מצויינת ויאפשר נגישות טובה."
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "לצבע שלך יש ניגודיות סבירה ומתאים לדרישות הנגישות המינימליות." msgstr "לצבע שלך יש ניגודיות סבירה ומתאים לדרישות הנגישות המינימליות."
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "לצבע שלך יש ניגודיות חלשה מדי ביחד לצבע לבן. נגישות האתר תיפגע." msgstr "לצבע שלך יש ניגודיות חלשה מדי ביחד לצבע לבן. נגישות האתר תיפגע."
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "שאילתת חיפוש" msgstr "שאילתת חיפוש"
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "הכל" msgstr "הכל"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "כלום" msgstr "כלום"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "שנבחרו בלבד" msgstr "שנבחרו בלבד"
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "הכנס מספר דף בין 1 ל %(max)s." msgstr "הכנס מספר דף בין 1 ל %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "מספר דף לא תקין." msgstr "מספר דף לא תקין."
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "השתמש בשם אחר לצורך פנימי" msgstr "השתמש בשם אחר לצורך פנימי"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "לחץ לסגירה" msgstr "לחץ לסגירה"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "יש לך שינויים שלא נשמרו!" msgstr "יש לך שינויים שלא נשמרו!"
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2025-03-16 10:17+0000\n" "PO-Revision-Date: 2025-03-16 10:17+0000\n"
"Last-Translator: Robert Rigo <kontakt@bicikli.hr>\n" "Last-Translator: Robert Rigo <kontakt@bicikli.hr>\n"
"Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -634,56 +634,56 @@ msgstr ""
msgid "Unknown error." msgid "Unknown error."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
msgid "" msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility " "Your color has decent contrast and is sufficient for minimum accessibility "
"requirements." "requirements."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-17 14:06+0000\n" "POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-01-23 15:00+0000\n" "PO-Revision-Date: 2026-01-23 15:00+0000\n"
"Last-Translator: Vajda Tamás <vajda.tamas@szwg.hu>\n" "Last-Translator: Vajda Tamás <vajda.tamas@szwg.hu>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -680,13 +680,13 @@ msgstr "Üzenetek generálása…"
msgid "Unknown error." msgid "Unknown error."
msgstr "Ismeretlen hiba." msgstr "Ismeretlen hiba."
#: pretix/static/pretixcontrol/js/ui/main.js:309 #: pretix/static/pretixcontrol/js/ui/main.js:310
#, fuzzy #, fuzzy
#| msgid "Your color has great contrast and is very easy to read!" #| msgid "Your color has great contrast and is very easy to read!"
msgid "Your color has great contrast and will provide excellent accessibility." msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "A választott színek remek kontrasztot adnak, és nagyon könnyű olvasni!" msgstr "A választott színek remek kontrasztot adnak, és nagyon könnyű olvasni!"
#: pretix/static/pretixcontrol/js/ui/main.js:313 #: pretix/static/pretixcontrol/js/ui/main.js:314
#, fuzzy #, fuzzy
#| msgid "Your color has decent contrast and is probably good-enough to read!" #| msgid "Your color has decent contrast and is probably good-enough to read!"
msgid "" msgid ""
@@ -695,46 +695,46 @@ msgid ""
msgstr "" msgstr ""
"A választott színek kontrasztja elégséges, és valószínűleg jól olvasható!" "A választott színek kontrasztja elégséges, és valószínűleg jól olvasható!"
#: pretix/static/pretixcontrol/js/ui/main.js:317 #: pretix/static/pretixcontrol/js/ui/main.js:318
msgid "" msgid ""
"Your color has insufficient contrast to white. Accessibility of your site " "Your color has insufficient contrast to white. Accessibility of your site "
"will be impacted." "will be impacted."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:445 #: pretix/static/pretixcontrol/js/ui/main.js:446
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:466
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:463 #: pretix/static/pretixcontrol/js/ui/main.js:464
msgid "All" msgid "All"
msgstr "Összes" msgstr "Összes"
#: pretix/static/pretixcontrol/js/ui/main.js:464 #: pretix/static/pretixcontrol/js/ui/main.js:465
msgid "None" msgid "None"
msgstr "Semmi" msgstr "Semmi"
#: pretix/static/pretixcontrol/js/ui/main.js:468 #: pretix/static/pretixcontrol/js/ui/main.js:469
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:841 #: pretix/static/pretixcontrol/js/ui/main.js:842
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:844 #: pretix/static/pretixcontrol/js/ui/main.js:845
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1002 #: pretix/static/pretixcontrol/js/ui/main.js:1003
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Használj másik nevet" msgstr "Használj másik nevet"
#: pretix/static/pretixcontrol/js/ui/main.js:1042 #: pretix/static/pretixcontrol/js/ui/main.js:1043
msgid "Click to close" msgid "Click to close"
msgstr "Bezárásért kattints" msgstr "Bezárásért kattints"
#: pretix/static/pretixcontrol/js/ui/main.js:1123 #: pretix/static/pretixcontrol/js/ui/main.js:1124
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Mentetlen változtatások!" msgstr "Mentetlen változtatások!"
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More