Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
# Spanish translations for camper package
# Traducciones al español para el paquete camper.
# Copyright (C) 2023 THE camper'S COPYRIGHT HOLDER
# This file is distributed under the same license as the camper package.
# jordi fita mas <jordi@tandem.blog>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
2024-02-29 15:59:30 +00:00
"POT-Creation-Date: 2024-02-29 16:55+0100\n"
2024-02-06 09:55:29 +00:00
"PO-Revision-Date: 2024-02-06 10:04+0100\n"
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
2024-02-06 09:55:29 +00:00
"X-Generator: Poedit 3.4.2\n"
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
2024-01-31 14:12:11 +00:00
#: web/templates/campground_map.svg:1598
msgctxt "title"
msgid "Zones"
msgstr "Zonas"
#: web/templates/campground_map.svg:1599
msgctxt "tooltip"
msgid "Zone 7"
msgstr "Zona 7"
#: web/templates/campground_map.svg:1600
msgctxt "tooltip"
msgid "Zone 6"
msgstr "Zona 6"
#: web/templates/campground_map.svg:1601
msgctxt "tooltip"
msgid "Zone 5"
msgstr "Zona 6"
#: web/templates/campground_map.svg:1602
msgctxt "tooltip"
msgid "Zone 4"
msgstr "Zona 4"
#: web/templates/campground_map.svg:1603
msgctxt "tooltip"
msgid "Zone 3"
msgstr "Zona 3"
#: web/templates/campground_map.svg:1604
msgctxt "tooltip"
msgid "Zone 2"
msgstr "Zona 2"
#: web/templates/campground_map.svg:1605
msgctxt "tooltip"
msgid "Zone 1"
msgstr "Zona 1"
2024-02-29 15:59:30 +00:00
#: web/templates/mail/payment/details.gotxt:1
2024-02-13 04:20:35 +00:00
#: web/templates/mail/payment/body.gohtml:33
#: web/templates/mail/payment/body.gotxt:1
msgid "Hi %s,"
msgstr "Hola %s,"
2024-02-29 15:59:30 +00:00
#: web/templates/mail/payment/details.gotxt:3
2024-02-13 04:20:35 +00:00
#: web/templates/mail/payment/body.gohtml:35
#: web/templates/mail/payment/body.gotxt:3
msgid "We have successfully received the payment for the booking with the following details:"
msgstr "Hemos recibido correctamente el pago de la reserva con los siguientes detalles:"
2024-02-29 15:59:30 +00:00
#: web/templates/mail/payment/details.gotxt:7
#: web/templates/admin/payment/details.gohtml:19
msgctxt "title"
msgid "Payment"
msgstr "Pago"
#: web/templates/mail/payment/details.gotxt:9
#: web/templates/admin/payment/index.gohtml:21
#: web/templates/admin/payment/details.gohtml:22
#: web/templates/admin/booking/index.gohtml:21
msgctxt "header"
msgid "Reference"
msgstr "Referencia"
#: web/templates/mail/payment/details.gotxt:10
#: web/templates/admin/payment/index.gohtml:22
#: web/templates/admin/payment/details.gohtml:26
#: web/templates/admin/booking/index.gohtml:25
msgctxt "header"
msgid "Status"
msgstr "Estado"
#: web/templates/mail/payment/details.gotxt:11
#: web/templates/admin/payment/details.gohtml:30
msgctxt "payment header"
msgid "Created at"
msgstr "Creado el"
#: web/templates/mail/payment/details.gotxt:12
#: web/templates/admin/payment/details.gohtml:34
msgctxt "payment header"
msgid "Last updated at"
msgstr "Actualizado por última vez el"
#: web/templates/mail/payment/details.gotxt:14
#: web/templates/public/layout.gohtml:71
#: web/templates/public/booking/page.gohtml:7
#: web/templates/admin/payment/details.gohtml:41
msgctxt "title"
msgid "Booking"
msgstr "Reserva"
#: web/templates/mail/payment/details.gotxt:16
#: web/templates/public/booking/fields.gohtml:14
#: web/templates/admin/payment/details.gohtml:44
msgctxt "title"
msgid "Accommodation"
msgstr "Alojamientos"
#: web/templates/mail/payment/details.gotxt:17
#: web/templates/admin/payment/details.gohtml:48
msgctxt "header"
msgid "Area preferences"
msgstr "Preferencias de área"
#: web/templates/mail/payment/details.gotxt:18
#: web/templates/public/campsite/dates.gohtml:4
#: web/templates/public/booking/fields.gohtml:30
#: web/templates/admin/payment/details.gohtml:52
msgctxt "input"
msgid "Arrival date"
msgstr "Fecha de llegada"
#: web/templates/mail/payment/details.gotxt:19
#: web/templates/public/campsite/dates.gohtml:15
#: web/templates/public/booking/fields.gohtml:41
#: web/templates/admin/payment/details.gohtml:56
msgctxt "input"
msgid "Departure date"
msgstr "Fecha de salida"
#: web/templates/mail/payment/details.gotxt:20
#: web/templates/admin/payment/details.gohtml:60
msgctxt "cart"
msgid "Nights"
msgstr "Noches"
#: web/templates/mail/payment/details.gotxt:21
#: web/templates/public/booking/fields.gohtml:60
#: web/templates/admin/payment/details.gohtml:64
msgctxt "input"
msgid "Adults aged 17 or older"
msgstr "Adultos de 17 años o más"
#: web/templates/mail/payment/details.gotxt:22
#: web/templates/public/booking/fields.gohtml:71
#: web/templates/admin/payment/details.gohtml:68
msgctxt "input"
msgid "Teenagers from 11 to 16 years old"
msgstr "Adolescentes de 11 a 16 años"
#: web/templates/mail/payment/details.gotxt:23
#: web/templates/public/booking/fields.gohtml:82
#: web/templates/admin/payment/details.gohtml:72
msgctxt "input"
msgid "Children from 2 to 10 years old"
msgstr "Niños de 2 a 10 años"
#: web/templates/mail/payment/details.gotxt:24
#: web/templates/public/booking/fields.gohtml:100
#: web/templates/admin/payment/details.gohtml:76
msgctxt "input"
msgid "Dogs"
msgstr "Perros"
#: web/templates/mail/payment/details.gotxt:25
#: web/templates/admin/payment/details.gohtml:80 pkg/booking/cart.go:191
msgctxt "cart"
msgid "Tourist tax"
msgstr "Impuesto turístico"
#: web/templates/mail/payment/details.gotxt:26
#: web/templates/public/booking/fields.gohtml:242
msgctxt "cart"
msgid "Total"
msgstr "Total"
#: web/templates/mail/payment/details.gotxt:27
#: web/templates/public/booking/fields.gohtml:247
#: web/templates/admin/payment/details.gohtml:84
msgctxt "cart"
msgid "Down payment"
msgstr "A cuenta"
#: web/templates/mail/payment/details.gotxt:30
#: web/templates/admin/payment/details.gohtml:92
#: web/templates/admin/campsite/type/option/form.gohtml:18
#: web/templates/admin/campsite/type/option/index.gohtml:6
#: web/templates/admin/campsite/type/option/index.gohtml:17
msgctxt "title"
msgid "Campsite Type Options"
msgstr "Opciones del tipo de alojamiento"
#: web/templates/mail/payment/details.gotxt:38
#: web/templates/public/booking/fields.gohtml:146
#: web/templates/admin/payment/details.gohtml:106
msgctxt "title"
msgid "Customer Details"
msgstr "Detalles del cliente"
#: web/templates/mail/payment/details.gotxt:40
#: web/templates/public/booking/fields.gohtml:149
#: web/templates/admin/payment/details.gohtml:109
msgctxt "input"
msgid "Full name"
msgstr "Nombre y apellidos"
#: web/templates/mail/payment/details.gotxt:41
#: web/templates/public/booking/fields.gohtml:158
#: web/templates/admin/payment/details.gohtml:113
#: web/templates/admin/taxDetails.gohtml:69
msgctxt "input"
msgid "Address"
msgstr "Dirección"
#: web/templates/mail/payment/details.gotxt:42
#: web/templates/public/booking/fields.gohtml:167
#: web/templates/admin/payment/details.gohtml:117
#: web/templates/admin/taxDetails.gohtml:93
msgctxt "input"
msgid "Postcode"
msgstr "Código postal"
#: web/templates/mail/payment/details.gotxt:43
#: web/templates/admin/payment/details.gohtml:121
#: web/templates/admin/taxDetails.gohtml:77
msgctxt "input"
msgid "City"
msgstr "Población"
#: web/templates/mail/payment/details.gotxt:44
#: web/templates/public/booking/fields.gohtml:185
#: web/templates/admin/payment/details.gohtml:125
#: web/templates/admin/taxDetails.gohtml:101
msgctxt "input"
msgid "Country"
msgstr "País"
#: web/templates/mail/payment/details.gotxt:45
#: web/templates/public/booking/fields.gohtml:196
#: web/templates/admin/payment/details.gohtml:129
#: web/templates/admin/login.gohtml:27 web/templates/admin/profile.gohtml:38
#: web/templates/admin/taxDetails.gohtml:53
msgctxt "input"
msgid "Email"
msgstr "Correo-e"
#: web/templates/mail/payment/details.gotxt:46
#: web/templates/public/booking/fields.gohtml:205
#: web/templates/admin/payment/details.gohtml:133
#: web/templates/admin/taxDetails.gohtml:45
msgctxt "input"
msgid "Phone"
msgstr "Teléfono"
#: web/templates/mail/payment/details.gotxt:47
#: web/templates/admin/payment/details.gohtml:137
#: web/templates/admin/profile.gohtml:68
msgctxt "input"
msgid "Language"
msgstr "Idioma"
#: web/templates/mail/payment/details.gotxt:48
#: web/templates/admin/payment/details.gohtml:141
msgctxt "input"
msgid "ACSI card?"
msgstr "¿Tarjeta ACSI?"
#: web/templates/mail/payment/details.gotxt:48
#: web/templates/admin/payment/details.gohtml:142
#: web/templates/admin/campsite/index.gohtml:41
#: web/templates/admin/campsite/type/index.gohtml:53
#: web/templates/admin/season/index.gohtml:44
#: web/templates/admin/user/login-attempts.gohtml:31
#: web/templates/admin/amenity/index.gohtml:40
msgid "Yes"
msgstr "Sí"
#: web/templates/mail/payment/details.gotxt:48
#: web/templates/admin/payment/details.gohtml:142
#: web/templates/admin/campsite/index.gohtml:41
#: web/templates/admin/campsite/type/index.gohtml:53
#: web/templates/admin/season/index.gohtml:44
#: web/templates/admin/user/login-attempts.gohtml:31
#: web/templates/admin/amenity/index.gohtml:40
msgid "No"
msgstr "No"
#: web/templates/mail/payment/details.gotxt:54
msgid "Best regards,"
msgstr "Saludos,"
#: web/templates/mail/payment/body.gohtml:6
msgctxt "title"
msgid "Booking Payment Notification"
msgstr "Notificación de pago de reserva"
2024-02-13 04:20:35 +00:00
#: web/templates/mail/payment/body.gohtml:37
msgid "Payment reference: <strong>%s</strong>"
msgstr "Referencia del pago: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:39
msgid "Accommodation: <strong>%s</strong>"
msgstr "Alojamiento: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:41
msgid "Arrival Date: <strong>%s</strong>"
msgstr "Fecha de llegada: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:43
msgid "Departure Date: <strong>%s</strong>"
msgstr "Fecha de salida: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:45
msgid "Total: <strong>%s</strong>"
msgstr "Total: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:48
2024-02-13 22:45:25 +00:00
msgid "Down payment: <strong>%s</strong>"
msgstr "A cuenta: <strong>%s</strong>"
#: web/templates/mail/payment/body.gohtml:52
#: web/templates/mail/payment/body.gotxt:12
2024-02-13 04:20:35 +00:00
msgid "Thank you for your booking, and see you soon!"
msgstr "Gracias por su reserva y ¡hasta pronto!"
#: web/templates/mail/payment/body.gotxt:5
msgid "Payment reference: **%s**"
msgstr "Referencia del pago: **%s**"
#: web/templates/mail/payment/body.gotxt:6
msgid "Accommodation: **%s**"
msgstr "Alojamiento: **%s**"
#: web/templates/mail/payment/body.gotxt:7
msgid "Arrival Date: **%s**"
msgstr "Fecha de llegada: **%s**"
#: web/templates/mail/payment/body.gotxt:8
msgid "Departure Date: **%s**"
msgstr "Fecha de salida: **%s**"
#: web/templates/mail/payment/body.gotxt:9
msgid "Total: **%s**"
msgstr "Total: **%s**"
2024-02-13 22:45:25 +00:00
#: web/templates/mail/payment/body.gotxt:10
msgid "Down payment: **%s**"
msgstr "A cuenta: **%s**"
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#: web/templates/public/payment/success.gohtml:6
msgctxt "title"
msgid "Payment Successful"
msgstr "Pago con éxito"
2024-02-12 17:06:17 +00:00
#: web/templates/public/payment/success.gohtml:12
msgid "We have received the payment. Thank you."
msgstr "Hemos recibido su pago. Gracias."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#: web/templates/public/payment/request.gohtml:6
msgctxt "title"
2024-02-12 17:06:17 +00:00
msgid "Booking Payment"
msgstr "Pago de la reserva"
#: web/templates/public/payment/request.gohtml:18
msgid "Thank you for your booking. Please, click the button below to pay with a credit card via Servired/Redsys."
msgstr "Gracias por vuestro pedido. Haced clic al botón de abajo para pagar con tarjeta de crédito vía Servired/Redsys."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-12 17:06:17 +00:00
#: web/templates/public/payment/request.gohtml:27
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgctxt "action"
2024-02-12 17:06:17 +00:00
msgid "Pay with credit card"
msgstr "Pagar con tarjeta de crédito"
#: web/templates/public/payment/request.gohtml:30
msgid "Please, wait until we redirect you to the payment page."
msgstr "Esperad mientras se os redirige a la página de pago."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#: web/templates/public/payment/failure.gohtml:6
msgctxt "title"
msgid "Payment Failed"
msgstr "Pago fallido"
2024-02-12 17:06:17 +00:00
#: web/templates/public/payment/failure.gohtml:12
msgid "We could not process the payment. Please, contact us for support."
msgstr "No hemos podido procesar su pago. Póngase en contacto con nosotros para solucionar el problema."
#: web/templates/public/payment/details.gohtml:4
msgctxt "title"
msgid "Order Number"
msgstr "Número de pedido"
#: web/templates/public/payment/details.gohtml:8
msgctxt "title"
msgid "Date"
msgstr "Fecha"
#: web/templates/public/payment/details.gohtml:12
msgctxt "title"
msgid "Total"
msgstr "Total"
2024-02-13 22:45:25 +00:00
#: web/templates/public/payment/details.gohtml:17
msgctxt "title"
msgid "Down Payment"
msgstr "A cuenta"
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
#: web/templates/public/services.gohtml:7
#: web/templates/public/services.gohtml:16
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:59
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
msgid "Services"
msgstr "Servicios"
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
#: web/templates/public/services.gohtml:19
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgid "The campsite offers many different services."
msgstr "El camping dispone de varios servicios."
2024-01-27 21:51:41 +00:00
#: web/templates/public/amenity.gohtml:39
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:114
2024-01-27 21:51:41 +00:00
#: web/templates/public/campsite/page.gohtml:39
msgctxt "title"
msgid "Features"
msgstr "Características"
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
#: web/templates/public/location.gohtml:7
#: web/templates/public/location.gohtml:13
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:70 web/templates/public/layout.gohtml:98
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:64
2023-12-21 20:17:04 +00:00
msgctxt "title"
msgid "Location"
msgstr "Cómo llegar"
2024-02-29 15:59:30 +00:00
#: web/templates/public/home.gohtml:7 web/templates/public/layout.gohtml:54
#: web/templates/public/layout.gohtml:94
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgctxt "title"
msgid "Home"
msgstr "Inicio"
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:25
2023-09-05 02:40:48 +00:00
msgctxt "link"
msgid "Booking"
msgstr "Reservar"
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:28
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
msgid "The pleasure of camping in the middle of nature…"
msgstr "El placer de acampar en plena naturaleza…"
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:40
2023-09-05 02:40:48 +00:00
msgid "Our services"
msgstr "Nuestros servicios"
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:44
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
#: web/templates/public/surroundings.gohtml:7
#: web/templates/public/surroundings.gohtml:12
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:69 web/templates/public/layout.gohtml:97
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:15
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:67
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
2023-09-11 02:20:21 +00:00
msgid "Surroundings"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgstr "El entorno"
2023-09-05 02:40:48 +00:00
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:47
2023-09-11 02:20:21 +00:00
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situados en la <strong>Alta Garrotxa</strong>, entre los <strong>Pirineos</strong> y la <strong>Costa Brava</strong>."
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:48
2023-09-11 02:20:21 +00:00
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda d’ en Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgstr "Cerca tenéis los <strong>piletones de Sadernes</strong>, <strong>volcanes</strong>, <strong>La Fageda d’ en Jordà</strong>, la judería de <strong>Besalú</strong>, el riscal basáltico de <strong>Castellfollit de la Roca</strong>… mucho por ver y mucho por hacer."
2023-09-11 02:20:21 +00:00
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:49
2023-09-11 02:20:21 +00:00
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal d’ Empordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menos de una hora de <strong>Girona</strong>, a una de <strong>La Bisbal d’ Empordà</strong> y a dos de <strong>Barcelona</strong>."
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: web/templates/public/home.gohtml:50
2024-02-06 09:55:29 +00:00
msgid "Discover"
msgstr "Descubre"
2023-09-11 02:20:21 +00:00
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#: web/templates/public/campsite/type.gohtml:49
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:269
2023-10-13 19:59:45 +00:00
msgctxt "action"
msgid "Book"
msgstr "Reservar"
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#: web/templates/public/campsite/type.gohtml:57
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/index.gohtml:54
2023-12-22 02:32:40 +00:00
msgctxt "title"
msgid "Calendar"
msgstr "Calendario"
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#: web/templates/public/campsite/type.gohtml:68
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:153
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:70
2023-10-01 19:14:39 +00:00
msgctxt "title"
msgid "Prices"
msgstr "Precios"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:82
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "%s: %s/night"
msgstr "%s: %s/noche"
2023-12-22 02:32:40 +00:00
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:84
msgid "%s: %s"
msgstr "%s: %s"
#: web/templates/public/campsite/type.gohtml:88
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "%s/night"
msgstr "%s/noche"
2024-01-14 01:09:17 +00:00
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:96
2023-10-01 19:14:39 +00:00
msgid "*Minimum %d nights per stay"
msgstr "*Mínimo %d noches por estancia"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:101
2024-01-15 00:45:58 +00:00
msgid "10 % VAT included."
msgstr "IVA del 10 % incluido."
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:102
2024-02-27 18:45:47 +00:00
msgid "Tourist tax: %s/night per person aged 17 or older. Maximum %d nights."
msgstr "Impuesto turístico: %s/noche por persona mayor de 16 años. Máximo %d noches."
2024-01-15 00:45:58 +00:00
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:104
2024-01-15 01:07:32 +00:00
msgid "Dogs: %s/night, tied, accompanied, and minimal barking."
msgstr "Perros: %s/noche, atados, acompañados y con mínimo de ladrido."
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:106
2024-01-15 01:07:32 +00:00
msgid "No dogs allowed."
msgstr "No se permiten perros"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:125
2023-10-13 11:40:48 +00:00
msgctxt "title"
msgid "Info"
msgstr "Información"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:129
2023-10-13 11:40:48 +00:00
msgctxt "title"
msgid "Facilities"
2024-01-14 23:28:34 +00:00
msgstr "Equipamiento"
2023-10-13 11:40:48 +00:00
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:133
2023-10-13 11:40:48 +00:00
msgctxt "title"
msgid "Description"
msgstr "Descripción"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:137
2024-01-14 23:28:34 +00:00
msgctxt "title"
msgid "Additional Information"
msgstr "Información adicional"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:140
2024-01-15 00:02:50 +00:00
msgctxt "time"
2024-01-22 19:19:19 +00:00
msgid "Check-in"
2024-01-15 00:02:50 +00:00
msgstr "Entrada"
2024-02-11 20:45:00 +00:00
#: web/templates/public/campsite/type.gohtml:144
2024-01-15 00:02:50 +00:00
msgctxt "time"
2024-01-22 19:19:19 +00:00
msgid "Check-out"
2024-01-15 00:02:50 +00:00
msgstr "Salida"
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#: web/templates/public/campsite/calendar.gohtml:18
#: web/templates/admin/season/calendar.gohtml:16
msgctxt "day"
msgid "Mon"
msgstr "lu"
#: web/templates/public/campsite/calendar.gohtml:19
#: web/templates/admin/season/calendar.gohtml:17
msgctxt "day"
msgid "Tue"
msgstr "ma"
#: web/templates/public/campsite/calendar.gohtml:20
#: web/templates/admin/season/calendar.gohtml:18
msgctxt "day"
msgid "Wed"
msgstr "mi"
#: web/templates/public/campsite/calendar.gohtml:21
#: web/templates/admin/season/calendar.gohtml:19
msgctxt "day"
msgid "Thu"
msgstr "ju"
#: web/templates/public/campsite/calendar.gohtml:22
#: web/templates/admin/season/calendar.gohtml:20
msgctxt "day"
msgid "Fri"
msgstr "vi"
#: web/templates/public/campsite/calendar.gohtml:23
#: web/templates/admin/season/calendar.gohtml:21
msgctxt "day"
msgid "Sat"
msgstr "sá"
#: web/templates/public/campsite/calendar.gohtml:24
#: web/templates/admin/season/calendar.gohtml:22
msgctxt "day"
msgid "Sun"
msgstr "do"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:30
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "¿Qué hacer desde el camping?"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:50
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Una vez en el camping, os podemos informar de qué actividades hacer"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:53
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Cycle routes"
msgstr "Rutas en bicicleta"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:54
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podéis encontrar empresas de alquiler de bicicletas."
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:58
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Routes"
msgstr "Rutas"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:59
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Rutas de todo tipo, escalada, puertos de montaña, para todos los niveles."
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:63
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Family outing"
msgstr "Excusiones familiares"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:64
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursiones para todas las edades."
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:68
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Kayak"
msgstr "Kayak"
2024-01-23 13:53:15 +00:00
#: web/templates/public/surroundings.gohtml:69
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Ter como también en la costa…."
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
#: web/templates/public/campground.gohtml:7
#: web/templates/public/campground.gohtml:16
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:55 web/templates/public/layout.gohtml:95
2023-10-06 20:14:11 +00:00
msgctxt "title"
msgid "Campground"
msgstr "El camping"
2024-01-29 13:37:27 +00:00
#: web/templates/public/campground.gohtml:20
msgctxt "title"
msgid "Legend"
msgstr "Leyenda"
#: web/templates/public/campground.gohtml:21
msgctxt "title"
msgid "Entrance"
msgstr "Entrada"
#: web/templates/public/campground.gohtml:23
msgctxt "legend"
msgid "Information"
msgstr "Información"
#: web/templates/public/campground.gohtml:24
msgctxt "legend"
msgid "Shop"
msgstr "Tienda"
#: web/templates/public/campground.gohtml:25
msgctxt "legend"
msgid "Restaurant"
msgstr "Restaurante"
#: web/templates/public/campground.gohtml:26
msgctxt "legend"
msgid "Bar"
msgstr "Bar"
#: web/templates/public/campground.gohtml:27
msgctxt "legend"
msgid "TV room"
msgstr "Sala de televisión"
#: web/templates/public/campground.gohtml:28
msgctxt "legend"
msgid "Game room"
msgstr "Sala de juegos"
#: web/templates/public/campground.gohtml:29
msgctxt "legend"
msgid "Recycling"
msgstr "Reciclaje"
#: web/templates/public/campground.gohtml:30
msgctxt "legend"
msgid "Waste"
msgstr "Basura"
#: web/templates/public/campground.gohtml:31
msgctxt "legend"
msgid "Service station"
msgstr "Estación de servicio"
#: web/templates/public/campground.gohtml:33
msgctxt "title"
msgid "Playtime"
msgstr "Recreo"
#: web/templates/public/campground.gohtml:35
msgctxt "legend"
msgid "Pool"
msgstr "Piscina"
#: web/templates/public/campground.gohtml:36
msgctxt "legend"
msgid "Playground"
msgstr "Parque infantil"
#: web/templates/public/campground.gohtml:37
msgctxt "legend"
msgid "Sports field"
msgstr "Campo de deportes"
#: web/templates/public/campground.gohtml:39
msgctxt "title"
msgid "Accomodations"
msgstr "Alojamientos"
#: web/templates/public/campground.gohtml:41
msgctxt "legend"
msgid "Wooden lodge"
msgstr "Cabaña de madera"
#: web/templates/public/campground.gohtml:42
msgctxt "legend"
msgid "Bungalow"
msgstr "Bungaló"
#: web/templates/public/campground.gohtml:43
msgctxt "legend"
msgid "Safari tent"
msgstr "Safari tent"
#: web/templates/public/campground.gohtml:45
msgctxt "title"
msgid "Main Building"
msgstr "Edificio principal"
#: web/templates/public/campground.gohtml:47
msgctxt "legend"
msgid "Restroom"
msgstr "Lavabo"
#: web/templates/public/campground.gohtml:48
msgctxt "legend"
msgid "Shower"
msgstr "Duchas"
#: web/templates/public/campground.gohtml:49
msgctxt "legend"
msgid "Baby bath"
msgstr "Baño para bebés"
#: web/templates/public/campground.gohtml:50
msgctxt "legend"
msgid "Washing machine"
msgstr "Lavadora"
#: web/templates/public/campground.gohtml:51
msgctxt "legend"
msgid "Clothesline"
msgstr "Tendedero"
#: web/templates/public/campground.gohtml:52
msgctxt "legend"
msgid "Barbecue"
msgstr "Barbacoa"
#: web/templates/public/campground.gohtml:53
msgctxt "legend"
msgid "Chemical waste disposal"
msgstr "Vaciado váter químico"
#: web/templates/public/campground.gohtml:55
msgctxt "title"
msgid "Throughout the Campground"
msgstr "En todo el camping"
#: web/templates/public/campground.gohtml:57
msgctxt "legend"
msgid "Fire extinguisher"
msgstr "Extintor"
#: web/templates/public/campground.gohtml:58
msgctxt "legend"
msgid "Faucet"
msgstr "Grifo"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:12 web/templates/public/layout.gohtml:49
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Campsite Montagut"
msgstr "Camping Montagut"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:25 web/templates/admin/layout.gohtml:21
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Skip to main content"
msgstr "Saltar al contenido principal"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:51
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Menu"
msgstr "Menú"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:59 web/templates/public/layout.gohtml:105
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:16
#: web/templates/admin/campsite/feature/index.gohtml:10
#: web/templates/admin/campsite/carousel/form.gohtml:16
#: web/templates/admin/campsite/carousel/index.gohtml:10
#: web/templates/admin/campsite/form.gohtml:15
#: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:15
#: web/templates/admin/campsite/type/feature/form.gohtml:16
#: web/templates/admin/campsite/type/feature/index.gohtml:10
#: web/templates/admin/campsite/type/carousel/form.gohtml:16
#: web/templates/admin/campsite/type/carousel/index.gohtml:10
#: web/templates/admin/campsite/type/form.gohtml:15
#: web/templates/admin/campsite/type/option/form.gohtml:16
#: web/templates/admin/campsite/type/option/index.gohtml:10
#: web/templates/admin/campsite/type/index.gohtml:10
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:95
msgctxt "title"
msgid "Campsites"
msgstr "Alojamientos"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:92
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "title"
msgid "Sections"
msgstr "Apartados"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:116
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "title"
msgid "Opening"
msgstr "Apertura"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:123
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
msgstr "<abbr title=\"Número\">Nº</abbr> <abbr title=\"Registro de Turismo de Cataluña\">RTC</abbr> %s"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:132
2024-02-26 18:13:17 +00:00
msgctxt "title"
msgid "Credits"
msgstr "Créditos"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:132
2024-02-26 18:13:17 +00:00
msgctxt "title"
msgid "Terms and Conditions"
msgstr "Aviso legal"
2024-02-29 15:59:30 +00:00
#: web/templates/public/layout.gohtml:132
2024-02-26 18:13:17 +00:00
msgctxt "title"
msgid "Reservation Conditions"
msgstr "Condiciones de reserva"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/page.gohtml:19
2024-02-24 19:03:11 +00:00
msgid "Sorry, there was a problem. You’ ll find more details highlighted below."
msgstr "Ha habido un problema. Encontraréis más información resaltada debajo."
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/page.gohtml:24
2024-02-26 15:00:29 +00:00
msgid "Payment is in test mode. You can make the booking regardless, but no money will be charged. We will send you an additional email with instructions on how to perform the payment."
msgstr "El pago está en modo de pruebas. Igualmente podéis hacer la reserva, pero no se os hará ningún cargo. Os enviaremos un correo adicional con instrucciones sobre cómo realizar el pago."
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:27
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "title"
msgid "Booking Period"
msgstr "Periodo de reserva"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:56
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "title"
msgid "Guests"
msgstr "Huéspedes"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:92
2024-02-11 21:06:00 +00:00
msgid "Note: Due to guest capacity, we have added more accomodations to the booking, but we <strong>cannot</strong> guarantee that they will be next to each other."
msgstr "Nota: Se han añadido alojamientos a la reserva debido a la capacidad de cada una, pero <strong>no</strong> se garantiza que estén de lado."
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:109
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Note: This accommodation does <strong>not</strong> allow dogs."
2024-02-11 21:06:00 +00:00
msgstr "Nota: En este alojamiento <strong>no</strong> se permiten perros."
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:121
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "input"
msgid "Area preferences (optional)"
msgstr "Preferencias de área (opcional)"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:123
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Campground map"
msgstr "Mapa del camping"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:176
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgctxt "input"
2024-02-24 19:03:11 +00:00
msgid "Town or village"
msgstr "Población"
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:188
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgid "Choose a country"
msgstr "Escoja un país"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:216
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgctxt "input"
msgid "ACSI card? (optional)"
msgstr "¿Tarjeta ACSI? (opcional)"
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:224
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgctxt "input"
2024-01-22 02:41:54 +00:00
msgid "I have read and I accept %[1]sthe reservation conditions%[2]s"
msgstr "He leído y acepto %[1]slas condiciones de reserva%[2]s"
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:261
2024-02-15 14:54:22 +00:00
msgid "By down paying the %d %% of the total, you are pre-booking your preferences. We will respond within 24 hours and this percentage will be charged if accepted."
msgstr "En tramitar el %d %% del total estáis realizando la prerreserva de vuestras preferencias. Os responderemos en un término de 24 horas y os cobraremos este porcentaje en caso que sea aceptada."
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:263
2024-02-15 14:54:22 +00:00
msgid "By paying the total you are pre-booking your preferences. We will respond within 24 hours and this amount will be charged if accepted."
msgstr "En tramitar el pago del total estáis realizando la prerreserva de vuestras preferencias. Os responderemos en un término de 24 horas y os cobraremos esta cantidad en caso que sea aceptada."
2024-02-29 15:59:30 +00:00
#: web/templates/public/booking/fields.gohtml:267
2024-02-15 14:54:22 +00:00
msgid "See <%s>our conditions</%s> for more information."
msgstr "Consultad <%s>nuestras condiciones</%s> para más información."
2024-02-14 03:54:42 +00:00
#: web/templates/admin/payment/settings.gohtml:6
#: web/templates/admin/payment/index.gohtml:14
msgctxt "title"
msgid "Payment Settings"
msgstr "Parámetros de pago"
#: web/templates/admin/payment/settings.gohtml:10
#: web/templates/admin/payment/index.gohtml:6
#: web/templates/admin/payment/details.gohtml:11
#: web/templates/admin/layout.gohtml:40
msgctxt "title"
msgid "Payments"
msgstr "Pagos"
#: web/templates/admin/payment/settings.gohtml:21
msgctxt "input"
msgid "Merchant Code"
msgstr "Código del comercio"
#: web/templates/admin/payment/settings.gohtml:30
msgctxt "input"
msgid "Terminal Number"
msgstr "Número de terminal"
#: web/templates/admin/payment/settings.gohtml:40
msgctxt "input"
msgid "Merchant Key (only if must change it)"
msgstr "Clave del comercio (sólo si se debe cambiar)"
#: web/templates/admin/payment/settings.gohtml:42
msgctxt "input"
msgid "Merchant Key"
msgstr "Clave del comercio"
#: web/templates/admin/payment/settings.gohtml:52
msgctxt "title"
msgid "Environment"
msgstr "Entorno"
#: web/templates/admin/payment/settings.gohtml:59
msgctxt "title"
msgid "Integration"
msgstr "Integración"
#: web/templates/admin/payment/settings.gohtml:66
#: web/templates/admin/location.gohtml:53 web/templates/admin/profile.gohtml:78
2024-02-27 18:45:47 +00:00
#: web/templates/admin/taxDetails.gohtml:179
2024-02-14 03:54:42 +00:00
msgctxt "action"
msgid "Save changes"
msgstr "Guardar los cambios"
#: web/templates/admin/payment/index.gohtml:20
#: web/templates/admin/user/login-attempts.gohtml:19
msgctxt "header"
msgid "Date"
msgstr "Fecha"
#: web/templates/admin/payment/index.gohtml:23
msgctxt "header"
msgid "Down payment"
msgstr "A cuenta"
#: web/templates/admin/payment/index.gohtml:24
msgctxt "header"
msgid "Total"
msgstr "Total"
#: web/templates/admin/payment/index.gohtml:40
msgid "No payments found."
msgstr "No se ha encontrado ningún pago."
#: web/templates/admin/payment/details.gohtml:7
msgctxt "title"
msgid "Payment %s"
msgstr "Pago %s"
2023-12-22 01:23:18 +00:00
#: web/templates/admin/legal/form.gohtml:8
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:29
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
2023-12-22 01:23:18 +00:00
msgid "Edit Legal Text"
msgstr "Edición del texto legal"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2023-12-22 01:23:18 +00:00
#: web/templates/admin/legal/form.gohtml:10
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:31
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
2023-12-22 01:23:18 +00:00
msgid "New Legal Text"
msgstr "Nuevo texto legal"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:15
#: web/templates/admin/legal/index.gohtml:6
#: web/templates/admin/legal/index.gohtml:15
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:70
2024-01-21 21:44:04 +00:00
msgctxt "title"
msgid "Legal Texts"
msgstr "Textos legales"
#: web/templates/admin/legal/form.gohtml:41
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
2023-12-22 01:23:18 +00:00
msgid "Slug"
msgstr "Álias"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:50
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:50
#: web/templates/admin/campsite/type/feature/form.gohtml:59
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/form.gohtml:51
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:41
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:50
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:53
2024-01-21 21:44:04 +00:00
#: web/templates/admin/profile.gohtml:29
#: web/templates/admin/surroundings/form.gohtml:41
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/form.gohtml:50
#: web/templates/admin/amenity/form.gohtml:50
2023-12-22 01:23:18 +00:00
msgctxt "input"
msgid "Name"
msgstr "Nombre"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:68
2023-12-22 01:23:18 +00:00
msgctxt "input"
msgid "Content"
msgstr "Contenido"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:88
#: web/templates/admin/carousel/form.gohtml:55
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:65
#: web/templates/admin/campsite/carousel/form.gohtml:50
#: web/templates/admin/campsite/form.gohtml:92
#: web/templates/admin/campsite/type/feature/form.gohtml:74
#: web/templates/admin/campsite/type/carousel/form.gohtml:59
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:287
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:98
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:73
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:81
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:69
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:58
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/form.gohtml:65
#: web/templates/admin/amenity/carousel/form.gohtml:50
#: web/templates/admin/amenity/form.gohtml:91
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:34
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:39
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Update"
msgstr "Actualizar"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/form.gohtml:90
#: web/templates/admin/carousel/form.gohtml:57
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:67
#: web/templates/admin/campsite/carousel/form.gohtml:52
#: web/templates/admin/campsite/form.gohtml:94
#: web/templates/admin/campsite/type/feature/form.gohtml:76
#: web/templates/admin/campsite/type/carousel/form.gohtml:61
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:289
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:100
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:75
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:83
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:71
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/form.gohtml:67
#: web/templates/admin/amenity/carousel/form.gohtml:52
#: web/templates/admin/amenity/form.gohtml:93
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Add"
msgstr "Añadir"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/index.gohtml:14
2023-12-22 01:23:18 +00:00
msgctxt "action"
msgid "Add Legal Text"
msgstr "Añadir texto legal"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/index.gohtml:20
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/index.gohtml:30
#: web/templates/admin/campsite/type/feature/index.gohtml:31
#: web/templates/admin/campsite/type/option/index.gohtml:30
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/index.gohtml:29
#: web/templates/admin/season/index.gohtml:29
#: web/templates/admin/user/index.gohtml:20
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:83
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/index.gohtml:30
#: web/templates/admin/amenity/index.gohtml:21
2023-12-22 01:23:18 +00:00
msgctxt "header"
msgid "Name"
msgstr "Nombre"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/legal/index.gohtml:32
2023-12-22 01:23:18 +00:00
msgid "No legal texts added yet."
msgstr "No se ha añadido ningún texto legal todavía."
#: web/templates/admin/carousel/form.gohtml:8
2024-01-21 21:44:04 +00:00
#: web/templates/admin/carousel/form.gohtml:28
2023-12-22 01:23:18 +00:00
msgctxt "title"
msgid "Edit Carousel Slide"
msgstr "Edición de la diapositiva del carrusel"
#: web/templates/admin/carousel/form.gohtml:10
2024-01-21 21:44:04 +00:00
#: web/templates/admin/carousel/form.gohtml:30
2023-12-22 01:23:18 +00:00
msgctxt "title"
msgid "New Carousel Slide"
msgstr "Nueva diapositiva del carrusel"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/carousel/form.gohtml:40
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/form.gohtml:35
#: web/templates/admin/campsite/type/carousel/form.gohtml:44
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/form.gohtml:35
2023-12-22 01:23:18 +00:00
msgctxt "input"
msgid "Caption"
msgstr "Leyenda"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/location.gohtml:6 web/templates/admin/location.gohtml:15
2023-12-21 20:17:04 +00:00
msgctxt "title"
msgid "Location Settings"
msgstr "Parámetros de cómo llegar"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/location.gohtml:20
2023-12-21 20:17:04 +00:00
msgctxt "input"
msgid "Directions"
msgstr "Instrucciones"
2024-01-24 10:13:39 +00:00
#: web/templates/admin/location.gohtml:33
2023-12-21 20:17:04 +00:00
msgctxt "input"
msgid "Opening Dates"
msgstr "Fechas de apertura"
2024-01-24 10:13:39 +00:00
#: web/templates/admin/location.gohtml:46
2023-12-21 20:17:04 +00:00
msgctxt "input"
msgid "Map Embed"
msgstr "Incrustación del mapa"
2023-10-13 18:30:31 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:8
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "Edit Campsite Feature"
msgstr "Edición de las características del alojamiento"
2023-10-13 18:30:31 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:10
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "New Campsite Feature"
msgstr "Nueva característica del alojamiento"
2023-10-13 18:30:31 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:17
2023-10-13 18:30:31 +00:00
#: web/templates/admin/campsite/feature/index.gohtml:6
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "Campsite Features"
msgstr "Características del alojamiento"
2023-10-13 18:30:31 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/form.gohtml:32
#: web/templates/admin/campsite/type/feature/form.gohtml:41
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:35
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/form.gohtml:32
2024-01-21 21:44:04 +00:00
msgctxt "input"
msgid "Icon"
msgstr "Icono"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/index.gohtml:15
#: web/templates/admin/campsite/type/feature/index.gohtml:16
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/index.gohtml:15
2023-10-13 18:30:31 +00:00
msgctxt "action"
msgid "Add Feature"
msgstr "Añadir características"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/index.gohtml:31
#: web/templates/admin/campsite/carousel/index.gohtml:31
2024-01-26 21:54:19 +00:00
#: web/templates/admin/campsite/type/feature/index.gohtml:32
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/carousel/index.gohtml:32
#: web/templates/admin/campsite/type/option/index.gohtml:31
#: web/templates/admin/services/index.gohtml:30
#: web/templates/admin/services/index.gohtml:75
#: web/templates/admin/user/index.gohtml:23
#: web/templates/admin/surroundings/index.gohtml:84
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/index.gohtml:31
#: web/templates/admin/amenity/carousel/index.gohtml:31
2024-01-29 02:38:11 +00:00
#: web/templates/admin/amenity/index.gohtml:25
2024-01-26 21:27:54 +00:00
#: web/templates/admin/home/index.gohtml:54
#: web/templates/admin/home/index.gohtml:99
msgctxt "header"
msgid "Actions"
msgstr "Acciones"
#: web/templates/admin/campsite/feature/index.gohtml:35
2024-01-26 21:54:19 +00:00
#: web/templates/admin/campsite/type/feature/index.gohtml:36
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/index.gohtml:35
2024-01-26 21:54:19 +00:00
msgid "Are you sure you wish to delete this feature?"
msgstr "¿Estáis seguro de querer borrar esta característica?"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/feature/index.gohtml:47
#: web/templates/admin/campsite/carousel/index.gohtml:49
2024-01-26 21:54:19 +00:00
#: web/templates/admin/campsite/type/feature/index.gohtml:48
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/carousel/index.gohtml:50
#: web/templates/admin/campsite/type/option/index.gohtml:47
#: web/templates/admin/services/index.gohtml:47
#: web/templates/admin/services/index.gohtml:91
#: web/templates/admin/user/index.gohtml:37
#: web/templates/admin/surroundings/index.gohtml:63
#: web/templates/admin/surroundings/index.gohtml:101
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/index.gohtml:47
#: web/templates/admin/amenity/carousel/index.gohtml:49
2024-01-29 02:38:11 +00:00
#: web/templates/admin/amenity/index.gohtml:45
2024-01-26 21:27:54 +00:00
#: web/templates/admin/home/index.gohtml:71
#: web/templates/admin/home/index.gohtml:116
msgctxt "action"
msgid "Delete"
msgstr "Borrar"
#: web/templates/admin/campsite/feature/index.gohtml:56
msgid "No campsite features added yet."
msgstr "No se ha añadido ninguna característica al alojamiento todavía."
2023-10-13 18:30:31 +00:00
2023-10-12 14:33:45 +00:00
#: web/templates/admin/campsite/carousel/form.gohtml:8
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "Edit Campsite Carousel Slide"
msgstr "Edición de la diapositiva del carrusel del alojamiento"
2023-10-12 14:33:45 +00:00
#: web/templates/admin/campsite/carousel/form.gohtml:10
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "New Campsite Carousel Slide"
msgstr "Nueva diapositiva del carrusel del alojamiento"
2023-10-12 14:33:45 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/form.gohtml:17
2023-10-12 14:33:45 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:6
msgctxt "title"
2024-01-26 21:27:54 +00:00
msgid "Campsite Carousel"
msgstr "Carrusel del alojamiento"
2023-10-12 14:33:45 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:16
#: web/templates/admin/campsite/type/carousel/index.gohtml:17
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:15
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/index.gohtml:16
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:84
2023-10-12 14:33:45 +00:00
msgctxt "action"
msgid "Add slide"
msgstr "Añadir diapositiva"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:29
#: web/templates/admin/campsite/type/carousel/index.gohtml:30
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:28
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:82
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/index.gohtml:29
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:52
#: web/templates/admin/home/index.gohtml:97
2023-10-12 14:33:45 +00:00
msgctxt "header"
msgid "Image"
msgstr "Imagen"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:30
#: web/templates/admin/campsite/type/carousel/index.gohtml:31
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:29
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/index.gohtml:30
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:53
#: web/templates/admin/home/index.gohtml:98
2023-10-12 14:33:45 +00:00
msgctxt "header"
msgid "Caption"
msgstr "Leyenda"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:35
#: web/templates/admin/campsite/type/carousel/index.gohtml:36
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:34
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/index.gohtml:35
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:103
2023-10-12 14:33:45 +00:00
msgid "Are you sure you wish to delete this slide?"
msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/carousel/index.gohtml:58
#: web/templates/admin/campsite/type/carousel/index.gohtml:59
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:56
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/carousel/index.gohtml:58
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:125
2023-10-12 14:33:45 +00:00
msgid "No slides added yet."
msgstr "No se ha añadido ninguna diapositiva todavía."
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/form.gohtml:8
2023-08-08 00:29:14 +00:00
msgctxt "title"
2023-08-14 18:18:26 +00:00
msgid "Edit Campsite"
msgstr "Edición del alojamientos"
2023-08-08 00:29:14 +00:00
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/form.gohtml:10
2023-08-04 17:59:58 +00:00
msgctxt "title"
2023-08-14 18:18:26 +00:00
msgid "New Campsite"
msgstr "Nuevo alojamiento"
2023-08-04 17:59:58 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:33
#: web/templates/admin/campsite/index.gohtml:27
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "campsite"
2023-08-14 09:43:58 +00:00
msgid "Active"
msgstr "Activo"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:42
2023-08-04 17:59:58 +00:00
msgctxt "input"
2023-08-14 18:18:26 +00:00
msgid "Campsite Type"
msgstr "Tipo de alojamiento"
2023-08-04 17:59:58 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:47
2023-08-14 18:18:26 +00:00
msgid "Select campsite type"
msgstr "Escoged un tipo de alojamiento"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:56
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/form.gohtml:42
2023-08-04 17:59:58 +00:00
msgctxt "input"
2023-08-14 18:18:26 +00:00
msgid "Label"
msgstr "Etiqueta"
2023-08-04 17:59:58 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:64
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/form.gohtml:63
2023-10-06 11:26:01 +00:00
msgctxt "input"
2024-01-26 21:27:54 +00:00
msgid "Info (First Column)"
msgstr "Información (primera columna)"
2023-10-06 11:26:01 +00:00
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/form.gohtml:77
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/form.gohtml:76
2023-10-06 11:26:01 +00:00
msgctxt "input"
2024-01-26 21:27:54 +00:00
msgid "Info (Second Column)"
msgstr "Información (segunda columna)"
2023-10-06 11:26:01 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/index.gohtml:14
2023-08-14 18:18:26 +00:00
msgctxt "action"
msgid "Add Campsite"
msgstr "Añadir alojamiento"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/index.gohtml:23
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/index.gohtml:20
2023-08-14 18:18:26 +00:00
msgctxt "header"
msgid "Label"
msgstr "Etiqueta"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/index.gohtml:24
2023-08-14 18:18:26 +00:00
msgctxt "header"
msgid "Type"
msgstr "Tipo"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:30
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/index.gohtml:22
2024-01-26 21:27:54 +00:00
msgctxt "header"
msgid "Features"
msgstr "Características"
#: web/templates/admin/campsite/index.gohtml:26
#: web/templates/admin/campsite/type/index.gohtml:32
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/index.gohtml:23
2024-01-26 21:27:54 +00:00
msgctxt "header"
msgid "Carousel"
msgstr "Carrusel"
#: web/templates/admin/campsite/index.gohtml:36
#: web/templates/admin/campsite/type/index.gohtml:45
2024-01-29 02:38:11 +00:00
#: web/templates/admin/amenity/index.gohtml:35
2024-01-26 21:27:54 +00:00
msgctxt "action"
msgid "Edit Features"
msgstr "Editar las características"
#: web/templates/admin/campsite/index.gohtml:39
#: web/templates/admin/campsite/type/index.gohtml:51
2024-01-29 02:38:11 +00:00
#: web/templates/admin/amenity/index.gohtml:38
2024-01-26 21:27:54 +00:00
msgctxt "action"
msgid "Edit Carousel"
msgstr "Editar el carrusel"
#: web/templates/admin/campsite/index.gohtml:47
2023-08-14 18:18:26 +00:00
msgid "No campsites added yet."
msgstr "No se ha añadido ningún alojamiento todavía."
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/feature/form.gohtml:8
#: web/templates/admin/campsite/type/feature/form.gohtml:32
msgctxt "title"
msgid "Edit Campsite Type Feature"
msgstr "Edición de las características del tipo de alojamiento"
#: web/templates/admin/campsite/type/feature/form.gohtml:10
#: web/templates/admin/campsite/type/feature/form.gohtml:34
msgctxt "title"
msgid "New Campsite Type Feature"
msgstr "Nueva característica del tipo de alojamiento"
#: web/templates/admin/campsite/type/feature/form.gohtml:17
#: web/templates/admin/campsite/type/feature/index.gohtml:11
#: web/templates/admin/campsite/type/carousel/form.gohtml:17
#: web/templates/admin/campsite/type/carousel/index.gohtml:11
#: web/templates/admin/campsite/type/form.gohtml:16
#: web/templates/admin/campsite/type/option/form.gohtml:17
#: web/templates/admin/campsite/type/option/index.gohtml:11
#: web/templates/admin/campsite/type/index.gohtml:6
#: web/templates/admin/campsite/type/index.gohtml:16
#: web/templates/admin/layout.gohtml:43
msgctxt "title"
msgid "Campsite Types"
msgstr "Tipos de alojamientos"
#: web/templates/admin/campsite/type/feature/form.gohtml:18
#: web/templates/admin/campsite/type/feature/index.gohtml:6
#: web/templates/admin/campsite/type/feature/index.gohtml:17
msgctxt "title"
msgid "Campsite Type Features"
msgstr "Características del tipo de alojamiento"
2024-01-26 21:54:19 +00:00
#: web/templates/admin/campsite/type/feature/index.gohtml:57
2024-01-26 21:27:54 +00:00
msgid "No campsite type features added yet."
msgstr "No se ha añadido ninguna característica al tipo de alojamiento todavía."
#: web/templates/admin/campsite/type/carousel/form.gohtml:8
#: web/templates/admin/campsite/type/carousel/form.gohtml:32
msgctxt "title"
msgid "Edit Campsite Type Carousel Slide"
msgstr "Edición de la diapositiva del carrusel del tipo de alojamiento"
#: web/templates/admin/campsite/type/carousel/form.gohtml:10
#: web/templates/admin/campsite/type/carousel/form.gohtml:34
msgctxt "title"
msgid "New Campsite Type Carousel Slide"
msgstr "Nueva diapositiva del carrusel del tipo de alojamiento"
#: web/templates/admin/campsite/type/carousel/form.gohtml:18
#: web/templates/admin/campsite/type/carousel/index.gohtml:6
#: web/templates/admin/campsite/type/carousel/index.gohtml:16
msgctxt "title"
msgid "Campsite Type Carousel"
msgstr "Carrusel del tipo de alojamiento"
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/type/form.gohtml:8
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/form.gohtml:30
2023-08-14 18:18:26 +00:00
msgctxt "title"
msgid "Edit Campsite Type"
2023-10-06 11:26:01 +00:00
msgstr "Edición del tipo de alojamiento"
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/type/form.gohtml:10
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/form.gohtml:32
2023-08-14 18:18:26 +00:00
msgctxt "title"
msgid "New Campsite Type"
msgstr "Nuevo tipo de alojamiento"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/form.gohtml:42
#: web/templates/admin/campsite/type/index.gohtml:33
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "campsite type"
msgid "Active"
msgstr "Activo"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/form.gohtml:67
2023-09-29 18:17:39 +00:00
msgctxt "input"
2024-01-22 19:19:19 +00:00
msgid "Check-in"
msgstr "Entrada"
#: web/templates/admin/campsite/type/form.gohtml:80
msgctxt "input"
msgid "Check-out"
msgstr "Salida"
2024-01-31 22:06:45 +00:00
#: web/templates/admin/campsite/type/form.gohtml:93
msgctxt "input"
msgid "Minimum number of nights"
msgstr "Número mínimos de noches"
#: web/templates/admin/campsite/type/form.gohtml:101
msgctxt "input"
msgid "Maximum number of nights"
msgstr "Número máximo de noches"
#: web/templates/admin/campsite/type/form.gohtml:110
2024-01-22 19:19:19 +00:00
msgctxt "input"
2023-09-29 18:17:39 +00:00
msgid "Maximum number of campers"
msgstr "Número máximo de personas"
2024-01-31 22:06:45 +00:00
#: web/templates/admin/campsite/type/form.gohtml:120
2024-01-29 02:38:11 +00:00
msgctxt "input"
msgid "Allow overflowing guests to neighbouring campsites"
msgstr "Permitir reservar alojamientos vecinos si se supera el máximo de personas"
2024-01-31 22:06:45 +00:00
#: web/templates/admin/campsite/type/form.gohtml:129
2024-01-29 02:38:11 +00:00
msgctxt "input"
msgid "Ask for zone preferences when booking"
msgstr "Pedir la preferencia de zona durante la reserva"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:139
2023-09-29 18:17:39 +00:00
msgctxt "input"
msgid "Dogs allowed"
msgstr "Se permiten perros"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:144
msgctxt "input"
msgid "Dogs price"
msgstr "Precio de los perros"
#: web/templates/admin/campsite/type/form.gohtml:157
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Season"
msgstr "Temporada"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:158
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Price per night"
msgstr "Precio por noche"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:159
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Price per adult (> 16)"
msgstr "Precio por adulto (> 16)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:160
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Price per teenager (11– 16)"
msgstr "Precio por adolescente (11– 16)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:161
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Price per child (2– 10)"
msgstr "Precio por niño (2– 10)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:171
2024-01-26 21:27:54 +00:00
msgctxt "input"
msgid "Price per night"
msgstr "Precio por noche"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:182
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "input"
msgid "Price per adult (> 16)"
msgstr "Precio por adulto (> 16)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:193
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "input"
msgid "Price per teenager (11– 16)"
msgstr "Precio por adolescente (11– 16)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:204
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "input"
msgid "Price per child (2– 10)"
msgstr "Precio por niño (2– 10)"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:220
2023-10-12 16:47:08 +00:00
msgctxt "input"
msgid "Spiel"
msgstr "Introducción"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:233
2023-10-13 11:40:48 +00:00
msgctxt "input"
msgid "Info"
msgstr "Información"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:246
2023-10-13 11:40:48 +00:00
msgctxt "input"
msgid "Facilities"
msgstr "Equipamento"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:259
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:66
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:54
2023-08-14 18:18:26 +00:00
msgctxt "input"
msgid "Description"
msgstr "Descripción"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: web/templates/admin/campsite/type/form.gohtml:272
2024-01-14 23:28:34 +00:00
msgctxt "input"
msgid "Additional Information"
msgstr "Información adicional"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:8
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:32
2024-01-26 21:27:54 +00:00
msgctxt "title"
msgid "Edit Campsite Type Option"
msgstr "Edición de la opción del tipo de alojamiento"
#: web/templates/admin/campsite/type/option/form.gohtml:10
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:34
2024-01-26 21:27:54 +00:00
msgctxt "title"
msgid "New Campsite Type Option"
msgstr "Nueva opción del tipo de alojamiento"
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:54
2024-01-26 21:27:54 +00:00
msgctxt "input"
msgid "Minimum"
msgstr "Mínimo"
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:62
2024-01-26 21:27:54 +00:00
msgctxt "input"
msgid "Maximum"
msgstr "Màximo"
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:75
2024-02-11 20:45:00 +00:00
msgctxt "campsite type"
msgid "Per night"
msgstr "Por noche"
2024-02-11 21:06:00 +00:00
#: web/templates/admin/campsite/type/option/form.gohtml:84
2024-02-11 20:45:00 +00:00
msgctxt "input"
msgid "Price"
msgstr "Precio"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/option/index.gohtml:16
msgctxt "action"
msgid "Add Option"
msgstr "Añadir opción"
2024-01-26 21:54:19 +00:00
#: web/templates/admin/campsite/type/option/index.gohtml:35
msgid "Are you sure you wish to delete this option?"
msgstr "¿Estáis seguro de querer borrar esta opción?"
2024-01-26 21:27:54 +00:00
#: web/templates/admin/campsite/type/option/index.gohtml:56
msgid "No campsite type options added yet."
msgstr "No se ha añadido ninguna opció al tipo de alojamiento todavía."
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/index.gohtml:15
2023-08-04 17:59:58 +00:00
msgctxt "action"
msgid "Add Type"
msgstr "Añadir tipo"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/index.gohtml:31
2023-10-13 18:30:31 +00:00
msgctxt "header"
2023-10-06 11:26:01 +00:00
msgid "Options"
msgstr "Opciones"
2023-08-04 17:59:58 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/index.gohtml:48
2023-10-06 11:26:01 +00:00
msgctxt "action"
msgid "Edit Options"
msgstr "Editar opciones"
2023-09-12 18:20:23 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/campsite/type/index.gohtml:60
2023-08-04 17:59:58 +00:00
msgid "No campsite types added yet."
msgstr "No se ha añadido ningún tipo de alojamiento todavía."
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
#: web/templates/admin/season/form.gohtml:8
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:29
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "title"
msgid "Edit Season"
msgstr "Edición de temporada"
#: web/templates/admin/season/form.gohtml:10
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:31
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "title"
msgid "New Season"
msgstr "Nueva temporada"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:15
2024-01-22 02:41:54 +00:00
#: web/templates/admin/season/index.gohtml:6
#: web/templates/admin/season/index.gohtml:15
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:52
2024-01-21 21:44:04 +00:00
msgctxt "title"
2024-01-22 02:41:54 +00:00
msgid "Seasons"
2024-01-21 21:44:04 +00:00
msgstr "Temporadas"
#: web/templates/admin/season/form.gohtml:41
#: web/templates/admin/season/index.gohtml:30
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "season"
msgid "Active"
msgstr "Activa"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/form.gohtml:63
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "input"
msgid "Color"
msgstr "Color"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/index.gohtml:14
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "action"
msgid "Add Season"
msgstr "Añadir temporada"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/index.gohtml:28
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "header"
msgid "Color"
msgstr "Color"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/season/index.gohtml:51
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgid "No seasons added yet."
msgstr "No se ha añadido ninguna temporada todavía."
2023-09-29 18:17:39 +00:00
#: web/templates/admin/season/calendar.gohtml:49
#: web/templates/admin/media/picker.gohtml:61
msgctxt "action"
msgid "Cancel"
msgstr "Cancelar"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/dashboard.gohtml:6
2024-01-27 21:51:41 +00:00
#: web/templates/admin/dashboard.gohtml:13 web/templates/admin/layout.gohtml:89
Get user from database based on cookie and serve login if not logged in
To get the user from the database i have to set the cookie first, that
was already done in database.MustAcquire, but i thought they were too
far apart, even thought they are so related. So, the cookie, and thus
the role, is set when getting the user, that is actually the first thing
to do once the connection is acquired. However, that way the database
package has no knowledge of cookies, and the code that sets the cookie
and retrieves the user are next to each other.
I applied the same logic to the changes of locale.Match: it has not
business knowing that the accept language string comes from a request;
it only needs the actual string. Also, the TODO comment about getting
the user’s locale made no sense, now, because app already knows that
locale, so there is no need to pass the user to the locale package.
Getting the locale is done after retrieving the user from the database,
for the same reason the connection is Acquired as far up as possible:
almost every request will need this value, together with the user and
the database connection.
I am a bit affraid that i will end up with functions that always expect
these three values. Maybe i can put the locale inside user, as it is
the user’s locale, after all, no matter if it came from the database or
the user agent, but connection and user must be separate, i think.
We’ll see.
2023-07-25 23:50:39 +00:00
msgctxt "title"
msgid "Dashboard"
msgstr "Panel"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/login.gohtml:6 web/templates/admin/login.gohtml:18
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "title"
msgid "Login"
msgstr "Entrada"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/login.gohtml:36 web/templates/admin/profile.gohtml:49
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "input"
msgid "Password"
msgstr "Contraseña"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/login.gohtml:45
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "action"
msgid "Login"
msgstr "Entrar"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/form.gohtml:8
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:26
2023-09-25 18:10:33 +00:00
msgctxt "title"
msgid "Edit Service"
msgstr "Edición de servicio"
#: web/templates/admin/services/form.gohtml:10
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:28
2023-09-25 18:10:33 +00:00
msgctxt "title"
msgid "New Service"
msgstr "Nuevo servicio"
2024-01-24 10:13:39 +00:00
#: web/templates/admin/services/form.gohtml:15
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#: web/templates/admin/services/index.gohtml:6
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:61
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Services Page"
msgstr "Página de servicios"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:14
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:83
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
msgid "Carousel"
msgstr "Carrusel"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:60
2023-09-26 14:51:35 +00:00
msgctxt "action"
msgid "Add service"
msgstr "Añadir servicio"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:73
2024-01-13 00:15:24 +00:00
msgctxt "header"
msgid "Order"
msgstr "Orden"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:74
2023-09-25 18:10:33 +00:00
msgctxt "header"
msgid "Service"
msgstr "Servicio"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:79
2023-09-26 15:00:22 +00:00
msgid "Are you sure you wish to delete this service?"
msgstr "¿Estáis seguro de querer borrar este servicio?"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/services/index.gohtml:100
2023-09-25 18:10:33 +00:00
msgid "No services added yet."
msgstr "No se ha añadido ningún servicio todavía."
2024-01-21 21:44:04 +00:00
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:15
2024-01-16 00:25:25 +00:00
#: web/templates/admin/layout.gohtml:33
2023-07-26 18:46:09 +00:00
msgctxt "title"
msgid "Profile"
msgstr "Perfil"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/profile.gohtml:20
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgctxt "inut"
msgid "Profile Image"
msgstr "Imagen del perfil"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/profile.gohtml:46
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgctxt "legend"
msgid "Change password"
msgstr "Cambio de contraseña"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/profile.gohtml:58
2023-07-26 18:46:09 +00:00
msgctxt "input"
msgid "Password Confirmation"
msgstr "Confirmación de la contraseña"
2024-01-17 19:28:42 +00:00
#: web/templates/admin/user/login-attempts.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/login-attempts.gohtml:15
2024-01-17 19:28:42 +00:00
msgctxt "title"
msgid "Login Attempts"
msgstr "Intentos de entrada"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/login-attempts.gohtml:10
#: web/templates/admin/user/index.gohtml:6
#: web/templates/admin/user/index.gohtml:16
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:73
2024-01-21 21:44:04 +00:00
msgctxt "title"
msgid "Users"
msgstr "Usuarios"
#: web/templates/admin/user/login-attempts.gohtml:20
#: web/templates/admin/user/index.gohtml:21
2024-01-17 19:28:42 +00:00
msgctxt "header"
msgid "Email"
msgstr "Correo-e"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/login-attempts.gohtml:21
2024-01-17 19:28:42 +00:00
msgctxt "header"
msgid "IP Address"
msgstr "Dirección IP"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/login-attempts.gohtml:22
2024-01-17 19:28:42 +00:00
msgctxt "header"
msgid "Success"
msgstr "Éxito"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/index.gohtml:14
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
msgctxt "action"
msgid "Add User"
msgstr "Añadir usuario"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/index.gohtml:15
2024-01-17 19:28:42 +00:00
msgctxt "action"
msgid "Logs"
msgstr "Registros"
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/index.gohtml:22
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
msgctxt "header"
msgid "Role"
msgstr "Rol"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/user/index.gohtml:27
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
msgid "Are you sure you wish to delete this user?"
msgstr "¿Estáis seguro de querer borrar este usuario?"
2023-08-15 20:35:21 +00:00
#: web/templates/admin/taxDetails.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:15
2023-08-15 20:35:21 +00:00
msgctxt "title"
msgid "Tax Details"
msgstr "Configuración fiscal"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:20
#: web/templates/admin/taxDetails.gohtml:61
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Business Name"
msgstr "Nombre de empresa"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:29
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "VAT Number"
msgstr "NIF"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:37
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Trade Name"
msgstr "Nombre comercial"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:85
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Province"
msgstr "Provincia"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:111
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Currency"
msgstr "Moneda"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:121
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Default Language"
msgstr "Idioma por defecto"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:130
2024-01-14 01:09:17 +00:00
msgctxt "title"
msgid "Tourism"
msgstr "Turismo"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:133
2024-01-14 01:09:17 +00:00
msgctxt "input"
msgid "RTC number"
msgstr "Número RTC"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:141
2024-01-14 01:09:17 +00:00
msgctxt "input"
msgid "Tourist Tax"
msgstr "Impuesto turístico"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/taxDetails.gohtml:150
2024-02-27 18:45:47 +00:00
msgctxt "input"
msgid "Tourist Tax Days"
msgstr "Días del impuesto turístico"
#: web/templates/admin/taxDetails.gohtml:159
2024-01-14 01:09:17 +00:00
msgctxt "title"
msgid "Invoicing"
msgstr "Facturación"
2024-02-27 18:45:47 +00:00
#: web/templates/admin/taxDetails.gohtml:162
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Invoice Number Format"
msgstr "Formato de número de factura"
2024-02-27 18:45:47 +00:00
#: web/templates/admin/taxDetails.gohtml:170
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Nota legal"
2024-01-16 00:25:25 +00:00
#: web/templates/admin/surroundings/form.gohtml:8
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:29
2024-01-16 00:25:25 +00:00
msgctxt "title"
msgid "Edit Highlight"
msgstr "Edición del punto de interés"
#: web/templates/admin/surroundings/form.gohtml:10
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/form.gohtml:31
2024-01-16 00:25:25 +00:00
msgctxt "title"
msgid "New Highlight"
msgstr "Nuevo punto de interés"
#: web/templates/admin/surroundings/index.gohtml:6
msgctxt "title"
msgid "Surroundings Page"
msgstr "Página del entorno"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/surroundings/index.gohtml:14
2024-01-16 00:25:25 +00:00
msgctxt "title"
2024-01-23 13:53:15 +00:00
msgid "Ad"
msgstr "Anuncio"
#: web/templates/admin/surroundings/index.gohtml:21
msgctxt "input"
msgid "Title"
msgstr "Título"
#: web/templates/admin/surroundings/index.gohtml:37
msgctxt "input"
msgid "Link Text"
msgstr "Texto del enlace"
#: web/templates/admin/surroundings/index.gohtml:50
msgctxt "input"
msgid "Link URL"
msgstr "Dirección del enlace"
#: web/templates/admin/surroundings/index.gohtml:59
msgid "Are you sure you wish to delete the ad?"
msgstr "¿Estáis seguro de querer borrar este enlace?"
#: web/templates/admin/surroundings/index.gohtml:68
msgctxt "title"
2024-01-16 00:25:25 +00:00
msgid "Highlights"
msgstr "Puntos de interés"
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:69
2024-01-16 00:25:25 +00:00
msgctxt "action"
msgid "Add highlight"
msgstr "Añadir punto de interés"
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:88
2024-01-16 00:25:25 +00:00
msgid "Are you sure you wish to delete this highlight?"
msgstr "¿Estáis seguro de querer borrar este punto de interés?"
2024-01-23 13:53:15 +00:00
#: web/templates/admin/surroundings/index.gohtml:110
2024-01-16 00:25:25 +00:00
msgid "No highlights added yet."
msgstr "No se ha añadido ningún punto de interés todavía."
2024-01-27 21:51:41 +00:00
#: web/templates/admin/amenity/feature/form.gohtml:8
msgctxt "title"
msgid "Edit Amenity Feature"
msgstr "Edición de las características de la instalación"
#: web/templates/admin/amenity/feature/form.gohtml:10
msgctxt "title"
msgid "New Amenity Feature"
msgstr "Nueva característica de la instalación"
#: web/templates/admin/amenity/feature/form.gohtml:16
#: web/templates/admin/amenity/feature/index.gohtml:10
#: web/templates/admin/amenity/carousel/form.gohtml:16
#: web/templates/admin/amenity/carousel/index.gohtml:10
#: web/templates/admin/amenity/form.gohtml:15
#: web/templates/admin/amenity/index.gohtml:6
#: web/templates/admin/layout.gohtml:49
msgctxt "title"
msgid "Amenities"
msgstr "Instalaciones"
#: web/templates/admin/amenity/feature/form.gohtml:17
#: web/templates/admin/amenity/feature/index.gohtml:6
msgctxt "title"
msgid "Amenity Features"
msgstr "Características de la instalación"
#: web/templates/admin/amenity/feature/index.gohtml:56
msgid "No amenity features added yet."
msgstr "No se ha añadido ninguna característica a la instalación todavía."
#: web/templates/admin/amenity/carousel/form.gohtml:8
msgctxt "title"
msgid "Edit Amenity Carousel Slide"
msgstr "Edición de la diapositiva del carrusel de la instalación"
#: web/templates/admin/amenity/carousel/form.gohtml:10
msgctxt "title"
msgid "New Amenity Carousel Slide"
msgstr "Nueva diapositiva del carrusel de la instalación"
#: web/templates/admin/amenity/carousel/form.gohtml:17
#: web/templates/admin/amenity/carousel/index.gohtml:6
msgctxt "title"
msgid "Amenity Carousel"
msgstr "Carrusel de la instalación"
#: web/templates/admin/amenity/form.gohtml:8
msgctxt "title"
msgid "Edit Amenity"
msgstr "Edición de la instalación"
#: web/templates/admin/amenity/form.gohtml:10
msgctxt "title"
msgid "New Amenity"
msgstr "Nueva instalación"
#: web/templates/admin/amenity/form.gohtml:33
#: web/templates/admin/amenity/index.gohtml:24
msgctxt "amenity"
msgid "Active"
msgstr "Activa"
#: web/templates/admin/amenity/index.gohtml:14
msgctxt "action"
msgid "Add Amenity"
msgstr "Añadir instalación"
2024-01-29 02:38:11 +00:00
#: web/templates/admin/amenity/index.gohtml:29
msgid "Are you sure you wish to delete this amenity?"
msgstr "¿Estáis seguro de querer borrar esta instalación?"
#: web/templates/admin/amenity/index.gohtml:53
2024-01-27 21:51:41 +00:00
msgid "No amenities added yet."
msgstr "No se ha añadido ninguna instalación todavía."
2024-01-16 00:25:25 +00:00
#: web/templates/admin/layout.gohtml:29
2023-07-26 18:46:09 +00:00
msgctxt "title"
msgid "User Menu"
msgstr "Menú de usuario"
2024-01-16 00:25:25 +00:00
#: web/templates/admin/layout.gohtml:37
2023-08-15 20:35:21 +00:00
msgctxt "title"
msgid "Company Settings"
msgstr "Parámetros de la empresa"
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:55
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:10
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/index.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/index.gohtml:14
#: web/templates/admin/media/upload.gohtml:10
2023-09-25 18:10:33 +00:00
msgctxt "title"
msgid "Media"
msgstr "Medios"
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:58 web/templates/admin/home/index.gohtml:6
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
msgctxt "title"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Home Page"
msgstr "Página de inicio"
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:78
2023-09-25 18:10:33 +00:00
msgctxt "action"
msgid "Logout"
msgstr "Salir"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:92
2024-01-18 20:05:30 +00:00
#: web/templates/admin/booking/index.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:16
2024-01-18 20:05:30 +00:00
msgctxt "title"
msgid "Bookings"
msgstr "Reservas"
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:101
2024-01-21 21:44:04 +00:00
msgid "Breadcrumb"
msgstr "Migas de pan"
2024-01-27 21:51:41 +00:00
#: web/templates/admin/layout.gohtml:113
2024-01-21 19:50:04 +00:00
msgid "Camper Version: %s"
msgstr "Camper versión: %s"
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:15
msgctxt "title"
msgid "Slogan"
msgstr "Eslogan"
#: web/templates/admin/home/index.gohtml:21
msgctxt "input"
msgid "Slogan"
msgstr "Eslogan"
#: web/templates/admin/home/index.gohtml:38
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
msgctxt "title"
msgid "Cover"
msgstr "Portada"
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:39
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
msgctxt "action"
msgid "Add cover image"
msgstr "Añadir imagen de portada"
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:58
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
msgid "Are you sure you wish to delete this cover image?"
msgstr "¿Estáis seguro de querer borrar esta imagen de portada?"
2024-01-23 10:52:39 +00:00
#: web/templates/admin/home/index.gohtml:80
Add home’s cover carousel
This is a separate carousel from the one displayed at the bottom with
location info; it is, i suppose, a carousel for the hero image.
For the database, it works exactly as the home carousel, but on the
front had to use AlpineJS instead of Slick because it needs to show a
text popping up from the bottom when the slide is show, something i do
not know how to do in Slick.
It now makes no sense to have the carousel inside the “nature” section,
because the heading is no longer in there, and moved it out into a new
“hero” div.
Since i now have two carousels in home, i had to add additional
attributes to carousel.AdminHandler to know which URL to point to when
POSTing, PUTting, or redirecting.
2024-01-16 20:05:52 +00:00
msgid "No images added to the cover yet."
msgstr "No se ha añadido ninguna imagen de portada todavía."
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
#: web/templates/admin/media/picker.gohtml:8
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Media Picker"
msgstr "Selector de medio"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
#: web/templates/admin/media/picker.gohtml:19
msgctxt "title"
msgid "Upload New Media"
msgstr "Subida de un nuevo medio"
#: web/templates/admin/media/picker.gohtml:22
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/upload.gohtml:21
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "input"
msgid "File"
msgstr "Archivo"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: web/templates/admin/media/picker.gohtml:26
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:26
#: web/templates/admin/media/upload.gohtml:25
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgid "Maximum upload file size: %s"
msgstr "Tamaño máximo del archivos a subir: %s"
#: web/templates/admin/media/picker.gohtml:31
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/upload.gohtml:30
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "action"
msgid "Upload"
msgstr "Subir"
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: web/templates/admin/media/picker.gohtml:47
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "title"
msgid "Choose Existing Media"
msgstr "Elección de un medio existente"
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: web/templates/admin/media/picker.gohtml:58
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/index.gohtml:23
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "No media uploaded yet."
msgstr "No se ha subido ningún medio todavía."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: web/templates/admin/media/form.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:16
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Edit Media"
msgstr "Edición de medio"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:22
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Updated file"
msgstr "Archivo actualizado"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/form.gohtml:31
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Filename"
msgstr "Nombre de archivo"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/index.gohtml:15
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Upload media"
msgstr "Subir medio"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
#: web/templates/admin/media/upload.gohtml:6
2024-01-21 21:44:04 +00:00
#: web/templates/admin/media/upload.gohtml:16
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgctxt "title"
msgid "Upload Media"
msgstr "Subida de medio"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:14
2024-01-18 20:05:30 +00:00
msgctxt "action"
msgid "Add Booking"
msgstr "Añadir reserva"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:15
2024-01-18 20:05:30 +00:00
msgctxt "action"
msgid "Export Bookings"
msgstr "Exportar eservas"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:22
2024-01-18 20:05:30 +00:00
msgctxt "header"
msgid "Arrival Date"
msgstr "Fecha de llegada"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:23
2024-01-18 20:05:30 +00:00
msgctxt "header"
msgid "Departure Date"
msgstr "Fecha de salida"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:24
2024-01-18 20:05:30 +00:00
msgctxt "header"
msgid "Holder Name"
msgstr "Nombre del titular"
2024-01-21 21:44:04 +00:00
#: web/templates/admin/booking/index.gohtml:41
2024-01-18 20:05:30 +00:00
msgid "No booking found."
msgstr "No se ha encontrado ninguna reserva."
2024-02-14 03:54:42 +00:00
#: pkg/payment/settings.go:37
msgctxt "redsys environment"
msgid "Test"
msgstr "Pruebas"
#: pkg/payment/settings.go:41
msgctxt "redsys environment"
msgid "Live"
msgstr "Real"
#: pkg/payment/settings.go:50
msgctxt "redsys integration"
msgid "InSite"
msgstr "InSite"
#: pkg/payment/settings.go:54
msgctxt "redsys integration"
msgid "Redirect"
msgstr "Redirección"
#: pkg/payment/settings.go:98
msgid "Merchant code can not be empty."
msgstr "No podéis dejar el código del comercio en blanco."
#: pkg/payment/settings.go:99
msgid "Merchant code must be exactly nine digits long."
msgstr "El código del comercio tiene que ser de nueve dígitos."
#: pkg/payment/settings.go:100
msgid "Merchant code must be a number."
msgstr "El código del comercio tiene que ser un número."
#: pkg/payment/settings.go:104
msgid "Terminal number can not be empty."
msgstr "No podéis dejar el número de terminal en blanco."
#: pkg/payment/settings.go:105
msgid "Terminal number must be a number between 1 and 999."
msgstr "El número de terminal tiene que ser entre 1 y 999."
#: pkg/payment/settings.go:113
msgid "Selected environment is not valid."
msgstr "El entorno escogido no es válido."
#: pkg/payment/settings.go:114
msgid "Selected integration is not valid."
msgstr "La integración escogida no es válida."
#: pkg/payment/settings.go:117
msgid "The merchant key is not valid."
msgstr "Esta clave del comercio no es válida."
2024-02-29 15:59:30 +00:00
#: pkg/payment/public.go:111
2024-02-12 17:06:17 +00:00
msgctxt "order product name"
msgid "Campsite Booking"
msgstr "Reserva de camping"
2024-02-29 15:59:30 +00:00
#: pkg/payment/public.go:372
2024-02-13 04:20:35 +00:00
msgctxt "subject"
msgid "Booking payment successfully received"
msgstr "Se ha recibido correctamente el pago de la reserva"
2024-02-11 20:45:00 +00:00
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:365
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:577
2024-02-29 15:59:30 +00:00
#: pkg/campsite/feature.go:269 pkg/season/admin.go:411
2024-01-26 21:27:54 +00:00
#: pkg/services/admin.go:316 pkg/surroundings/admin.go:340
2024-01-29 02:38:11 +00:00
#: pkg/amenity/feature.go:269 pkg/amenity/admin.go:283
2023-12-22 01:23:18 +00:00
msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco."
2024-02-11 20:45:00 +00:00
#: pkg/legal/admin.go:259 pkg/campsite/types/option.go:366
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:578
2024-01-27 21:51:41 +00:00
#: pkg/campsite/feature.go:270 pkg/amenity/feature.go:270
2023-12-22 01:23:18 +00:00
msgid "Name must have at least one letter."
msgstr "El nombre tiene que tener como mínimo una letra."
2024-01-23 10:52:39 +00:00
#: pkg/carousel/admin.go:276 pkg/campsite/types/carousel.go:225
2024-01-27 21:51:41 +00:00
#: pkg/campsite/carousel.go:227 pkg/amenity/carousel.go:227
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
2023-09-22 00:17:56 +00:00
msgid "Slide image"
msgstr "Imagen de la diapositiva"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2024-01-23 10:52:39 +00:00
#: pkg/carousel/admin.go:277 pkg/campsite/types/carousel.go:226
2024-01-27 21:51:41 +00:00
#: pkg/campsite/carousel.go:228 pkg/amenity/carousel.go:228
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
2023-09-22 00:17:56 +00:00
msgid "Set slide image"
msgstr "Establecer la imagen de la diapositiva"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2024-01-23 10:52:39 +00:00
#: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299
2024-01-26 21:27:54 +00:00
#: pkg/campsite/carousel.go:302 pkg/surroundings/admin.go:335
2024-01-27 21:51:41 +00:00
#: pkg/amenity/carousel.go:302
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Slide image can not be empty."
msgstr "No podéis dejar la imagen de la diapositiva en blanco."
2024-01-23 10:52:39 +00:00
#: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300
2024-01-26 21:27:54 +00:00
#: pkg/campsite/carousel.go:303 pkg/surroundings/admin.go:336
2024-01-27 21:51:41 +00:00
#: pkg/amenity/carousel.go:303
2023-09-22 00:17:56 +00:00
msgid "Slide image must be an image media type."
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2024-02-27 18:45:47 +00:00
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:224
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:536
2023-07-24 15:17:15 +00:00
msgid "Email can not be empty."
msgstr "No podéis dejar el correo-e en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:225
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:537
2023-07-24 15:17:15 +00:00
msgid "This email is not valid. It should be like name@domain.com."
msgstr "Este correo-e no es válido. Tiene que ser parecido a nombre@dominio.com."
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
#: pkg/app/login.go:59
2023-07-24 15:17:15 +00:00
msgid "Password can not be empty."
msgstr "No podéis dejar la contraseña en blanco."
2023-07-26 18:46:09 +00:00
#: pkg/app/login.go:86
2023-07-24 15:17:15 +00:00
msgid "Invalid user or password."
msgstr "Usuario o contraseña incorrectos."
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
2023-08-08 00:29:14 +00:00
#: pkg/app/user.go:197
2023-07-26 18:46:09 +00:00
msgctxt "language option"
msgid "Automatic"
msgstr "Automático"
2023-08-08 00:29:14 +00:00
#: pkg/app/user.go:250
2023-07-26 18:46:09 +00:00
msgid "Confirmation does not match password."
msgstr "La confirmación no se corresponde con la contraseña."
2024-02-27 18:45:47 +00:00
#: pkg/app/user.go:251 pkg/company/admin.go:250
2023-07-26 18:46:09 +00:00
msgid "Selected language is not valid."
msgstr "El idioma escogido no es válido."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/app/user.go:253
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgid "File must be a valid PNG or JPEG image."
msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
2024-02-14 03:54:42 +00:00
#: pkg/app/admin.go:73
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgid "Access forbidden"
msgstr "Acceso prohibido"
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:369
2023-10-06 11:26:01 +00:00
msgid "Minimum can not be empty."
msgstr "No podéis dejar el mínimo en blanco."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:370
2023-10-06 11:26:01 +00:00
msgid "Minimum must be an integer number."
msgstr "El valor de mínimo tiene que ser un número entero."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:372
2023-10-06 11:26:01 +00:00
msgid "Minimum must be zero or greater."
msgstr "El valor de mínimo tiene que ser como mínimo cero."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:375
2023-10-06 11:26:01 +00:00
msgid "Maximum can not be empty."
msgstr "No podéis dejar el máxmimo en blanco."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:376
2023-10-06 11:26:01 +00:00
msgid "Maximum must be an integer number."
msgstr "El valor del máximo tiene que ser un número entero."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:378
2023-10-06 11:26:01 +00:00
msgid "Maximum must be equal or greater than minimum."
msgstr "El valor del máximo tiene que ser igual o mayor al del mínimo."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:382
msgid "Price can not be empty."
msgstr "No podéis dejar el precio en blanco."
2023-10-06 11:26:01 +00:00
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:383
msgid "Price must be a decimal number."
msgstr "El precio tiene que ser un número decimal."
2023-10-06 11:26:01 +00:00
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/option.go:384
msgid "Price must be zero or greater."
msgstr "El precio tiene que ser como mínimo cero."
2023-10-06 11:26:01 +00:00
2024-01-26 21:54:19 +00:00
#: pkg/campsite/types/feature.go:271 pkg/campsite/feature.go:268
2024-01-27 21:51:41 +00:00
#: pkg/services/admin.go:315 pkg/amenity/feature.go:268
2023-10-13 18:30:31 +00:00
msgid "Selected icon is not valid."
msgstr "El icono escogido no es válido."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:328
2023-09-22 00:17:56 +00:00
msgctxt "input"
msgid "Cover image"
msgstr "Imagen de portada"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:329
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Establecer la portada del tipo de alojamiento"
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:580
2024-01-22 19:19:19 +00:00
msgid "Check-in can not be empty."
msgstr "No podéis dejar la entrada en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:581
2024-01-22 19:19:19 +00:00
msgid "Check-out can not be empty."
msgstr "No podéis dejar la salida en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:582
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
msgid "Cover image can not be empty."
msgstr "No podéis dejar la imagen de portada en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:583
2023-09-22 00:17:56 +00:00
msgid "Cover image must be an image media type."
msgstr "La imagen de portada tiene que ser un medio de tipo imagen."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:587
2023-09-29 18:17:39 +00:00
msgid "Maximum number of campers can not be empty."
msgstr "No podéis dejar el número máximo de personas en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:588
2023-09-29 18:17:39 +00:00
msgid "Maximum number of campers must be an integer number."
msgstr "El número máximo de personas tiene que ser entero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:589
2023-09-29 18:17:39 +00:00
msgid "Maximum number of campers must be one or greater."
msgstr "El número máximo de personas no puede ser cero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:592
2023-10-01 19:14:39 +00:00
msgid "Minimum number of nights can not be empty."
msgstr "No podéis dejar el número mínimo de noches en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:593
2023-10-01 19:14:39 +00:00
msgid "Minimum number of nights must be an integer."
msgstr "El número mínimo de noches tiene que ser entero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:594
2023-10-01 19:14:39 +00:00
msgid "Minimum number of nights must be one or greater."
msgstr "El número mínimo de noches no puede ser cero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:597
2024-01-31 22:06:45 +00:00
msgid "Maximum number of nights can not be empty."
msgstr "No podéis dejar el número máximo de noches en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:598
2024-01-31 22:06:45 +00:00
msgid "Maximum number of nights must be an integer."
msgstr "El número máximo de noches tiene que ser entero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:599
2024-01-31 22:06:45 +00:00
msgid "Maximum number of nights must be equal or greater than the minimum."
msgstr "El valor del número máximo de noches tiene que ser igual o mayor al del mínimo."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:603
msgid "Dogs price can not be empty when dogs are allowed."
msgstr "El precio de los perros no puede ser vacío cuando son permitidos."
#: pkg/campsite/types/admin.go:604
msgid "Dogs price must be a decimal number."
msgstr "El precio de los perros tiene que ser un número decimal."
#: pkg/campsite/types/admin.go:605
msgid "Dogs price must be zero or greater."
msgstr "El precio de los perros tiene que ser como mínimo cero."
2024-02-11 20:45:00 +00:00
#: pkg/campsite/types/admin.go:610
msgid "Price per night can not be empty."
msgstr "No podéis dejar el precio por noche en blanco."
#: pkg/campsite/types/admin.go:611
msgid "Price per night must be a decimal number."
msgstr "El precio por noche tiene que ser un número decimal."
#: pkg/campsite/types/admin.go:612
msgid "Price per night must be zero or greater."
msgstr "El precio por noche tiene que ser como mínimo cero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:615
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per adult can not be empty."
msgstr "No podéis dejar el precio por adulto en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:616
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per adult must be a decimal number."
msgstr "El precio por adulto tiene que ser un número decimal."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:617
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per adult must be zero or greater."
msgstr "El precio por adulto tiene que ser como mínimo cero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:620
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per teenager can not be empty."
msgstr "No podéis dejar el precio por adolescente en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:621
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per teenager must be a decimal number."
msgstr "El precio por adolescente tiene que ser un número decimal."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:622
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per teenager must be zero or greater."
msgstr "El precio por adolescente tiene que ser como mínimo cero."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:625
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per child can not be empty."
msgstr "No podéis dejar el precio por niño en blanco."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:626
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per child must be a decimal number."
msgstr "El precio por niño tiene que ser un número decimal."
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#: pkg/campsite/types/admin.go:627
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Price per child must be zero or greater."
msgstr "El precio por niño tiene que ser como mínimo cero."
2024-02-27 18:45:47 +00:00
#: pkg/campsite/types/public.go:248
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Adults"
msgstr "Adultos"
2024-02-27 18:45:47 +00:00
#: pkg/campsite/types/public.go:255
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Teenagers (aged 11 to 16)"
msgstr "Adolescentes (de 11 a 16 años)"
2024-02-27 18:45:47 +00:00
#: pkg/campsite/types/public.go:262
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "header"
msgid "Children (aged 2 to 10)"
msgstr "Niños (de 2 a 10 años)"
2024-02-24 19:03:11 +00:00
#: pkg/campsite/admin.go:275 pkg/booking/public.go:172
#: pkg/booking/public.go:227
2023-08-14 18:18:26 +00:00
msgid "Selected campsite type is not valid."
msgstr "El tipo de alojamiento escogido no es válido."
2024-01-29 02:38:11 +00:00
#: pkg/campsite/admin.go:276 pkg/amenity/admin.go:282
2023-08-14 18:18:26 +00:00
msgid "Label can not be empty."
msgstr "No podéis dejar la etiqueta en blanco."
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:183
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "January"
msgstr "enero"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:184
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "February"
msgstr "febrero"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:185
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "March"
msgstr "marzo"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:186
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "April"
msgstr "abril"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:187
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "May"
msgstr "mayo"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:188
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "June"
msgstr "junio"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:189
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "July"
msgstr "julio"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:190
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "August"
msgstr "agosto"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:191
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "September"
msgstr "septiembre"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:192
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "October"
msgstr "octubre"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:193
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "November"
msgstr "noviembre"
2024-01-16 00:25:25 +00:00
#: pkg/season/admin.go:194
2023-09-27 00:23:09 +00:00
msgctxt "month"
msgid "December"
msgstr "diciembre"
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:412
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgid "Color can not be empty."
msgstr "No podéis dejar el color en blanco."
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:413
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgid "This color is not valid. It must be like #123abc."
msgstr "Este color no es válido. Tiene que ser parecido a #123abc."
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:513
2023-09-29 18:17:39 +00:00
msgctxt "action"
msgid "Unset"
msgstr "Desasignar"
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:544
2023-09-29 18:17:39 +00:00
msgid "Start date can not be empty."
msgstr "No podéis dejar la fecha de inicio en blanco."
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:545
2023-09-29 18:17:39 +00:00
msgid "Start date must be a valid date."
msgstr "La fecha de inicio tiene que ser una fecha válida."
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:547
2023-09-29 18:17:39 +00:00
msgid "End date can not be empty."
msgstr "No podéis dejar la fecha final en blanco."
2024-02-29 15:59:30 +00:00
#: pkg/season/admin.go:548
2023-09-29 18:17:39 +00:00
msgid "End date must be a valid date."
msgstr "La fecha final tiene que ser una fecha válida."
Add admin page to list the users
There is no way, for now, to add, edit or remove users, because
currently we only need to list users.
I can not give admins access to the user table, for security
permissions, so i had to create a new view. I could name it also ‘user’
in ‘camper’ scheme, but then i was afraid i would have problems with
unit tests and their search_path, so instead i called it
‘company_user_profile’, which is like ‘user_profile’ but for all users
in ‘company_user’.
I created a new Go package for it, rather than add the admin handler in
‘auth’, because ‘template’ depends on ‘auth’, and rendering from ‘auth’
would cause a dependency loop.
I needed to have the roles in gettext to translate them, but there is
no obvious place where to put the call to PgettextNoop. For now, there
are in ‘NewAdminHandler’ because it is called once in the application’s
lifetime and they actually do not matter much.
2024-01-17 18:42:47 +00:00
#: pkg/user/admin.go:18
msgctxt "role"
msgid "guest"
msgstr "invitado"
#: pkg/user/admin.go:19
msgctxt "role"
msgid "employee"
msgstr "trabajador"
#: pkg/user/admin.go:20
msgctxt "role"
msgid "admin"
msgstr "administrador"
2024-01-23 13:53:15 +00:00
#: pkg/surroundings/admin.go:286
2024-01-16 00:25:25 +00:00
msgctxt "input"
msgid "Highlight image"
msgstr "Imagen del punto de interés"
2024-01-23 13:53:15 +00:00
#: pkg/surroundings/admin.go:287
2024-01-16 00:25:25 +00:00
msgctxt "action"
msgid "Set highlight image"
msgstr "Establecer la imagen del punto de interés"
2024-01-23 13:53:15 +00:00
#: pkg/surroundings/admin.go:407
msgctxt "input"
msgid "Ad image"
msgstr "Imagen del anuncio"
#: pkg/surroundings/admin.go:408
msgctxt "action"
msgid "Set ad image"
msgstr "Establecer la imagen del anuncio"
#: pkg/surroundings/admin.go:459
msgid "Ad image can not be empty."
msgstr "No podéis dejar la imagen del anuncio en blanco."
#: pkg/surroundings/admin.go:460
msgid "Ad image must be an image media type."
msgstr "La imagen del anuncio tiene que ser un medio de tipo imagen."
#: pkg/surroundings/admin.go:464
msgid "The title can not be empty."
msgstr "No podéis dejar el título en blanco."
#: pkg/surroundings/admin.go:465
msgid "The link text can not be empty."
msgstr "No podéis dejar el texto del enlace en blanco."
#: pkg/surroundings/admin.go:466
msgid "The ad URL can not be empty"
msgstr "No podéis dejar la dirección del enlace en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/surroundings/admin.go:467 pkg/company/admin.go:228
2024-01-23 13:53:15 +00:00
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:207 pkg/booking/public.go:521
2023-08-15 20:35:21 +00:00
msgid "Selected country is not valid."
msgstr "El país escogido no es válido."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:211
2023-08-15 20:35:21 +00:00
msgid "Business name can not be empty."
msgstr "No podéis dejar el nombre de empresa en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:212
2023-08-15 20:35:21 +00:00
msgid "Business name must have at least two letters."
msgstr "El nombre de la empresa tiene que tener como mínimo dos letras."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:214
2023-08-15 20:35:21 +00:00
msgid "VAT number can not be empty."
msgstr "No podéis dejar el NIF en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:215
2023-08-15 20:35:21 +00:00
msgid "This VAT number is not valid."
msgstr "Este NIF no es válido."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:219 pkg/booking/public.go:539
2023-08-15 20:35:21 +00:00
msgid "Phone can not be empty."
msgstr "No podéis dejar el teléfono en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:220 pkg/booking/public.go:540
2023-08-15 20:35:21 +00:00
msgid "This phone number is not valid."
msgstr "Este teléfono no es válido."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:230 pkg/booking/public.go:529
2023-08-15 20:35:21 +00:00
msgid "Address can not be empty."
msgstr "No podéis dejar la dirección en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:231
2023-08-15 20:35:21 +00:00
msgid "City can not be empty."
msgstr "No podéis dejar la población en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:232
2023-08-15 20:35:21 +00:00
msgid "Province can not be empty."
msgstr "No podéis dejar la provincia en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:233 pkg/booking/public.go:531
2024-02-24 19:03:11 +00:00
msgid "Postcode can not be empty."
2023-08-15 20:35:21 +00:00
msgstr "No podéis dejar el código postal en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:234 pkg/booking/public.go:532
2024-02-24 19:03:11 +00:00
msgid "This postcode is not valid."
2023-08-15 20:35:21 +00:00
msgstr "Este código postal no es válido."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:238
2023-10-14 19:59:36 +00:00
msgid "RTC number can not be empty."
msgstr "No podéis dejar el número RTC en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:239
2024-01-14 01:09:17 +00:00
msgid "Tourist tax can not be empty."
msgstr "No podéis dejar el impuesto turístico en blanco."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:240
2024-01-14 01:09:17 +00:00
msgid "Tourist tax must be a decimal number."
msgstr "El impuesto turístico tiene que ser un número decimal."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:241
2024-01-14 01:09:17 +00:00
msgid "Tourist tax must be zero or greater."
msgstr "El impuesto turístico tiene que ser como mínimo cero."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:244
msgid "Tourist tax days can not be empty."
msgstr "No podéis dejar el números de días del impuesto turístico en blanco."
#: pkg/company/admin.go:245
msgid "Tourist tax days must be an integer number."
msgstr "El números de días de impuesto turístico tiene que ser un número entero."
#: pkg/company/admin.go:246
msgid "Tourist tax days must be one or greater."
msgstr "El número de días del impuesto turístico tiene que ser como mínimo uno."
#: pkg/company/admin.go:249
2023-08-15 20:35:21 +00:00
msgid "Selected currency is not valid."
msgstr "La moneda escogida no es válida."
2024-02-27 18:45:47 +00:00
#: pkg/company/admin.go:251
2023-08-15 20:35:21 +00:00
msgid "Invoice number format can not be empty."
msgstr "No podéis dejar el formato de número de factura en blanco."
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
#: pkg/auth/user.go:40
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
msgid "Cross-site request forgery detected."
msgstr "Se ha detectado un intento de falsificación de petición en sitios cruzados."
2023-08-14 09:43:58 +00:00
2024-01-16 00:25:25 +00:00
#: pkg/media/admin.go:312
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Uploaded file can not be empty."
msgstr "No podéis dejar el archivo del medio en blanco."
2024-01-16 00:25:25 +00:00
#: pkg/media/admin.go:371
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Filename can not be empty."
msgstr "No podéis dejar el nombre del archivo en blanco."
2024-02-15 14:54:22 +00:00
#: pkg/booking/cart.go:153
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "cart"
msgid "Night"
msgstr "Noche"
2024-02-15 14:54:22 +00:00
#: pkg/booking/cart.go:154
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "cart"
msgid "Adult"
msgstr "Adulto"
2024-02-15 14:54:22 +00:00
#: pkg/booking/cart.go:155
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "cart"
msgid "Teenager"
msgstr "Adolescente"
2024-02-15 14:54:22 +00:00
#: pkg/booking/cart.go:156
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgctxt "cart"
msgid "Child"
msgstr "Niño"
2024-02-15 14:54:22 +00:00
#: pkg/booking/cart.go:157
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
msgctxt "cart"
msgid "Dog"
msgstr "Perro"
2024-02-14 03:54:42 +00:00
#: pkg/booking/admin.go:126
2024-01-18 20:05:30 +00:00
msgctxt "filename"
msgid "bookings.ods"
msgstr "reservas.ods"
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:276 pkg/booking/public.go:305
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Arrival date must be a valid date."
msgstr "La fecha de llegada tiene que ser una fecha válida."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:290 pkg/booking/public.go:312
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Departure date must be a valid date."
msgstr "La fecha de partida tiene que ser una fecha válida."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:304
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgid "Arrival date can not be empty"
msgstr "No podéis dejar la fecha de llegada en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:306
Add campsite_type_pet_cost relation to hold price of dogs in campsites
It is a separate relation, instead of having a field in campsite_type,
because not all campsite types allow dogs. I could have added a new
field to campsite_type, but then its values it would be meaningless for
campsites that do not allow dogs, and a nullable field is not a valid
solution because NULL means “unknown”, but we **do** know the price —
none.
A separate relation encodes the same information without ambiguities nor
null values, and, in fact, removed the dogs_allowed field from
campsite_type to prevent erroneous status, such as a campsite type that
allows dogs without having a cost — even if the cost is zero, it has to
be added to the new relation.
2024-02-10 05:18:30 +00:00
#, c-format
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Arrival date must be %s or after."
msgstr "La fecha de llegada tiene que ser igual o posterior a %s."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:307
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#, c-format
msgid "Arrival date must be %s or before."
msgstr "La fecha de llegada tiene que ser anterior o igual a %s."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:311
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgid "Departure date can not be empty"
msgstr "No podéis dejar la fecha de partida en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:313
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#, c-format
msgid "Departure date must be %s or after."
msgstr "La fecha de partida tiene que igual o posterior a %s."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:314
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#, c-format
msgid "Departure date must be %s or before."
msgstr "La fecha de partida tiene que ser anterior o igual a %s."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:356
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#, c-format
msgid "There can be at most %d guests in this accommodation."
msgstr "Solo puede haber como máximo %d invitados en este alojamiento."
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:376
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of adults can not be empty"
msgstr "No podéis dejar el número de adultos blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:377
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of adults must be an integer."
msgstr "El número de adultos tiene que ser entero."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:378
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "There must be at least one adult."
msgstr "Tiene que haber como mínimo un adulto."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:381
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of teenagers can not be empty"
msgstr "No podéis dejar el número de adolescentes en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:382
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of teenagers must be an integer."
msgstr "El número de adolescentes tiene que ser entero."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:383
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of teenagers can not be negative."
msgstr "El número de adolescentes no puede ser negativo."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:386
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of children can not be empty"
msgstr "No podéis dejar el número de niños en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:387
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of children must be an integer."
msgstr "El número de niños tiene que ser entero."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:388
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of children can not be negative."
msgstr "El número de niños no puede ser negativo."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:391
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of dogs can not be empty"
msgstr "No podéis dejar el número de perros en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:392
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of dogs must be an integer."
msgstr "El número de perros tiene que ser entero."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:393
Compute and show the “cart” for the booking form
I have to ask number and age ranges of hosts of guests for all campsite
types, not only those that have price options for adults, children, etc.
because i must compute the tourist tax for adults. These numbers will
be used to generate de rows for guests when actually creating the
booking, which is not done already.
To satisfy the campsite types that do have a price per guest, not only
per night, i had to add the prices for each range in the
campsite_type_cost relation. If a campsite type does not have price
per person, then that should be zero; the website then does not display
the price.
The minimal price for any campsite type is one adult for one night,
thus to compute the price i need at least the campsite type, the dates,
and the number of adults, that has a minimum of one. I changed the
order of the form to ask for these values first, so i can compute the
initial price as soon as possible. To help further, i show the
<fieldset>s progressively when visitors select options.
2024-02-04 05:37:25 +00:00
msgid "Number of dogs can not be negative."
msgstr "El número de perros no puede ser negativo."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:464
Implement Redsys request signature in PostgreSQL
Every company need to have its own merchant code and encryption key,
thus it is not possible to use environment variables to keep that data,
and i have to store it in the database.
I do not want to give SELECT permission on the encryption key to guest,
because i am going to fuck it up sooner or later, and everyone would be
able to read that secret; i know it would. Therefore, i need a security
definer function that takes the data to encrypt, use the key to encrypt
it, and returns the result; nobody else should have access to that key,
not even admins!
By the way, i found out that every merchant receives the same key, thus
it is not a problem to keep it in the repository.
Since i need that SQL function to encrypt the data, i thought that i may
go the whole nine yards and sign the request in PostgreSQL too, after
all the data to sign comes from there, and it has JSON functions to
create and base64-code an object.
Fortunately, pg_crypto has all the functions that i need, but i can no
longer keep that extension inside the auth schema, because it is used
from others, and the public schema, like every other extensions, seems
more appropriate.
Instead of having the list of currency and language codes that Redsys
uses as constants in the code, i moved that as field to the currency
and language relations, so i can simply pass the lang_tag to the
function and it can transform that tag to the correct code; the currency
is from the company’s relation, since it is the only currency used in
the whole application (for now).
As a consequence, i had to grant execute to currency and the parse_price
functions to guest, too.
To generate the test data used in the unit tests, i used a third-party
PHP implementation[0], but i only got from that the resulting base64-coded
JSON object and signature, using the same that as in the unit test, and
did not use any code from there.
PostgreSQL formats the JSON as text differently than most
implementations i have seen: it adds spaces between the key name and
the colons, and space between the value and the separating comma. The
first implementation used replace() to format the JSON as exactly as
the PHP implementation, so that the result matches, and then tried to do
generate the form by hand using the output from PostgreSQL without the
replace(), to verify that Redsys would still accept my input. Finally,
i adjusted the unit test to whatever pg_prove said it was getting from
the function.
I still have the form’s action hard-codded to the test environment, but
the idea is that administrators should be able to switch from test to
live themselves. That means that i need that info in the redsys
relation as well. I think this is one of the few use cases for SQL’s
types, because it is unlikely to change anytime soon, and i do not need
the actual labels.
Unfortunately, i could not use enumerations for the request’s
transaction type because i can not attach an arbitrary number to the
enum’s values. Having a relation is overkill, because i would need
a constant in Go to refer to its primary key anyway, thus i kept the
same constant i had before for that. Language and currency constant
went out, as this is in the corresponding relations.
In setup_redsys i must have a separate update if the encrypt_key is null
because PostgreSQL checks constraints before key conflict, and i do
not want to give a default value to the key if the row is not there yet.
The problem is that i want to use null to mean “keep the same password”,
because it is what i intend to do with the user-facing form: leave the
input empty to keep the same password.
As now Go needs to pass composite types back and forth with PostgreSQL,
i need to register these types, and i have to do it every time because
the only moment i have access to the non-pooled connection is in the
AfterConnect function, but at that point i have no idea whether the
user is going to request a payment. I do not know how much the
performance degrades because of this.
[0]: https://github.com/ssheduardo/sermepa/blob/master/src/Sermepa/Tpv/Tpv.php
2023-10-26 23:52:04 +00:00
#, c-format
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
msgid "%s can not be empty"
msgstr "No podéis dejar %s en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:465
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#, c-format
msgid "%s must be an integer."
msgstr "%s tiene que ser un número entero."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:466
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#, c-format
msgid "%s must be %d or greater."
msgstr "%s tiene que ser como mínimo %d."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:467
Add the first draft of the booking and payment forms
The form is based on the one in the current website, but in a single
page instead of split into many pages; possibly each <fieldset> should
be in a separate page/view. The idea is for Oriol to check the design
and decide how it would be presented to the user, so i needed something
to show him first.
I hardcoded the **test** data for the customer’s Redsys account. Is
this bad? I hope not, but i am not really, really sure.
The data sent to Redsys is just a placeholder because there are booking
details that i do not know, like what i have to do with the “teenagers”
field or the area preferences, thus i can not yet have a booking
relation. Nevertheless, had to generate a random order number up to
12-chars in length or Redsys would refuse the payment, claiming that
the order is duplicated.
The Redsys package is based on the PHP code provided by Redsys
themselves, plus some hints at the implementations from various Go
packages that did not know why they were so complicated.
Had to grant select on table country to guest in order to show the
select with the country options.
I have changed the “Postal code” input in taxDetails for “Postcode”
because this is the spell that it is used in the current web, i did not
see a reason to change it—it is an accepted form—, and i did not want to
have inconsistencies between forms.
2023-10-19 19:37:34 +00:00
#, c-format
msgid "%s must be at most %d."
msgstr "%s tiene que ser como máximo %d"
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:525
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Full name can not be empty."
msgstr "No podéis dejar el nombre y los apellidos en blanco."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:526
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "Full name must have at least one letter."
msgstr "El nombre y los apellidos tienen que tener como mínimo una letra."
2024-02-24 19:03:11 +00:00
#: pkg/booking/public.go:530
msgid "Town or village can not be empty."
msgstr "No podéis dejar la población en blanco."
#: pkg/booking/public.go:545
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
msgid "It is mandatory to agree to the reservation conditions."
msgstr "Es obligatorio aceptar las condiciones de reserva."
2024-02-24 19:03:11 +00:00
#~ msgid "Postal code can not be empty."
#~ msgstr "No podéis dejar el código postal en blanco."
#~ msgid "This postal code is not valid."
#~ msgstr "Este código postal no es válido."
#~ msgctxt "input"
#~ msgid "Address (optional)"
#~ msgstr "Dirección (opcional)"
#~ msgctxt "input"
#~ msgid "Postcode (optional)"
#~ msgstr "Código postal (opcional)"
2024-02-12 17:06:17 +00:00
#~ msgctxt "action"
#~ msgid "Pay"
#~ msgstr "Pagar"
Handle the booking cart entirely with HTMx
Besides the dynamic final cart, that was already handled by HTMx, i had
to check the maximum number of guests, whether the accommodation allows
“overflow”, whether dogs are allowed, and that the booking dates were
within the campground’s opening and closing dates.
I could do all of this with AlpineJS, but then i would have to add the
same validation to the backend, prior to accept the payment. Would not
make more sense to have them in a single place, namely the backend? With
HTMx i can do that.
However, i now have to create the form “piecemeal”, because i may not
have the whole information when the visitor arrives to the booking page,
and i still had the same problem as in commit d2858302efa—parsing the
whole form as is would leave guests and options field empty, rather than
at their minimum values.
One of the fieldsets in that booking form are the arrival and departure
dates, that are the sames we use in the campsite type’s page to
“preselect” these values. Since now are in a separate struct, i can
reuse the same type and validation logic for both pages, making my
JavaScript code useless, but requiring HTMx. I think this is a good
tradeoff, in fact.
2024-02-10 02:49:44 +00:00
#~ msgctxt "input"
#~ msgid "Check-in Date"
#~ msgstr "Fecha de entrada"
#~ msgctxt "input"
#~ msgid "Check-out Date"
#~ msgstr "Fecha de salida"
#~ msgid "The departure date must be after the arrival date."
#~ msgstr "La fecha de partida tiene que ser posterior a la de llegada."
2024-01-16 00:25:25 +00:00
#~ msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda d’ en Jordà, cycle tours for all ages…."
#~ msgstr "El Camping Montagut es ideal como punto de salida de excursiones tranquilas, escalada, bañarse en el río y piletones, volcanes, la Fageda d’ en Jordà, salidas en bicicleta para todos los niveles…."
#~ msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
#~ msgstr "Llegar hasta la Costa Brava y disfrutar de las playas, la gastronomía o ir en kayak…."
#~ msgid "You will also find museums in Olot, Figures, Girona."
#~ msgstr "También encontraréis museos en Olot, Figueres, Girona."
#~ msgid "As well as music festivals, dance, theater…."
#~ msgstr "Como festivales de música, danza, teatro…."
2024-01-13 00:15:24 +00:00
#~ msgctxt "header"
#~ msgid "Translations"
#~ msgstr "Traducciones"
#~ msgctxt "title"
#~ msgid "Translate Season to %s"
#~ msgstr "Traducción de la temporada a %s"
#~ msgid "Source:"
#~ msgstr "Origen:"
#~ msgctxt "input"
#~ msgid "Translation:"
#~ msgstr "Traducción"
#~ msgctxt "action"
#~ msgid "Translate"
#~ msgstr "Traducir"
#~ msgctxt "title"
#~ msgid "Translate Service to %s"
#~ msgstr "Traducción del servicio a %s"
2024-01-10 20:52:49 +00:00
#~ msgctxt "title"
2024-01-12 18:33:44 +00:00
#~ msgid "Translate Carousel Slide to %s"
#~ msgstr "Traducción de la diapositiva de carrusel a %s"
#~ msgctxt "title"
2024-01-10 20:52:49 +00:00
#~ msgid "Translate Campsite Type Feature to %s"
#~ msgstr "Traducción de la característica del tipo de alojamiento a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Carousel Slide to %s"
#~ msgstr "Traducción de la diapositiva de carrusel del tipo de alojamiento a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Option to %s"
#~ msgstr "Traducción de la opción del tipo de alojamiento a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type to %s"
#~ msgstr "Traducción de tipo de alojamiento a %s"
2023-12-22 02:32:40 +00:00
#~ msgid "Starting from %s €/night"
#~ msgstr "A partir de %s €/noche"
#~ msgctxt "season"
#~ msgid "Closed"
#~ msgstr "Cerrado"
2023-12-12 22:16:04 +00:00
#~ msgctxt "title"
#~ msgid "Party Details"
#~ msgstr "Datos de los visitantes"
#~ msgid "Number of adults must be one or greater."
#~ msgstr "El número de adultos no puede ser cero."
#~ msgid "Number of teenagers must be zero or greater."
#~ msgstr "El número de adolescentes tiene que ser como mínimo cero."
#~ msgid "Number of children must be zero or greater."
#~ msgstr "El número de niños tiene que ser como mínimo cero."
#~ msgid "Number of dogs must be zero or greater."
#~ msgstr "El número de perros tiene que ser como mínimo cero."
2023-10-13 11:40:48 +00:00
#~ msgctxt "input"
#~ msgid "Pricing"
#~ msgstr "Precios"
#~ msgctxt "input"
#~ msgid "Features"
#~ msgstr "Características"
2023-10-06 16:58:24 +00:00
#~ msgid "Singular Lodges"
#~ msgstr "Alojamientos singulares"
2023-10-06 11:26:01 +00:00
#~ msgctxt "campsite type"
#~ msgid "Translations"
#~ msgstr "Traducciones"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#~ msgid "Surroundings"
#~ msgstr "Entorno"
2023-08-14 09:43:58 +00:00
#~ msgctxt "title"
#~ msgid "Pages"
#~ msgstr "Páginas"
#~ msgctxt "action"
#~ msgid "Add Page"
#~ msgstr "Añadir página"
#~ msgctxt "header"
#~ msgid "Title"
#~ msgstr "Título"