camper/po/es.po

2542 lines
72 KiB
Plaintext
Raw Normal View History

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"
"POT-Creation-Date: 2024-02-02 21:57+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
"PO-Revision-Date: 2023-07-22 23:46+0200\n"
"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"
#: 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"
#: web/templates/public/payment/success.gohtml:6
#: web/templates/public/payment/success.gohtml:11
msgctxt "title"
msgid "Payment Successful"
msgstr "Pago con éxito"
#: web/templates/public/payment/request.gohtml:6
#: web/templates/public/payment/request.gohtml:11
msgctxt "title"
msgid "Payment"
msgstr "Pago"
#: web/templates/public/payment/request.gohtml:23
msgctxt "action"
msgid "Pay"
msgstr "Pagar"
#: web/templates/public/payment/failure.gohtml:6
#: web/templates/public/payment/failure.gohtml:11
msgctxt "title"
msgid "Payment Failed"
msgstr "Pago fallido"
#: web/templates/public/services.gohtml:7
#: web/templates/public/services.gohtml:16
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
#: web/templates/admin/services/index.gohtml:59
msgctxt "title"
msgid "Services"
msgstr "Servicios"
#: web/templates/public/services.gohtml:19
msgid "The campsite offers many different services."
msgstr "El camping dispone de varios servicios."
#: web/templates/public/amenity.gohtml:39
#: web/templates/public/campsite/type.gohtml:114
#: web/templates/public/campsite/page.gohtml:39
msgctxt "title"
msgid "Features"
msgstr "Características"
#: web/templates/public/location.gohtml:7
#: web/templates/public/location.gohtml:13
#: web/templates/public/layout.gohtml:69 web/templates/public/layout.gohtml:97
#: web/templates/admin/layout.gohtml:64
msgctxt "title"
msgid "Location"
msgstr "Cómo llegar"
#: web/templates/public/home.gohtml:7 web/templates/public/layout.gohtml:53
#: web/templates/public/layout.gohtml:93
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"
#: web/templates/public/home.gohtml:25
msgctxt "link"
msgid "Booking"
msgstr "Reservar"
#: web/templates/public/home.gohtml:28
msgid "The pleasure of camping in the middle of nature…"
msgstr "El placer de acampar en plena naturaleza…"
#: web/templates/public/home.gohtml:40
msgid "Our services"
msgstr "Nuestros servicios"
#: web/templates/public/home.gohtml:44
#: web/templates/public/surroundings.gohtml:7
#: web/templates/public/surroundings.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
#: web/templates/admin/surroundings/form.gohtml:15
#: web/templates/admin/layout.gohtml:67
msgctxt "title"
msgid "Surroundings"
msgstr "El entorno"
#: web/templates/public/home.gohtml:47
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>."
#: web/templates/public/home.gohtml:48
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den 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."
msgstr "Cerca tenéis los <strong>piletones de Sadernes</strong>, <strong>volcanes</strong>, <strong>La Fageda den 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."
#: web/templates/public/home.gohtml:49
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menos de una hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> y a dos de <strong>Barcelona</strong>."
#: web/templates/public/home.gohtml:50
msgid "Discover the surroundings"
msgstr "Descubre el entorno"
#: web/templates/public/campsite/type.gohtml:41
msgctxt "input"
msgid "Check-in Date"
msgstr "Fecha de entrada"
#: web/templates/public/campsite/type.gohtml:47
msgctxt "input"
msgid "Check-out Date"
msgstr "Fecha de salida"
#: web/templates/public/campsite/type.gohtml:56
#: web/templates/public/booking.gohtml:171
msgctxt "action"
msgid "Book"
msgstr "Reservar"
#: web/templates/public/campsite/type.gohtml:64
#: web/templates/admin/season/index.gohtml:54
2023-12-22 02:32:40 +00:00
msgctxt "title"
msgid "Calendar"
msgstr "Calendario"
#: web/templates/public/campsite/type.gohtml:75
#: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/campsite/type/option/form.gohtml:70
2023-10-01 19:14:39 +00:00
msgctxt "title"
msgid "Prices"
msgstr "Precios"
#: web/templates/public/campsite/type.gohtml:87
#: web/templates/public/campsite/type.gohtml:93
2023-12-22 02:32:40 +00:00
msgid "%s: %s €/night"
msgstr "%s: %s €/noche"
#: web/templates/public/campsite/type.gohtml:89
msgid "%s €/night"
msgstr "%s €/noche"
#: 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"
#: web/templates/public/campsite/type.gohtml:101
msgid "10 % VAT included."
msgstr "IVA del 10 % incluido."
#: web/templates/public/campsite/type.gohtml:102
msgid "Tourist tax: %s/night per person aged 17 or older."
msgstr "Impuesto turístico: %s/noche por persona mayor de de 16 años."
#: web/templates/public/campsite/type.gohtml:104
msgid "Dogs: %s/night, tied, accompanied, and minimal barking."
msgstr "Perros: %s/noche, atados, acompañados y con mínimo de ladrido."
#: web/templates/public/campsite/type.gohtml:106
msgid "No dogs allowed."
msgstr "No se permiten perros"
#: web/templates/public/campsite/type.gohtml:125
msgctxt "title"
msgid "Info"
msgstr "Información"
#: web/templates/public/campsite/type.gohtml:129
msgctxt "title"
msgid "Facilities"
msgstr "Equipamiento"
#: web/templates/public/campsite/type.gohtml:133
msgctxt "title"
msgid "Description"
msgstr "Descripción"
#: web/templates/public/campsite/type.gohtml:137
msgctxt "title"
msgid "Additional Information"
msgstr "Información adicional"
#: web/templates/public/campsite/type.gohtml:140
msgctxt "time"
msgid "Check-in"
msgstr "Entrada"
#: web/templates/public/campsite/type.gohtml:144
msgctxt "time"
msgid "Check-out"
msgstr "Salida"
#: 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"
#: web/templates/public/surroundings.gohtml:30
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "¿Qué hacer desde el camping?"
#: web/templates/public/surroundings.gohtml:50
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"
#: web/templates/public/surroundings.gohtml:53
msgid "Cycle routes"
msgstr "Rutas en bicicleta"
#: web/templates/public/surroundings.gohtml:54
msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podéis encontrar empresas de alquiler de bicicletas."
#: web/templates/public/surroundings.gohtml:58
msgid "Routes"
msgstr "Rutas"
#: web/templates/public/surroundings.gohtml:59
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."
#: web/templates/public/surroundings.gohtml:63
msgid "Family outing"
msgstr "Excusiones familiares"
#: web/templates/public/surroundings.gohtml:64
msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursiones para todas las edades."
#: web/templates/public/surroundings.gohtml:68
msgid "Kayak"
msgstr "Kayak"
#: web/templates/public/surroundings.gohtml:69
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…."
#: web/templates/public/campground.gohtml:7
#: web/templates/public/campground.gohtml:16
#: web/templates/public/layout.gohtml:54 web/templates/public/layout.gohtml:94
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"
#: web/templates/public/booking.gohtml:7 web/templates/public/booking.gohtml:12
#: web/templates/public/layout.gohtml:70
msgctxt "title"
msgid "Booking"
msgstr "Reserva"
#: web/templates/public/booking.gohtml:16
msgctxt "title"
msgid "Customer Details"
msgstr "Detalles del cliente"
#: web/templates/public/booking.gohtml:19
msgctxt "input"
msgid "Full name"
msgstr "Nombre y apellidos"
#: web/templates/public/booking.gohtml:28
msgctxt "input"
msgid "Address (optional)"
msgstr "Dirección (opcional)"
#: web/templates/public/booking.gohtml:37
msgctxt "input"
msgid "Postcode (optional)"
msgstr "Código postal (opcional)"
#: web/templates/public/booking.gohtml:46
msgctxt "input"
msgid "Town or village (optional)"
msgstr "Población (opcional)"
#: web/templates/public/booking.gohtml:55
#: web/templates/admin/taxDetails.gohtml:101
msgctxt "input"
msgid "Country"
msgstr "País"
#: web/templates/public/booking.gohtml:58
msgid "Choose a country"
msgstr "Escoja un país"
#: web/templates/public/booking.gohtml:66 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/public/booking.gohtml:75
#: web/templates/admin/taxDetails.gohtml:45
msgctxt "input"
msgid "Phone"
msgstr "Teléfono"
#: web/templates/public/booking.gohtml:84
msgctxt "title"
msgid "Accommodation"
msgstr "Alojamientos"
#: web/templates/public/booking.gohtml:101
msgctxt "input"
msgid "Area preferences (optional)"
msgstr "Preferencias de área (opcional)"
#: web/templates/public/booking.gohtml:108
msgid "Campground map"
msgstr "Mapa del camping"
#: web/templates/public/booking.gohtml:126
msgctxt "title"
msgid "Booking Period"
msgstr "Periodo de reserva"
#: web/templates/public/booking.gohtml:129
msgctxt "input"
msgid "Arrival date"
msgstr "Fecha de llegada"
#: web/templates/public/booking.gohtml:139
msgctxt "input"
msgid "Departure date"
msgstr "Fecha de salida"
#: web/templates/public/booking.gohtml:151
msgctxt "input"
msgid "ACSI card? (optional)"
msgstr "¿Tarjeta ACSI? (opcional)"
#: web/templates/public/booking.gohtml:158
msgctxt "input"
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"
#: web/templates/public/layout.gohtml:12 web/templates/public/layout.gohtml:48
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 "Campsite Montagut"
msgstr "Camping Montagut"
#: web/templates/public/layout.gohtml:24 web/templates/admin/layout.gohtml:21
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 "Skip to main content"
msgstr "Saltar al contenido principal"
#: web/templates/public/layout.gohtml:50
msgid "Menu"
msgstr "Menú"
#: web/templates/public/layout.gohtml:58 web/templates/public/layout.gohtml:104
#: 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"
#: web/templates/public/layout.gohtml:91
msgctxt "title"
msgid "Sections"
msgstr "Apartados"
#: web/templates/public/layout.gohtml:115
msgctxt "title"
msgid "Opening"
msgstr "Apertura"
#: web/templates/public/layout.gohtml:122
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"
2023-12-22 01:23:18 +00:00
#: web/templates/admin/legal/form.gohtml:8
#: web/templates/admin/legal/form.gohtml:29
msgctxt "title"
2023-12-22 01:23:18 +00:00
msgid "Edit Legal Text"
msgstr "Edición del texto legal"
2023-12-22 01:23:18 +00:00
#: web/templates/admin/legal/form.gohtml:10
#: web/templates/admin/legal/form.gohtml:31
msgctxt "title"
2023-12-22 01:23:18 +00:00
msgid "New Legal Text"
msgstr "Nuevo texto legal"
#: web/templates/admin/legal/form.gohtml:15
#: web/templates/admin/legal/index.gohtml:6
#: web/templates/admin/legal/index.gohtml:15
#: web/templates/admin/layout.gohtml:70
msgctxt "title"
msgid "Legal Texts"
msgstr "Textos legales"
#: web/templates/admin/legal/form.gohtml:41
msgctxt "input"
2023-12-22 01:23:18 +00:00
msgid "Slug"
msgstr "Álias"
#: web/templates/admin/legal/form.gohtml:50
#: web/templates/admin/campsite/feature/form.gohtml:50
#: web/templates/admin/campsite/type/feature/form.gohtml:59
#: web/templates/admin/campsite/type/form.gohtml:51
#: web/templates/admin/campsite/type/option/form.gohtml:41
#: web/templates/admin/season/form.gohtml:50
#: web/templates/admin/services/form.gohtml:53
#: web/templates/admin/profile.gohtml:29
#: web/templates/admin/surroundings/form.gohtml:41
#: 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"
#: web/templates/admin/legal/form.gohtml:68
2023-12-22 01:23:18 +00:00
msgctxt "input"
msgid "Content"
msgstr "Contenido"
#: web/templates/admin/legal/form.gohtml:88
#: web/templates/admin/carousel/form.gohtml:55
#: 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
#: web/templates/admin/campsite/type/form.gohtml:228
#: web/templates/admin/campsite/type/option/form.gohtml:90
#: web/templates/admin/season/form.gohtml:73
#: web/templates/admin/services/form.gohtml:81
#: web/templates/admin/surroundings/form.gohtml:69
#: web/templates/admin/surroundings/index.gohtml:58
#: web/templates/admin/amenity/feature/form.gohtml:65
#: web/templates/admin/amenity/carousel/form.gohtml:50
#: web/templates/admin/amenity/form.gohtml:91
#: web/templates/admin/home/index.gohtml:34
#: web/templates/admin/media/form.gohtml:39
msgctxt "action"
msgid "Update"
msgstr "Actualizar"
#: web/templates/admin/legal/form.gohtml:90
#: web/templates/admin/carousel/form.gohtml:57
#: 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
#: web/templates/admin/campsite/type/form.gohtml:230
#: web/templates/admin/campsite/type/option/form.gohtml:92
#: web/templates/admin/season/form.gohtml:75
#: web/templates/admin/services/form.gohtml:83
#: web/templates/admin/surroundings/form.gohtml:71
#: web/templates/admin/amenity/feature/form.gohtml:67
#: web/templates/admin/amenity/carousel/form.gohtml:52
#: web/templates/admin/amenity/form.gohtml:93
msgctxt "action"
msgid "Add"
msgstr "Añadir"
#: 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"
#: web/templates/admin/legal/index.gohtml:20
#: 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
#: web/templates/admin/campsite/type/index.gohtml:29
#: web/templates/admin/season/index.gohtml:29
#: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:83
#: 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"
#: 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
#: 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
#: 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"
#: web/templates/admin/carousel/form.gohtml:40
#: web/templates/admin/campsite/carousel/form.gohtml:35
#: web/templates/admin/campsite/type/carousel/form.gohtml:44
#: web/templates/admin/amenity/carousel/form.gohtml:35
2023-12-22 01:23:18 +00:00
msgctxt "input"
msgid "Caption"
msgstr "Leyenda"
#: web/templates/admin/location.gohtml:6 web/templates/admin/location.gohtml:15
msgctxt "title"
msgid "Location Settings"
msgstr "Parámetros de cómo llegar"
#: web/templates/admin/location.gohtml:20
msgctxt "input"
msgid "Directions"
msgstr "Instrucciones"
#: web/templates/admin/location.gohtml:33
msgctxt "input"
msgid "Opening Dates"
msgstr "Fechas de apertura"
#: web/templates/admin/location.gohtml:46
msgctxt "input"
msgid "Map Embed"
msgstr "Incrustación del mapa"
#: web/templates/admin/location.gohtml:53 web/templates/admin/profile.gohtml:78
#: web/templates/admin/taxDetails.gohtml:170
#: web/templates/admin/booking/payment.gohtml:65
msgctxt "action"
msgid "Save changes"
msgstr "Guardar los cambios"
#: web/templates/admin/campsite/feature/form.gohtml:8
msgctxt "title"
msgid "Edit Campsite Feature"
msgstr "Edición de las características del alojamiento"
#: web/templates/admin/campsite/feature/form.gohtml:10
msgctxt "title"
msgid "New Campsite Feature"
msgstr "Nueva característica del alojamiento"
#: web/templates/admin/campsite/feature/form.gohtml:17
#: web/templates/admin/campsite/feature/index.gohtml:6
msgctxt "title"
msgid "Campsite Features"
msgstr "Características del alojamiento"
#: web/templates/admin/campsite/feature/form.gohtml:32
#: web/templates/admin/campsite/type/feature/form.gohtml:41
#: web/templates/admin/services/form.gohtml:35
#: web/templates/admin/amenity/feature/form.gohtml:32
msgctxt "input"
msgid "Icon"
msgstr "Icono"
#: web/templates/admin/campsite/feature/index.gohtml:15
#: web/templates/admin/campsite/type/feature/index.gohtml:16
#: web/templates/admin/amenity/feature/index.gohtml:15
msgctxt "action"
msgid "Add Feature"
msgstr "Añadir características"
#: web/templates/admin/campsite/feature/index.gohtml:31
#: web/templates/admin/campsite/carousel/index.gohtml:31
#: web/templates/admin/campsite/type/feature/index.gohtml:32
#: 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
#: web/templates/admin/amenity/feature/index.gohtml:31
#: web/templates/admin/amenity/carousel/index.gohtml:31
#: web/templates/admin/amenity/index.gohtml:25
#: 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
#: web/templates/admin/campsite/type/feature/index.gohtml:36
#: web/templates/admin/amenity/feature/index.gohtml:35
msgid "Are you sure you wish to delete this feature?"
msgstr "¿Estáis seguro de querer borrar esta característica?"
#: web/templates/admin/campsite/feature/index.gohtml:47
#: web/templates/admin/campsite/carousel/index.gohtml:49
#: web/templates/admin/campsite/type/feature/index.gohtml:48
#: 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
#: web/templates/admin/amenity/feature/index.gohtml:47
#: web/templates/admin/amenity/carousel/index.gohtml:49
#: web/templates/admin/amenity/index.gohtml:45
#: 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."
#: web/templates/admin/campsite/carousel/form.gohtml:8
msgctxt "title"
msgid "Edit Campsite Carousel Slide"
msgstr "Edición de la diapositiva del carrusel del alojamiento"
#: web/templates/admin/campsite/carousel/form.gohtml:10
msgctxt "title"
msgid "New Campsite Carousel Slide"
msgstr "Nueva diapositiva del carrusel del alojamiento"
#: web/templates/admin/campsite/carousel/form.gohtml:17
#: web/templates/admin/campsite/carousel/index.gohtml:6
msgctxt "title"
msgid "Campsite Carousel"
msgstr "Carrusel del alojamiento"
#: web/templates/admin/campsite/carousel/index.gohtml:16
#: web/templates/admin/campsite/type/carousel/index.gohtml:17
#: web/templates/admin/services/index.gohtml:15
#: web/templates/admin/amenity/carousel/index.gohtml:16
#: web/templates/admin/home/index.gohtml:84
msgctxt "action"
msgid "Add slide"
msgstr "Añadir diapositiva"
#: web/templates/admin/campsite/carousel/index.gohtml:29
#: web/templates/admin/campsite/type/carousel/index.gohtml:30
#: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/surroundings/index.gohtml:82
#: web/templates/admin/amenity/carousel/index.gohtml:29
#: web/templates/admin/home/index.gohtml:52
#: web/templates/admin/home/index.gohtml:97
msgctxt "header"
msgid "Image"
msgstr "Imagen"
#: web/templates/admin/campsite/carousel/index.gohtml:30
#: web/templates/admin/campsite/type/carousel/index.gohtml:31
#: web/templates/admin/services/index.gohtml:29
#: web/templates/admin/amenity/carousel/index.gohtml:30
#: web/templates/admin/home/index.gohtml:53
#: web/templates/admin/home/index.gohtml:98
msgctxt "header"
msgid "Caption"
msgstr "Leyenda"
#: web/templates/admin/campsite/carousel/index.gohtml:35
#: web/templates/admin/campsite/type/carousel/index.gohtml:36
#: web/templates/admin/services/index.gohtml:34
#: web/templates/admin/amenity/carousel/index.gohtml:35
#: web/templates/admin/home/index.gohtml:103
msgid "Are you sure you wish to delete this slide?"
msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:58
#: web/templates/admin/campsite/type/carousel/index.gohtml:59
#: web/templates/admin/services/index.gohtml:56
#: web/templates/admin/amenity/carousel/index.gohtml:58
#: web/templates/admin/home/index.gohtml:125
msgid "No slides added yet."
msgstr "No se ha añadido ninguna diapositiva todavía."
#: web/templates/admin/campsite/form.gohtml:8
msgctxt "title"
msgid "Edit Campsite"
msgstr "Edición del alojamientos"
#: web/templates/admin/campsite/form.gohtml:10
msgctxt "title"
msgid "New Campsite"
msgstr "Nuevo alojamiento"
#: web/templates/admin/campsite/form.gohtml:33
#: web/templates/admin/campsite/index.gohtml:27
msgctxt "campsite"
msgid "Active"
msgstr "Activo"
#: web/templates/admin/campsite/form.gohtml:42
msgctxt "input"
msgid "Campsite Type"
msgstr "Tipo de alojamiento"
#: web/templates/admin/campsite/form.gohtml:47
msgid "Select campsite type"
msgstr "Escoged un tipo de alojamiento"
#: web/templates/admin/campsite/form.gohtml:56
#: web/templates/admin/amenity/form.gohtml:42
msgctxt "input"
msgid "Label"
msgstr "Etiqueta"
#: web/templates/admin/campsite/form.gohtml:64
#: web/templates/admin/amenity/form.gohtml:63
msgctxt "input"
msgid "Info (First Column)"
msgstr "Información (primera columna)"
#: web/templates/admin/campsite/form.gohtml:77
#: web/templates/admin/amenity/form.gohtml:76
msgctxt "input"
msgid "Info (Second Column)"
msgstr "Información (segunda columna)"
#: web/templates/admin/campsite/index.gohtml:14
msgctxt "action"
msgid "Add Campsite"
msgstr "Añadir alojamiento"
#: web/templates/admin/campsite/index.gohtml:23
#: web/templates/admin/amenity/index.gohtml:20
msgctxt "header"
msgid "Label"
msgstr "Etiqueta"
#: web/templates/admin/campsite/index.gohtml:24
msgctxt "header"
msgid "Type"
msgstr "Tipo"
#: web/templates/admin/campsite/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:30
#: web/templates/admin/amenity/index.gohtml:22
msgctxt "header"
msgid "Features"
msgstr "Características"
#: web/templates/admin/campsite/index.gohtml:26
#: web/templates/admin/campsite/type/index.gohtml:32
#: web/templates/admin/amenity/index.gohtml:23
msgctxt "header"
msgid "Carousel"
msgstr "Carrusel"
#: web/templates/admin/campsite/index.gohtml:36
#: web/templates/admin/campsite/type/index.gohtml:45
#: web/templates/admin/amenity/index.gohtml:35
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
#: web/templates/admin/amenity/index.gohtml:38
msgctxt "action"
msgid "Edit Carousel"
msgstr "Editar el carrusel"
#: 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/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/admin/campsite/index.gohtml:47
msgid "No campsites added yet."
msgstr "No se ha añadido ningún alojamiento todavía."
#: 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"
#: web/templates/admin/campsite/type/feature/index.gohtml:57
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"
#: web/templates/admin/campsite/type/form.gohtml:8
#: web/templates/admin/campsite/type/form.gohtml:30
msgctxt "title"
msgid "Edit Campsite Type"
msgstr "Edición del tipo de alojamiento"
#: web/templates/admin/campsite/type/form.gohtml:10
#: web/templates/admin/campsite/type/form.gohtml:32
msgctxt "title"
msgid "New Campsite Type"
msgstr "Nuevo tipo de alojamiento"
#: web/templates/admin/campsite/type/form.gohtml:42
#: web/templates/admin/campsite/type/index.gohtml:33
msgctxt "campsite type"
msgid "Active"
msgstr "Activo"
#: web/templates/admin/campsite/type/form.gohtml:67
msgctxt "input"
msgid "Check-in"
msgstr "Entrada"
#: web/templates/admin/campsite/type/form.gohtml:80
msgctxt "input"
msgid "Check-out"
msgstr "Salida"
#: 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
msgctxt "input"
msgid "Maximum number of campers"
msgstr "Número máximo de personas"
#: web/templates/admin/campsite/type/form.gohtml:120
msgctxt "input"
msgid "Allow overflowing guests to neighbouring campsites"
msgstr "Permitir reservar alojamientos vecinos si se supera el máximo de personas"
#: web/templates/admin/campsite/type/form.gohtml:129
msgctxt "input"
msgid "Ask for zone preferences when booking"
msgstr "Pedir la preferencia de zona durante la reserva"
#: web/templates/admin/campsite/type/form.gohtml:137
msgctxt "input"
msgid "Dogs allowed"
msgstr "Se permiten perros"
#: web/templates/admin/campsite/type/form.gohtml:149
#: web/templates/admin/campsite/type/option/form.gohtml:76
msgctxt "input"
msgid "Price per night"
msgstr "Precio por noche"
#: web/templates/admin/campsite/type/form.gohtml:161
msgctxt "input"
msgid "Spiel"
msgstr "Introducción"
#: web/templates/admin/campsite/type/form.gohtml:174
msgctxt "input"
msgid "Info"
msgstr "Información"
#: web/templates/admin/campsite/type/form.gohtml:187
msgctxt "input"
msgid "Facilities"
msgstr "Equipamento"
#: web/templates/admin/campsite/type/form.gohtml:200
#: web/templates/admin/services/form.gohtml:66
#: web/templates/admin/surroundings/form.gohtml:54
msgctxt "input"
msgid "Description"
msgstr "Descripción"
#: web/templates/admin/campsite/type/form.gohtml:213
msgctxt "input"
msgid "Additional Information"
msgstr "Información adicional"
#: web/templates/admin/campsite/type/option/form.gohtml:8
#: web/templates/admin/campsite/type/option/form.gohtml:32
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
#: web/templates/admin/campsite/type/option/form.gohtml:34
msgctxt "title"
msgid "New Campsite Type Option"
msgstr "Nueva opción del tipo de alojamiento"
#: 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/admin/campsite/type/option/form.gohtml:54
msgctxt "input"
msgid "Minimum"
msgstr "Mínimo"
#: web/templates/admin/campsite/type/option/form.gohtml:62
msgctxt "input"
msgid "Maximum"
msgstr "Màximo"
#: web/templates/admin/campsite/type/option/index.gohtml:16
msgctxt "action"
msgid "Add Option"
msgstr "Añadir opción"
#: 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?"
#: 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."
#: web/templates/admin/campsite/type/index.gohtml:15
msgctxt "action"
msgid "Add Type"
msgstr "Añadir tipo"
#: web/templates/admin/campsite/type/index.gohtml:31
msgctxt "header"
msgid "Options"
msgstr "Opciones"
#: web/templates/admin/campsite/type/index.gohtml:48
msgctxt "action"
msgid "Edit Options"
msgstr "Editar opciones"
#: web/templates/admin/campsite/type/index.gohtml:60
msgid "No campsite types added yet."
msgstr "No se ha añadido ningún tipo de alojamiento todavía."
#: web/templates/admin/season/form.gohtml:8
#: web/templates/admin/season/form.gohtml:29
msgctxt "title"
msgid "Edit Season"
msgstr "Edición de temporada"
#: web/templates/admin/season/form.gohtml:10
#: web/templates/admin/season/form.gohtml:31
msgctxt "title"
msgid "New Season"
msgstr "Nueva temporada"
#: web/templates/admin/season/form.gohtml:15
#: web/templates/admin/season/index.gohtml:6
#: web/templates/admin/season/index.gohtml:15
#: web/templates/admin/layout.gohtml:52
msgctxt "title"
msgid "Seasons"
msgstr "Temporadas"
#: web/templates/admin/season/form.gohtml:41
#: web/templates/admin/season/index.gohtml:30
msgctxt "season"
msgid "Active"
msgstr "Activa"
#: web/templates/admin/season/form.gohtml:63
msgctxt "input"
msgid "Color"
msgstr "Color"
#: web/templates/admin/season/index.gohtml:14
msgctxt "action"
msgid "Add Season"
msgstr "Añadir temporada"
#: web/templates/admin/season/index.gohtml:28
msgctxt "header"
msgid "Color"
msgstr "Color"
#: web/templates/admin/season/index.gohtml:51
msgid "No seasons added yet."
msgstr "No se ha añadido ninguna temporada todavía."
#: 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
#: web/templates/admin/dashboard.gohtml:13 web/templates/admin/layout.gohtml:89
msgctxt "title"
msgid "Dashboard"
msgstr "Panel"
#: 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"
#: 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"
#: 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"
#: web/templates/admin/services/form.gohtml:8
#: web/templates/admin/services/form.gohtml:26
msgctxt "title"
msgid "Edit Service"
msgstr "Edición de servicio"
#: web/templates/admin/services/form.gohtml:10
#: web/templates/admin/services/form.gohtml:28
msgctxt "title"
msgid "New Service"
msgstr "Nuevo servicio"
#: web/templates/admin/services/form.gohtml:15
#: web/templates/admin/services/index.gohtml:6
#: web/templates/admin/layout.gohtml:61
msgctxt "title"
msgid "Services Page"
msgstr "Página de servicios"
#: web/templates/admin/services/index.gohtml:14
#: web/templates/admin/home/index.gohtml:83
msgctxt "title"
msgid "Carousel"
msgstr "Carrusel"
#: web/templates/admin/services/index.gohtml:60
2023-09-26 14:51:35 +00:00
msgctxt "action"
msgid "Add service"
msgstr "Añadir servicio"
#: web/templates/admin/services/index.gohtml:73
msgctxt "header"
msgid "Order"
msgstr "Orden"
#: web/templates/admin/services/index.gohtml:74
msgctxt "header"
msgid "Service"
msgstr "Servicio"
#: web/templates/admin/services/index.gohtml:79
msgid "Are you sure you wish to delete this service?"
msgstr "¿Estáis seguro de querer borrar este servicio?"
#: web/templates/admin/services/index.gohtml:100
msgid "No services added yet."
msgstr "No se ha añadido ningún servicio todavía."
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:15
#: web/templates/admin/layout.gohtml:33
msgctxt "title"
msgid "Profile"
msgstr "Perfil"
#: web/templates/admin/profile.gohtml:20
msgctxt "inut"
msgid "Profile Image"
msgstr "Imagen del perfil"
#: web/templates/admin/profile.gohtml:46
msgctxt "legend"
msgid "Change password"
msgstr "Cambio de contraseña"
#: web/templates/admin/profile.gohtml:58
msgctxt "input"
msgid "Password Confirmation"
msgstr "Confirmación de la contraseña"
#: web/templates/admin/profile.gohtml:68
msgctxt "input"
msgid "Language"
msgstr "Idioma"
#: web/templates/admin/user/login-attempts.gohtml:6
#: web/templates/admin/user/login-attempts.gohtml:15
msgctxt "title"
msgid "Login Attempts"
msgstr "Intentos de entrada"
#: web/templates/admin/user/login-attempts.gohtml:10
#: web/templates/admin/user/index.gohtml:6
#: web/templates/admin/user/index.gohtml:16
#: web/templates/admin/layout.gohtml:73
msgctxt "title"
msgid "Users"
msgstr "Usuarios"
#: web/templates/admin/user/login-attempts.gohtml:19
msgctxt "header"
msgid "Date"
msgstr "Fecha"
#: web/templates/admin/user/login-attempts.gohtml:20
#: web/templates/admin/user/index.gohtml:21
msgctxt "header"
msgid "Email"
msgstr "Correo-e"
#: web/templates/admin/user/login-attempts.gohtml:21
msgctxt "header"
msgid "IP Address"
msgstr "Dirección IP"
#: web/templates/admin/user/login-attempts.gohtml:22
msgctxt "header"
msgid "Success"
msgstr "Éxito"
#: web/templates/admin/user/index.gohtml:14
msgctxt "action"
msgid "Add User"
msgstr "Añadir usuario"
#: web/templates/admin/user/index.gohtml:15
msgctxt "action"
msgid "Logs"
msgstr "Registros"
#: web/templates/admin/user/index.gohtml:22
msgctxt "header"
msgid "Role"
msgstr "Rol"
#: web/templates/admin/user/index.gohtml:27
msgid "Are you sure you wish to delete this user?"
msgstr "¿Estáis seguro de querer borrar este usuario?"
#: web/templates/admin/taxDetails.gohtml:6
#: web/templates/admin/taxDetails.gohtml:15
msgctxt "title"
msgid "Tax Details"
msgstr "Configuración fiscal"
#: web/templates/admin/taxDetails.gohtml:20
#: web/templates/admin/taxDetails.gohtml:61
msgctxt "input"
msgid "Business Name"
msgstr "Nombre de empresa"
#: web/templates/admin/taxDetails.gohtml:29
msgctxt "input"
msgid "VAT Number"
msgstr "NIF"
#: web/templates/admin/taxDetails.gohtml:37
msgctxt "input"
msgid "Trade Name"
msgstr "Nombre comercial"
#: web/templates/admin/taxDetails.gohtml:69
msgctxt "input"
msgid "Address"
msgstr "Dirección"
#: web/templates/admin/taxDetails.gohtml:77
msgctxt "input"
msgid "City"
msgstr "Población"
#: web/templates/admin/taxDetails.gohtml:85
msgctxt "input"
msgid "Province"
msgstr "Provincia"
#: web/templates/admin/taxDetails.gohtml:93
msgctxt "input"
msgid "Postcode"
msgstr "Código postal"
#: web/templates/admin/taxDetails.gohtml:111
msgctxt "input"
msgid "Currency"
msgstr "Moneda"
#: web/templates/admin/taxDetails.gohtml:121
msgctxt "input"
msgid "Default Language"
msgstr "Idioma por defecto"
#: web/templates/admin/taxDetails.gohtml:130
msgctxt "title"
msgid "Tourism"
msgstr "Turismo"
#: web/templates/admin/taxDetails.gohtml:133
msgctxt "input"
msgid "RTC number"
msgstr "Número RTC"
#: web/templates/admin/taxDetails.gohtml:141
msgctxt "input"
msgid "Tourist Tax"
msgstr "Impuesto turístico"
#: web/templates/admin/taxDetails.gohtml:150
msgctxt "title"
msgid "Invoicing"
msgstr "Facturación"
#: web/templates/admin/taxDetails.gohtml:153
msgctxt "input"
msgid "Invoice Number Format"
msgstr "Formato de número de factura"
#: web/templates/admin/taxDetails.gohtml:161
msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Nota legal"
#: web/templates/admin/surroundings/form.gohtml:8
#: web/templates/admin/surroundings/form.gohtml:29
msgctxt "title"
msgid "Edit Highlight"
msgstr "Edición del punto de interés"
#: web/templates/admin/surroundings/form.gohtml:10
#: web/templates/admin/surroundings/form.gohtml:31
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"
#: web/templates/admin/surroundings/index.gohtml:14
msgctxt "title"
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"
msgid "Highlights"
msgstr "Puntos de interés"
#: web/templates/admin/surroundings/index.gohtml:69
msgctxt "action"
msgid "Add highlight"
msgstr "Añadir punto de interés"
#: web/templates/admin/surroundings/index.gohtml:88
msgid "Are you sure you wish to delete this highlight?"
msgstr "¿Estáis seguro de querer borrar este punto de interés?"
#: web/templates/admin/surroundings/index.gohtml:110
msgid "No highlights added yet."
msgstr "No se ha añadido ningún punto de interés todavía."
#: 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"
#: 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
msgid "No amenities added yet."
msgstr "No se ha añadido ninguna instalación todavía."
#: web/templates/admin/layout.gohtml:29
msgctxt "title"
msgid "User Menu"
msgstr "Menú de usuario"
#: web/templates/admin/layout.gohtml:37
msgctxt "title"
msgid "Company Settings"
msgstr "Parámetros de la empresa"
#: web/templates/admin/layout.gohtml:40
#: web/templates/admin/booking/payment.gohtml:6
#: web/templates/admin/booking/payment.gohtml:15
msgctxt "title"
msgid "Payment Settings"
msgstr "Parámetros de pago"
#: web/templates/admin/layout.gohtml:55
#: web/templates/admin/media/form.gohtml:10
#: web/templates/admin/media/index.gohtml:6
#: web/templates/admin/media/index.gohtml:14
#: web/templates/admin/media/upload.gohtml:10
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
#: 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"
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
#: web/templates/admin/layout.gohtml:78
msgctxt "action"
msgid "Logout"
msgstr "Salir"
#: web/templates/admin/layout.gohtml:92
#: web/templates/admin/booking/index.gohtml:6
#: web/templates/admin/booking/index.gohtml:16
msgctxt "title"
msgid "Bookings"
msgstr "Reservas"
#: web/templates/admin/layout.gohtml:101
msgid "Breadcrumb"
msgstr "Migas de pan"
#: web/templates/admin/layout.gohtml:113
msgid "Camper Version: %s"
msgstr "Camper versión: %s"
#: 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
msgctxt "title"
msgid "Cover"
msgstr "Portada"
#: web/templates/admin/home/index.gohtml:39
msgctxt "action"
msgid "Add cover image"
msgstr "Añadir imagen de portada"
#: web/templates/admin/home/index.gohtml:58
msgid "Are you sure you wish to delete this cover image?"
msgstr "¿Estáis seguro de querer borrar esta imagen de portada?"
#: web/templates/admin/home/index.gohtml:80
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
msgctxt "title"
msgid "Media Picker"
msgstr "Selector de medio"
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
#: 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"
#: web/templates/admin/media/picker.gohtml:26
#: 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
#: 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"
#: 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"
#: web/templates/admin/media/picker.gohtml:58
#: web/templates/admin/media/index.gohtml:23
msgid "No media uploaded yet."
msgstr "No se ha subido ningún medio todavía."
#: web/templates/admin/media/form.gohtml:6
#: web/templates/admin/media/form.gohtml:16
msgctxt "title"
msgid "Edit Media"
msgstr "Edición de medio"
#: web/templates/admin/media/form.gohtml:22
msgctxt "input"
msgid "Updated file"
msgstr "Archivo actualizado"
#: web/templates/admin/media/form.gohtml:31
msgctxt "input"
msgid "Filename"
msgstr "Nombre de archivo"
#: web/templates/admin/media/index.gohtml:15
msgctxt "action"
msgid "Upload media"
msgstr "Subir medio"
#: web/templates/admin/media/upload.gohtml:6
#: web/templates/admin/media/upload.gohtml:16
msgctxt "title"
msgid "Upload Media"
msgstr "Subida de medio"
#: web/templates/admin/booking/payment.gohtml:20
msgctxt "input"
msgid "Merchant Code"
msgstr "Código del comercio"
#: web/templates/admin/booking/payment.gohtml:29
msgctxt "input"
msgid "Terminal Number"
msgstr "Número de terminal"
#: web/templates/admin/booking/payment.gohtml:39
msgctxt "input"
msgid "Merchant Key (only if must change it)"
msgstr "Clave del comercio (sólo si se debe cambiar)"
#: web/templates/admin/booking/payment.gohtml:41
msgctxt "input"
msgid "Merchant Key"
msgstr "Clave del comercio"
#: web/templates/admin/booking/payment.gohtml:51
msgctxt "title"
msgid "Environment"
msgstr "Entorno"
#: web/templates/admin/booking/payment.gohtml:58
msgctxt "title"
msgid "Integration"
msgstr "Integración"
#: web/templates/admin/booking/index.gohtml:14
msgctxt "action"
msgid "Add Booking"
msgstr "Añadir reserva"
#: web/templates/admin/booking/index.gohtml:15
msgctxt "action"
msgid "Export Bookings"
msgstr "Exportar eservas"
#: web/templates/admin/booking/index.gohtml:21
msgctxt "header"
msgid "Reference"
msgstr "Referencia"
#: web/templates/admin/booking/index.gohtml:22
msgctxt "header"
msgid "Arrival Date"
msgstr "Fecha de llegada"
#: web/templates/admin/booking/index.gohtml:23
msgctxt "header"
msgid "Departure Date"
msgstr "Fecha de salida"
#: web/templates/admin/booking/index.gohtml:24
msgctxt "header"
msgid "Holder Name"
msgstr "Nombre del titular"
#: web/templates/admin/booking/index.gohtml:25
msgctxt "header"
msgid "Status"
msgstr "Estado"
#: web/templates/admin/booking/index.gohtml:41
msgid "No booking found."
msgstr "No se ha encontrado ninguna reserva."
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357
#: pkg/campsite/types/feature.go:272 pkg/campsite/types/admin.go:528
#: pkg/campsite/feature.go:269 pkg/season/admin.go:412
#: pkg/services/admin.go:316 pkg/surroundings/admin.go:340
#: 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."
#: pkg/legal/admin.go:259 pkg/campsite/types/option.go:358
#: pkg/campsite/types/feature.go:273 pkg/campsite/types/admin.go:529
#: 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."
#: pkg/carousel/admin.go:276 pkg/campsite/types/carousel.go:225
#: pkg/campsite/carousel.go:227 pkg/amenity/carousel.go:227
msgctxt "input"
msgid "Slide image"
msgstr "Imagen de la diapositiva"
#: pkg/carousel/admin.go:277 pkg/campsite/types/carousel.go:226
#: pkg/campsite/carousel.go:228 pkg/amenity/carousel.go:228
msgctxt "action"
msgid "Set slide image"
msgstr "Establecer la imagen de la diapositiva"
#: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299
#: pkg/campsite/carousel.go:302 pkg/surroundings/admin.go:335
#: pkg/amenity/carousel.go:302
msgid "Slide image can not be empty."
msgstr "No podéis dejar la imagen de la diapositiva en blanco."
#: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300
#: pkg/campsite/carousel.go:303 pkg/surroundings/admin.go:336
#: pkg/amenity/carousel.go:303
msgid "Slide image must be an image media type."
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:217
#: pkg/booking/public.go:312
msgid "Email can not be empty."
msgstr "No podéis dejar el correo-e en blanco."
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:218
#: pkg/booking/public.go:313
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
msgid "Password can not be empty."
msgstr "No podéis dejar la contraseña en blanco."
#: pkg/app/login.go:86
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
#: pkg/app/user.go:197
msgctxt "language option"
msgid "Automatic"
msgstr "Automático"
#: pkg/app/user.go:250
msgid "Confirmation does not match password."
msgstr "La confirmación no se corresponde con la contraseña."
#: pkg/app/user.go:251 pkg/company/admin.go:238
msgid "Selected language is not valid."
msgstr "El idioma escogido no es válido."
#: pkg/app/user.go:253
msgid "File must be a valid PNG or JPEG image."
msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
#: pkg/app/admin.go:70
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"
#: pkg/campsite/types/option.go:361
msgid "Minimum can not be empty."
msgstr "No podéis dejar el mínimo en blanco."
#: pkg/campsite/types/option.go:362
msgid "Minimum must be an integer number."
msgstr "El valor de mínimo tiene que ser un número entero."
#: pkg/campsite/types/option.go:364
msgid "Minimum must be zero or greater."
msgstr "El valor de mínimo tiene que ser como mínimo cero."
#: pkg/campsite/types/option.go:367
msgid "Maximum can not be empty."
msgstr "No podéis dejar el máxmimo en blanco."
#: pkg/campsite/types/option.go:368
msgid "Maximum must be an integer number."
msgstr "El valor del máximo tiene que ser un número entero."
#: pkg/campsite/types/option.go:370
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."
#: pkg/campsite/types/option.go:374 pkg/campsite/types/admin.go:554
msgid "Price per night can not be empty."
msgstr "No podéis dejar el precio por noche en blanco."
#: pkg/campsite/types/option.go:375 pkg/campsite/types/admin.go:555
msgid "Price per night must be a decimal number."
msgstr "El precio por noche tiene que ser un número decimal."
#: pkg/campsite/types/option.go:376 pkg/campsite/types/admin.go:556
msgid "Price per night must be zero or greater."
msgstr "El precio por noche tiene que ser como mínimo cero."
#: pkg/campsite/types/feature.go:271 pkg/campsite/feature.go:268
#: pkg/services/admin.go:315 pkg/amenity/feature.go:268
msgid "Selected icon is not valid."
msgstr "El icono escogido no es válido."
#: pkg/campsite/types/admin.go:310
msgctxt "input"
msgid "Cover image"
msgstr "Imagen de portada"
#: pkg/campsite/types/admin.go:311
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Establecer la portada del tipo de alojamiento"
#: pkg/campsite/types/admin.go:531
msgid "Check-in can not be empty."
msgstr "No podéis dejar la entrada en blanco."
#: pkg/campsite/types/admin.go:532
msgid "Check-out can not be empty."
msgstr "No podéis dejar la salida en blanco."
#: pkg/campsite/types/admin.go:533
msgid "Cover image can not be empty."
msgstr "No podéis dejar la imagen de portada en blanco."
#: pkg/campsite/types/admin.go:534
msgid "Cover image must be an image media type."
msgstr "La imagen de portada tiene que ser un medio de tipo imagen."
#: pkg/campsite/types/admin.go:538
msgid "Maximum number of campers can not be empty."
msgstr "No podéis dejar el número máximo de personas en blanco."
#: pkg/campsite/types/admin.go:539
msgid "Maximum number of campers must be an integer number."
msgstr "El número máximo de personas tiene que ser entero."
#: pkg/campsite/types/admin.go:540
msgid "Maximum number of campers must be one or greater."
msgstr "El número máximo de personas no puede ser cero."
#: pkg/campsite/types/admin.go:543
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."
#: pkg/campsite/types/admin.go:544
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."
#: pkg/campsite/types/admin.go:545
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."
#: pkg/campsite/types/admin.go:548
msgid "Maximum number of nights can not be empty."
msgstr "No podéis dejar el número máximo de noches en blanco."
#: pkg/campsite/types/admin.go:549
msgid "Maximum number of nights must be an integer."
msgstr "El número máximo de noches tiene que ser entero."
#: pkg/campsite/types/admin.go:550
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."
#: pkg/campsite/admin.go:275 pkg/booking/public.go:321
msgid "Selected campsite type is not valid."
msgstr "El tipo de alojamiento escogido no es válido."
#: pkg/campsite/admin.go:276 pkg/amenity/admin.go:282
msgid "Label can not be empty."
msgstr "No podéis dejar la etiqueta en blanco."
#: pkg/season/admin.go:183
msgctxt "month"
msgid "January"
msgstr "enero"
#: pkg/season/admin.go:184
msgctxt "month"
msgid "February"
msgstr "febrero"
#: pkg/season/admin.go:185
msgctxt "month"
msgid "March"
msgstr "marzo"
#: pkg/season/admin.go:186
msgctxt "month"
msgid "April"
msgstr "abril"
#: pkg/season/admin.go:187
msgctxt "month"
msgid "May"
msgstr "mayo"
#: pkg/season/admin.go:188
msgctxt "month"
msgid "June"
msgstr "junio"
#: pkg/season/admin.go:189
msgctxt "month"
msgid "July"
msgstr "julio"
#: pkg/season/admin.go:190
msgctxt "month"
msgid "August"
msgstr "agosto"
#: pkg/season/admin.go:191
msgctxt "month"
msgid "September"
msgstr "septiembre"
#: pkg/season/admin.go:192
msgctxt "month"
msgid "October"
msgstr "octubre"
#: pkg/season/admin.go:193
msgctxt "month"
msgid "November"
msgstr "noviembre"
#: pkg/season/admin.go:194
msgctxt "month"
msgid "December"
msgstr "diciembre"
#: pkg/season/admin.go:413
msgid "Color can not be empty."
msgstr "No podéis dejar el color en blanco."
#: pkg/season/admin.go:414
msgid "This color is not valid. It must be like #123abc."
msgstr "Este color no es válido. Tiene que ser parecido a #123abc."
#: pkg/season/admin.go:514
msgctxt "action"
msgid "Unset"
msgstr "Desasignar"
#: pkg/season/admin.go:545
msgid "Start date can not be empty."
msgstr "No podéis dejar la fecha de inicio en blanco."
#: pkg/season/admin.go:546
msgid "Start date must be a valid date."
msgstr "La fecha de inicio tiene que ser una fecha válida."
#: pkg/season/admin.go:548
msgid "End date can not be empty."
msgstr "No podéis dejar la fecha final en blanco."
#: pkg/season/admin.go:549
msgid "End date must be a valid date."
msgstr "La fecha final tiene que ser una fecha válida."
#: 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"
#: pkg/surroundings/admin.go:286
msgctxt "input"
msgid "Highlight image"
msgstr "Imagen del punto de interés"
#: pkg/surroundings/admin.go:287
msgctxt "action"
msgid "Set highlight image"
msgstr "Establecer la imagen del punto de interés"
#: 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."
#: pkg/surroundings/admin.go:467 pkg/company/admin.go:221
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/."
#: pkg/company/admin.go:200 pkg/booking/public.go:299
msgid "Selected country is not valid."
msgstr "El país escogido no es válido."
#: pkg/company/admin.go:204
msgid "Business name can not be empty."
msgstr "No podéis dejar el nombre de empresa en blanco."
#: pkg/company/admin.go:205
msgid "Business name must have at least two letters."
msgstr "El nombre de la empresa tiene que tener como mínimo dos letras."
#: pkg/company/admin.go:207
msgid "VAT number can not be empty."
msgstr "No podéis dejar el NIF en blanco."
#: pkg/company/admin.go:208
msgid "This VAT number is not valid."
msgstr "Este NIF no es válido."
#: pkg/company/admin.go:212 pkg/booking/public.go:315
msgid "Phone can not be empty."
msgstr "No podéis dejar el teléfono en blanco."
#: pkg/company/admin.go:213 pkg/booking/public.go:316
msgid "This phone number is not valid."
msgstr "Este teléfono no es válido."
#: pkg/company/admin.go:223
msgid "Address can not be empty."
msgstr "No podéis dejar la dirección en blanco."
#: pkg/company/admin.go:224
msgid "City can not be empty."
msgstr "No podéis dejar la población en blanco."
#: pkg/company/admin.go:225
msgid "Province can not be empty."
msgstr "No podéis dejar la provincia en blanco."
#: pkg/company/admin.go:226
msgid "Postal code can not be empty."
msgstr "No podéis dejar el código postal en blanco."
#: pkg/company/admin.go:227 pkg/booking/public.go:308
msgid "This postal code is not valid."
msgstr "Este código postal no es válido."
#: pkg/company/admin.go:231
msgid "RTC number can not be empty."
msgstr "No podéis dejar el número RTC en blanco."
#: pkg/company/admin.go:232
msgid "Tourist tax can not be empty."
msgstr "No podéis dejar el impuesto turístico en blanco."
#: pkg/company/admin.go:233
msgid "Tourist tax must be a decimal number."
msgstr "El impuesto turístico tiene que ser un número decimal."
#: pkg/company/admin.go:234
msgid "Tourist tax must be zero or greater."
msgstr "El impuesto turístico tiene que ser como mínimo cero."
#: pkg/company/admin.go:237
msgid "Selected currency is not valid."
msgstr "La moneda escogida no es válida."
#: pkg/company/admin.go:239
msgid "Invoice number format can not be empty."
msgstr "No podéis dejar el formato de número de factura en blanco."
#: 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."
#: pkg/media/admin.go:312
msgid "Uploaded file can not be empty."
msgstr "No podéis dejar el archivo del medio en blanco."
#: pkg/media/admin.go:371
msgid "Filename can not be empty."
msgstr "No podéis dejar el nombre del archivo en blanco."
#: pkg/booking/admin.go:149
msgctxt "filename"
msgid "bookings.ods"
msgstr "reservas.ods"
#: pkg/booking/admin.go:177
msgctxt "redsys environment"
msgid "Test"
msgstr "Pruebas"
#: pkg/booking/admin.go:181
msgctxt "redsys environment"
msgid "Live"
msgstr "Real"
#: pkg/booking/admin.go:190
msgctxt "redsys integration"
msgid "InSite"
msgstr "InSite"
#: pkg/booking/admin.go:194
msgctxt "redsys integration"
msgid "Redirect"
msgstr "Redirección"
#: pkg/booking/admin.go:238
msgid "Merchant code can not be empty."
msgstr "No podéis dejar el código del comercio en blanco."
#: pkg/booking/admin.go:239
msgid "Merchant code must be exactly nine digits long."
msgstr "El código del comercio tiene que ser de nueve dígitos."
#: pkg/booking/admin.go:240
msgid "Merchant code must be a number."
msgstr "El código del comercio tiene que ser un número."
#: pkg/booking/admin.go:244
msgid "Terminal number can not be empty."
msgstr "No podéis dejar el número de terminal en blanco."
#: pkg/booking/admin.go:245
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/booking/admin.go:253
msgid "Selected environment is not valid."
msgstr "El entorno escogido no es válido."
#: pkg/booking/admin.go:254
msgid "Selected integration is not valid."
msgstr "La integración escogida no es válida."
#: pkg/booking/admin.go:257
msgid "The merchant key is not valid."
msgstr "Esta clave del comercio no es válida."
#: pkg/booking/public.go:303
msgid "Full name can not be empty."
msgstr "No podéis dejar el nombre y los apellidos en blanco."
#: pkg/booking/public.go:304
msgid "Full name must have at least one letter."
msgstr "El nombre y los apellidos tienen que tener como mínimo una letra."
#: pkg/booking/public.go:322
msgid "Arrival date can not be empty"
msgstr "No podéis dejar la fecha de llegada en blanco."
#: pkg/booking/public.go:323
msgid "Arrival date must be a valid date."
msgstr "La fecha de llegada tiene que ser una fecha válida."
#: pkg/booking/public.go:327
msgid "Departure date can not be empty"
msgstr "No podéis dejar la fecha de partida en blanco."
#: pkg/booking/public.go:328
msgid "Departure date must be a valid date."
msgstr "La fecha de partida tiene que ser una fecha válida."
#: pkg/booking/public.go:329
msgid "The departure date must be after the arrival date."
msgstr "La fecha de partida tiene que ser posterior a la de llegada."
#: pkg/booking/public.go:332
msgid "It is mandatory to agree to the reservation conditions."
msgstr "Es obligatorio aceptar las condiciones de reserva."
#: pkg/booking/public.go:335
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
msgid "%s can not be empty"
msgstr "No podéis dejar %s en blanco."
#: pkg/booking/public.go:336
#, c-format
msgid "%s must be an integer."
msgstr "%s tiene que ser un número entero."
#: pkg/booking/public.go:337
#, c-format
msgid "%s must be %d or greater."
msgstr "%s tiene que ser como mínimo %d."
#: pkg/booking/public.go:338
#, c-format
msgid "%s must be at most %d."
msgstr "%s tiene que ser como máximo %d"
#~ msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den 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 den 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…."
#~ 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"
#~ msgctxt "title"
#~ msgid "Translate Carousel Slide to %s"
#~ msgstr "Traducción de la diapositiva de carrusel a %s"
#~ msgctxt "title"
#~ 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"
#~ msgctxt "title"
#~ msgid "Party Details"
#~ msgstr "Datos de los visitantes"
#~ msgctxt "input"
#~ msgid "Adults"
#~ msgstr "Adultos"
#~ msgctxt "input"
#~ msgid "Teenagers (from 11 to 16 years old)"
#~ msgstr "Adolescentes (de 11 a 16 años)"
#~ msgctxt "input"
#~ msgid "Children (up to 10 years old)"
#~ msgstr "Niños (hasta 10 años)"
#~ msgctxt "input"
#~ msgid "Dogs"
#~ msgstr "Perros"
#~ msgid "Number of adults can not be empty"
#~ msgstr "No podéis dejar el número de adultos blanco."
#~ msgid "Number of adults must be an integer."
#~ msgstr "El número de adultos tiene que ser entero."
#~ msgid "Number of adults must be one or greater."
#~ msgstr "El número de adultos no puede ser cero."
#~ msgid "Number of teenagers can not be empty"
#~ msgstr "No podéis dejar el número de adolescentes en blanco."
#~ msgid "Number of teenagers must be an integer."
#~ msgstr "El número de adolescentes tiene que ser entero."
#~ 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 can not be empty"
#~ msgstr "No podéis dejar el número de niños en blanco."
#~ msgid "Number of children must be an integer."
#~ msgstr "El número de niños tiene que ser entero."
#~ 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 can not be empty"
#~ msgstr "No podéis dejar el número de perros en blanco."
#~ msgid "Number of dogs must be an integer."
#~ msgstr "El número de perros tiene que ser entero."
#~ msgid "Number of dogs must be zero or greater."
#~ msgstr "El número de perros tiene que ser como mínimo cero."
#~ msgctxt "input"
#~ msgid "Pricing"
#~ msgstr "Precios"
#~ msgctxt "input"
#~ msgid "Features"
#~ msgstr "Características"
#~ msgid "Singular Lodges"
#~ msgstr "Alojamientos singulares"
#~ msgctxt "campsite type"
#~ msgid "Translations"
#~ msgstr "Traducciones"
#~ msgid "Surroundings"
#~ msgstr "Entorno"
#~ msgctxt "title"
#~ msgid "Pages"
#~ msgstr "Páginas"
#~ msgctxt "action"
#~ msgid "Add Page"
#~ msgstr "Añadir página"
#~ msgctxt "header"
#~ msgid "Title"
#~ msgstr "Título"