Replace use of L10NInput with I18nInput for campsite

This commit is contained in:
jordi fita mas 2024-01-10 21:52:49 +01:00
parent 3f46ea3a9a
commit f28664acce
22 changed files with 657 additions and 1213 deletions

View File

@ -105,23 +105,7 @@ func (h *AdminHandler) typeHandler(user *auth.User, company *auth.Company, conn
case "slides": case "slides":
h.carouselHandler(user, company, conn, f.Slug).ServeHTTP(w, r) h.carouselHandler(user, company, conn, f.Slug).ServeHTTP(w, r)
default: default:
loc, ok := h.locales.Get(head)
if !ok {
http.NotFound(w, r) http.NotFound(w, r)
return
}
l10n := newTypeL10nForm(f, loc)
if err := l10n.FillFromDatabase(r.Context(), conn); err != nil {
panic(err)
}
switch r.Method {
case http.MethodGet:
l10n.MustRender(w, r, user, company)
case http.MethodPut:
editTypeL10n(w, r, user, company, conn, l10n)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
}
} }
}) })
} }
@ -141,13 +125,6 @@ type typeEntry struct {
Slug string Slug string
Name string Name string
Active bool Active bool
Translations []*translation
}
type translation struct {
Language string
Endonym string
Missing bool
} }
func collectTypeEntries(ctx context.Context, company *auth.Company, conn *database.Conn) ([]*typeEntry, error) { func collectTypeEntries(ctx context.Context, company *auth.Company, conn *database.Conn) ([]*typeEntry, error) {
@ -155,19 +132,10 @@ func collectTypeEntries(ctx context.Context, company *auth.Company, conn *databa
select campsite_type.slug select campsite_type.slug
, campsite_type.name , campsite_type.name
, campsite_type.active , campsite_type.active
, array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_i18n as i18n where i18n.campsite_type_id = campsite_type.campsite_type_id and i18n.lang_tag = language.lang_tag)) order by endonym)
from campsite_type from campsite_type
join company using (company_id) where campsite_type.company_id = $1
, language
where lang_tag <> default_lang_tag
and language.selectable
and campsite_type.company_id = $1
group by campsite_type.slug
, campsite_type.name
, campsite_type.position
, campsite_type.active
order by position, name order by position, name
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, company.ID) `, company.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -176,17 +144,9 @@ func collectTypeEntries(ctx context.Context, company *auth.Company, conn *databa
var types []*typeEntry var types []*typeEntry
for rows.Next() { for rows.Next() {
entry := &typeEntry{} entry := &typeEntry{}
var translations database.RecordArray if err = rows.Scan(&entry.Slug, &entry.Name, &entry.Active); err != nil {
if err = rows.Scan(&entry.Slug, &entry.Name, &entry.Active, &translations); err != nil {
return nil, err return nil, err
} }
for _, el := range translations.Elements {
entry.Translations = append(entry.Translations, &translation{
el.Fields[0].Get().(string),
el.Fields[1].Get().(string),
el.Fields[2].Get().(bool),
})
}
types = append(types, entry) types = append(types, entry)
} }
@ -207,14 +167,30 @@ func addType(w http.ResponseWriter, r *http.Request, user *auth.User, company *a
panic(err) panic(err)
} }
processTypeForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error { processTypeForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
slug, err := tx.AddCampsiteType(ctx, company.ID, f.Media.Int(), f.Name.Val, f.Spiel.Val, f.Info.Val, f.Facilities.Val, f.Description.Val, f.MaxCampers.Int(), f.DogsAllowed.Checked) slug, err := tx.AddCampsiteType(ctx, company.ID, f.Media.Int(), f.Name[f.DefaultLang].Val, f.Spiel[f.DefaultLang].Val, f.Info[f.DefaultLang].Val, f.Facilities[f.DefaultLang].Val, f.Description[f.DefaultLang].Val, f.MaxCampers.Int(), f.DogsAllowed.Checked)
if err != nil { if err != nil {
return err return err
} }
if err := translateTypes(ctx, tx, company, f); err != nil {
return err
}
return setTypePrices(ctx, tx, slug, f.Prices) return setTypePrices(ctx, tx, slug, f.Prices)
}) })
} }
func translateTypes(ctx context.Context, tx *database.Tx, company *auth.Company, f *typeForm) error {
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateCampsiteType(ctx, f.Slug, lang, f.Name[l].Val, f.Spiel[l].Val, f.Info[l].Val, f.Facilities[l].Val, f.Description[l].Val); err != nil {
return err
}
}
return nil
}
func setTypePrices(ctx context.Context, tx *database.Tx, slug string, prices map[int]*typePriceForm) error { func setTypePrices(ctx context.Context, tx *database.Tx, slug string, prices map[int]*typePriceForm) error {
for seasonID, p := range prices { for seasonID, p := range prices {
if err := tx.SetCampsiteTypeCost(ctx, slug, seasonID, p.MinNights.Int(), p.PricePerNight.Val); err != nil { if err := tx.SetCampsiteTypeCost(ctx, slug, seasonID, p.MinNights.Int(), p.PricePerNight.Val); err != nil {
@ -226,7 +202,10 @@ func setTypePrices(ctx context.Context, tx *database.Tx, slug string, prices map
func editType(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *typeForm) { func editType(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *typeForm) {
processTypeForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error { processTypeForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
if _, err := tx.EditCampsiteType(ctx, f.Slug, f.Media.Int(), f.Name.Val, f.Spiel.Val, f.Info.Val, f.Facilities.Val, f.Description.Val, f.MaxCampers.Int(), f.DogsAllowed.Checked, f.Active.Checked); err != nil { if _, err := tx.EditCampsiteType(ctx, f.Slug, f.Media.Int(), f.Name[f.DefaultLang].Val, f.Spiel[f.DefaultLang].Val, f.Info[f.DefaultLang].Val, f.Facilities[f.DefaultLang].Val, f.Description[f.DefaultLang].Val, f.MaxCampers.Int(), f.DogsAllowed.Checked, f.Active.Checked); err != nil {
return err
}
if err := translateTypes(ctx, tx, company, f); err != nil {
return err return err
} }
return setTypePrices(ctx, tx, f.Slug, f.Prices) return setTypePrices(ctx, tx, f.Slug, f.Prices)
@ -291,16 +270,17 @@ func processTypeForm(w http.ResponseWriter, r *http.Request, user *auth.User, co
} }
type typeForm struct { type typeForm struct {
DefaultLang string
Slug string Slug string
Active *form.Checkbox Active *form.Checkbox
Media *form.Media Media *form.Media
Name *form.Input Name form.I18nInput
MaxCampers *form.Input MaxCampers *form.Input
DogsAllowed *form.Checkbox DogsAllowed *form.Checkbox
Spiel *form.Input Spiel form.I18nInput
Info *form.Input Info form.I18nInput
Facilities *form.Input Facilities form.I18nInput
Description *form.Input Description form.I18nInput
Prices map[int]*typePriceForm Prices map[int]*typePriceForm
} }
@ -312,6 +292,7 @@ type typePriceForm struct {
func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn) (*typeForm, error) { func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn) (*typeForm, error) {
f := &typeForm{ f := &typeForm{
DefaultLang: company.DefaultLanguage.String(),
Active: &form.Checkbox{ Active: &form.Checkbox{
Name: "active", Name: "active",
Checked: true, Checked: true,
@ -323,27 +304,17 @@ func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn
Label: locale.PgettextNoop("Cover image", "input"), Label: locale.PgettextNoop("Cover image", "input"),
Prompt: locale.PgettextNoop("Set campsite type cover", "action"), Prompt: locale.PgettextNoop("Set campsite type cover", "action"),
}, },
Name: &form.Input{ Name: form.NewI18nInput(company.Locales, "name"),
Name: "name",
},
MaxCampers: &form.Input{ MaxCampers: &form.Input{
Name: "max_campers", Name: "max_campers",
}, },
DogsAllowed: &form.Checkbox{ DogsAllowed: &form.Checkbox{
Name: "dogs_allowed", Name: "dogs_allowed",
}, },
Spiel: &form.Input{ Spiel: form.NewI18nInput(company.Locales, "spiel"),
Name: "spiel", Info: form.NewI18nInput(company.Locales, "info"),
}, Facilities: form.NewI18nInput(company.Locales, "facilities"),
Info: &form.Input{ Description: form.NewI18nInput(company.Locales, "description"),
Name: "info",
},
Facilities: &form.Input{
Name: "facilities",
},
Description: &form.Input{
Name: "description",
},
} }
rows, err := conn.Query(ctx, "select season_id, name from season where active and company_id = $1", company.ID) rows, err := conn.Query(ctx, "select season_id, name from season where active and company_id = $1", company.ID)
@ -377,20 +348,55 @@ func newTypeForm(ctx context.Context, company *auth.Company, conn *database.Conn
func (f *typeForm) FillFromDatabase(ctx context.Context, conn *database.Conn, slug string) error { func (f *typeForm) FillFromDatabase(ctx context.Context, conn *database.Conn, slug string) error {
f.Slug = slug f.Slug = slug
var name database.RecordArray
var spiel database.RecordArray
var info database.RecordArray
var facilities database.RecordArray
var description database.RecordArray
row := conn.QueryRow(ctx, ` row := conn.QueryRow(ctx, `
select name select campsite_type.name
, spiel::text , campsite_type.spiel::text
, info::text , campsite_type.info::text
, facilities::text , campsite_type.facilities::text
, description::text , campsite_type.description::text
, media_id::text , media_id::text
, max_campers::text , max_campers::text
, dogs_allowed , dogs_allowed
, active , active
, array_agg((lang_tag, i18n.name))
, array_agg((lang_tag, i18n.spiel::text))
, array_agg((lang_tag, i18n.info::text))
, array_agg((lang_tag, i18n.facilities::text))
, array_agg((lang_tag, i18n.description::text))
from campsite_type from campsite_type
left join campsite_type_i18n as i18n using (campsite_type_id)
where slug = $1 where slug = $1
`, slug) group by campsite_type.name
if err := row.Scan(&f.Name.Val, &f.Spiel.Val, &f.Info.Val, &f.Facilities.Val, &f.Description.Val, &f.Media.Val, &f.MaxCampers.Val, &f.DogsAllowed.Checked, &f.Active.Checked); err != nil { , campsite_type.spiel::text
, campsite_type.info::text
, campsite_type.facilities::text
, campsite_type.description::text
, media_id::text
, max_campers::text
, dogs_allowed
, active
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, slug)
if err := row.Scan(&f.Name[f.DefaultLang].Val, &f.Spiel[f.DefaultLang].Val, &f.Info[f.DefaultLang].Val, &f.Facilities[f.DefaultLang].Val, &f.Description[f.DefaultLang].Val, &f.Media.Val, &f.MaxCampers.Val, &f.DogsAllowed.Checked, &f.Active.Checked, &name, &spiel, &info, &facilities, &description); err != nil {
return err
}
if err := f.Name.FillArray(name); err != nil {
return err
}
if err := f.Spiel.FillArray(spiel); err != nil {
return err
}
if err := f.Info.FillArray(info); err != nil {
return err
}
if err := f.Facilities.FillArray(facilities); err != nil {
return err
}
if err := f.Description.FillArray(description); err != nil {
return err return err
} }
@ -444,8 +450,8 @@ func (f *typeForm) Parse(r *http.Request) error {
func (f *typeForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) { func (f *typeForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) {
v := form.NewValidator(l) v := form.NewValidator(l)
if v.CheckRequired(f.Name, l.GettextNoop("Name can not be empty.")) { if v.CheckRequired(f.Name[f.DefaultLang], l.GettextNoop("Name can not be empty.")) {
v.CheckMinLength(f.Name, 1, l.GettextNoop("Name must have at least one letter.")) v.CheckMinLength(f.Name[f.DefaultLang], 1, l.GettextNoop("Name must have at least one letter."))
} }
if v.CheckRequired(f.Media.Input, l.GettextNoop("Cover image can not be empty.")) { if v.CheckRequired(f.Media.Input, l.GettextNoop("Cover image can not be empty.")) {
if _, err := v.CheckImageMedia(ctx, conn, f.Media.Input, l.GettextNoop("Cover image must be an image media type.")); err != nil { if _, err := v.CheckImageMedia(ctx, conn, f.Media.Input, l.GettextNoop("Cover image must be an image media type.")); err != nil {

View File

@ -39,7 +39,7 @@ func (h *AdminHandler) carouselHandler(user *auth.User, company *auth.Company, c
case "new": case "new":
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
f := newSlideForm(typeSlug) f := newSlideForm(company, typeSlug)
f.MustRender(w, r, user, company) f.MustRender(w, r, user, company)
default: default:
httplib.MethodNotAllowed(w, r, http.MethodGet) httplib.MethodNotAllowed(w, r, http.MethodGet)
@ -57,7 +57,7 @@ func (h *AdminHandler) carouselHandler(user *auth.User, company *auth.Company, c
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
f := newSlideForm(typeSlug) f := newSlideForm(company, typeSlug)
if err := f.FillFromDatabase(r.Context(), conn, mediaID); err != nil { if err := f.FillFromDatabase(r.Context(), conn, mediaID); err != nil {
if database.ErrorIsNotFound(err) { if database.ErrorIsNotFound(err) {
http.NotFound(w, r) http.NotFound(w, r)
@ -82,23 +82,7 @@ func (h *AdminHandler) carouselHandler(user *auth.User, company *auth.Company, c
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut, http.MethodDelete) httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut, http.MethodDelete)
} }
default: default:
loc, ok := h.locales.Get(langTag)
if !ok {
http.NotFound(w, r) http.NotFound(w, r)
return
}
l10n := newSlideL10nForm(f, loc)
if err := l10n.FillFromDatabase(r.Context(), conn); err != nil {
panic(err)
}
switch r.Method {
case http.MethodGet:
l10n.MustRender(w, r, user, company)
case http.MethodPut:
editSlideL10n(w, r, user, company, conn, l10n)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
}
} }
} }
}) })
@ -165,21 +149,12 @@ func collectSlideEntries(ctx context.Context, conn *database.Conn, typeSlug stri
select carousel.media_id select carousel.media_id
, media.path , media.path
, caption , caption
, array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_carousel_i18n as i18n where i18n.media_id = carousel.media_id and i18n.lang_tag = language.lang_tag)) order by endonym)
from campsite_type_carousel as carousel from campsite_type_carousel as carousel
join campsite_type using (campsite_type_id) join campsite_type using (campsite_type_id)
join media on media.media_id = carousel.media_id join media on media.media_id = carousel.media_id
join company on company.company_id = campsite_type.company_id where campsite_type.slug = $1
, language
where lang_tag <> default_lang_tag
and language.selectable
and campsite_type.slug = $1
group by carousel.media_id
, carousel.position
, media.path
, caption
order by carousel.position, caption order by carousel.position, caption
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, typeSlug) `, typeSlug)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -188,17 +163,9 @@ func collectSlideEntries(ctx context.Context, conn *database.Conn, typeSlug stri
var slides []*carousel.SlideEntry var slides []*carousel.SlideEntry
for rows.Next() { for rows.Next() {
slide := &carousel.SlideEntry{} slide := &carousel.SlideEntry{}
var translations database.RecordArray if err = rows.Scan(&slide.ID, &slide.Media, &slide.Caption); err != nil {
if err = rows.Scan(&slide.ID, &slide.Media, &slide.Caption, &translations); err != nil {
return nil, err return nil, err
} }
for _, el := range translations.Elements {
slide.Translations = append(slide.Translations, &carousel.Translation{
Language: el.Fields[0].Get().(string),
Endonym: el.Fields[1].Get().(string),
Missing: el.Fields[2].Get().(bool),
})
}
slides = append(slides, slide) slides = append(slides, slide)
} }
@ -206,13 +173,25 @@ func collectSlideEntries(ctx context.Context, conn *database.Conn, typeSlug stri
} }
func addSlide(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) { func addSlide(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) {
f := newSlideForm(typeSlug) f := newSlideForm(company, typeSlug)
editSlide(w, r, user, company, conn, f) editSlide(w, r, user, company, conn, f)
} }
func editSlide(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *slideForm) { func editSlide(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *slideForm) {
f.process(w, r, user, company, conn, func(ctx context.Context) { f.process(w, r, user, company, conn, func(ctx context.Context, tx *database.Tx) error {
conn.MustExec(ctx, "select add_campsite_type_carousel_slide($1, $2, $3)", f.TypeSlug, f.Media, f.Caption) if err := tx.AddCampsiteTypeCarouselSlide(ctx, f.TypeSlug, f.Media.Int(), f.Caption[f.DefaultLang].Val); err != nil {
return nil
}
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateCampsiteTypeCarouselSlide(ctx, f.TypeSlug, f.Media.Int(), lang, f.Caption[l].Val); err != nil {
return err
}
}
return nil
}) })
} }
@ -226,14 +205,16 @@ func (h *AdminHandler) deleteSlide(w http.ResponseWriter, r *http.Request, user
} }
type slideForm struct { type slideForm struct {
DefaultLang string
TypeSlug string TypeSlug string
MediaID int MediaID int
Media *form.Media Media *form.Media
Caption *form.Input Caption form.I18nInput
} }
func newSlideForm(typeSlug string) *slideForm { func newSlideForm(company *auth.Company, typeSlug string) *slideForm {
return &slideForm{ return &slideForm{
DefaultLang: company.DefaultLanguage.String(),
TypeSlug: typeSlug, TypeSlug: typeSlug,
Media: &form.Media{ Media: &form.Media{
Input: &form.Input{ Input: &form.Input{
@ -242,26 +223,35 @@ func newSlideForm(typeSlug string) *slideForm {
Label: locale.PgettextNoop("Slide image", "input"), Label: locale.PgettextNoop("Slide image", "input"),
Prompt: locale.PgettextNoop("Set slide image", "action"), Prompt: locale.PgettextNoop("Set slide image", "action"),
}, },
Caption: &form.Input{ Caption: form.NewI18nInput(company.Locales, "caption"),
Name: "caption",
},
} }
} }
func (f *slideForm) FillFromDatabase(ctx context.Context, conn *database.Conn, mediaID int) error { func (f *slideForm) FillFromDatabase(ctx context.Context, conn *database.Conn, mediaID int) error {
f.MediaID = mediaID f.MediaID = mediaID
var caption database.RecordArray
row := conn.QueryRow(ctx, ` row := conn.QueryRow(ctx, `
select caption select carousel.caption
, carousel.media_id::text , carousel.media_id::text
, array_agg((lang_tag, i18n.caption))
from campsite_type_carousel as carousel from campsite_type_carousel as carousel
left join campsite_type_carousel_i18n as i18n using (campsite_type_id, media_id)
join campsite_type using (campsite_type_id) join campsite_type using (campsite_type_id)
where campsite_type.slug = $1 where campsite_type.slug = $1
and carousel.media_id = $2 and carousel.media_id = $2
`, f.TypeSlug, mediaID) group by carousel.caption
return row.Scan(&f.Caption.Val, &f.Media.Val) , carousel.media_id::text
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, f.TypeSlug, mediaID)
if err := row.Scan(&f.Caption[f.DefaultLang].Val, &f.Media.Val, &caption); err != nil {
return err
}
if err := f.Caption.FillArray(caption); err != nil {
return err
}
return nil
} }
func (f *slideForm) process(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, act func(ctx context.Context)) { func (f *slideForm) process(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, act func(ctx context.Context, tx *database.Tx) error) {
if err := f.Parse(r); err != nil { if err := f.Parse(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@ -279,7 +269,17 @@ func (f *slideForm) process(w http.ResponseWriter, r *http.Request, user *auth.U
f.MustRender(w, r, user, company) f.MustRender(w, r, user, company)
return return
} }
act(r.Context()) tx := conn.MustBegin(r.Context())
if err := act(r.Context(), tx); err == nil {
if err := tx.Commit(r.Context()); err != nil {
panic(err)
}
} else {
if err := tx.Rollback(r.Context()); err != nil {
panic(err)
}
panic(err)
}
httplib.Redirect(w, r, "/admin/campsites/types/"+f.TypeSlug+"/slides", http.StatusSeeOther) httplib.Redirect(w, r, "/admin/campsites/types/"+f.TypeSlug+"/slides", http.StatusSeeOther)
} }

View File

@ -38,7 +38,7 @@ func (h *AdminHandler) featuresHandler(user *auth.User, company *auth.Company, c
case "new": case "new":
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
f := newFeatureForm(r.Context(), conn, typeSlug) f := newFeatureForm(r.Context(), company, conn, typeSlug)
f.MustRender(w, r, user, company) f.MustRender(w, r, user, company)
default: default:
httplib.MethodNotAllowed(w, r, http.MethodGet) httplib.MethodNotAllowed(w, r, http.MethodGet)
@ -56,7 +56,7 @@ func (h *AdminHandler) featuresHandler(user *auth.User, company *auth.Company, c
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
f := newFeatureForm(r.Context(), conn, typeSlug) f := newFeatureForm(r.Context(), company, conn, typeSlug)
if err := f.FillFromDatabase(r.Context(), conn, id); err != nil { if err := f.FillFromDatabase(r.Context(), conn, id); err != nil {
if database.ErrorIsNotFound(err) { if database.ErrorIsNotFound(err) {
http.NotFound(w, r) http.NotFound(w, r)
@ -85,23 +85,7 @@ func (h *AdminHandler) featureHandler(user *auth.User, company *auth.Company, co
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut) httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
} }
default: default:
loc, ok := h.locales.Get(head)
if !ok {
http.NotFound(w, r) http.NotFound(w, r)
return
}
l10n := newFeatureL10nForm(f, loc)
if err := l10n.FillFromDatabase(r.Context(), conn); err != nil {
panic(err)
}
switch r.Method {
case http.MethodGet:
l10n.MustRender(w, r, user, company)
case http.MethodPut:
editFeatureL10n(w, r, user, company, conn, l10n)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
}
} }
}) })
} }
@ -124,20 +108,11 @@ func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug st
, '/admin/campsites/types/' || campsite_type.slug || '/features/' || campsite_type_feature_id , '/admin/campsites/types/' || campsite_type.slug || '/features/' || campsite_type_feature_id
, feature.icon_name , feature.icon_name
, feature.name , feature.name
, array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_feature_i18n as i18n where i18n.campsite_type_feature_id = feature.campsite_type_feature_id and i18n.lang_tag = language.lang_tag)) order by endonym)
from campsite_type_feature as feature from campsite_type_feature as feature
join campsite_type using (campsite_type_id) join campsite_type using (campsite_type_id)
join company using (company_id) where campsite_type.slug = $1
, language
where lang_tag <> default_lang_tag
and language.selectable
and campsite_type.slug = $1
group by campsite_type_feature_id
, campsite_type.slug
, feature.name
, feature.position
order by feature.position, feature.name order by feature.position, feature.name
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, typeSlug) `, typeSlug)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -146,17 +121,9 @@ func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug st
var features []*featureEntry var features []*featureEntry
for rows.Next() { for rows.Next() {
feature := &featureEntry{} feature := &featureEntry{}
var translations database.RecordArray if err = rows.Scan(&feature.ID, &feature.URL, &feature.Icon, &feature.Name); err != nil {
if err = rows.Scan(&feature.ID, &feature.URL, &feature.Icon, &feature.Name, &translations); err != nil {
return nil, err return nil, err
} }
for _, el := range translations.Elements {
feature.Translations = append(feature.Translations, &locale.Translation{
URL: feature.URL + "/" + el.Fields[0].Get().(string),
Endonym: el.Fields[1].Get().(string),
Missing: el.Fields[2].Get().(bool),
})
}
features = append(features, feature) features = append(features, feature)
} }
@ -168,7 +135,6 @@ type featureEntry struct {
URL string URL string
Icon string Icon string
Name string Name string
Translations []*locale.Translation
} }
type featureIndex struct { type featureIndex struct {
@ -181,19 +147,40 @@ func (page *featureIndex) MustRender(w http.ResponseWriter, r *http.Request, use
} }
func addFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) { func addFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) {
f := newFeatureForm(r.Context(), conn, typeSlug) f := newFeatureForm(r.Context(), company, conn, typeSlug)
processFeatureForm(w, r, user, company, f, func(ctx context.Context) (int, error) { processFeatureForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
return conn.AddCampsiteTypeFeature(ctx, typeSlug, f.Icon.String(), f.Name.Val) var err error
f.ID, err = tx.AddCampsiteTypeFeature(ctx, typeSlug, f.Icon.String(), f.Name[f.DefaultLang].Val)
if err != nil {
return err
}
return translateFeatures(ctx, tx, company, f)
}) })
} }
func translateFeatures(ctx context.Context, tx *database.Tx, company *auth.Company, f *featureForm) error {
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateCampsiteTypeFeature(ctx, f.ID, lang, f.Name[l].Val); err != nil {
return err
}
}
return nil
}
func editFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *featureForm) { func editFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *featureForm) {
processFeatureForm(w, r, user, company, f, func(ctx context.Context) (int, error) { processFeatureForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
return conn.EditCampsiteTypeFeature(ctx, f.ID, f.Icon.String(), f.Name.Val) if _, err := tx.EditCampsiteTypeFeature(ctx, f.ID, f.Icon.String(), f.Name[f.DefaultLang].Val); err != nil {
return err
}
return translateFeatures(ctx, tx, company, f)
}) })
} }
func processFeatureForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, f *featureForm, act func(ctx context.Context) (int, error)) { func processFeatureForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *featureForm, act func(ctx context.Context, tx *database.Tx) error) {
if ok, err := form.Handle(f, w, r, user); err != nil { if ok, err := form.Handle(f, w, r, user); err != nil {
return return
} else if !ok { } else if !ok {
@ -201,41 +188,60 @@ func processFeatureForm(w http.ResponseWriter, r *http.Request, user *auth.User,
return return
} }
if _, err := act(r.Context()); err != nil { tx := conn.MustBegin(r.Context())
if err := act(r.Context(), tx); err == nil {
if err := tx.Commit(r.Context()); err != nil {
panic(err)
}
} else {
if err := tx.Rollback(r.Context()); err != nil {
panic(err)
}
panic(err) panic(err)
} }
httplib.Redirect(w, r, "/admin/campsites/types/"+f.TypeSlug+"/features", http.StatusSeeOther) httplib.Redirect(w, r, "/admin/campsites/types/"+f.TypeSlug+"/features", http.StatusSeeOther)
} }
type featureForm struct { type featureForm struct {
DefaultLang string
ID int ID int
TypeSlug string TypeSlug string
Icon *form.Select Icon *form.Select
Name *form.Input Name form.I18nInput
} }
func newFeatureForm(ctx context.Context, conn *database.Conn, typeSlug string) *featureForm { func newFeatureForm(ctx context.Context, company *auth.Company, conn *database.Conn, typeSlug string) *featureForm {
return &featureForm{ return &featureForm{
DefaultLang: company.DefaultLanguage.String(),
TypeSlug: typeSlug, TypeSlug: typeSlug,
Icon: &form.Select{ Icon: &form.Select{
Name: "icon", Name: "icon",
Options: form.MustGetOptions(ctx, conn, "select icon_name, icon_name from icon order by 1"), Options: form.MustGetOptions(ctx, conn, "select icon_name, icon_name from icon order by 1"),
}, },
Name: &form.Input{ Name: form.NewI18nInput(company.Locales, "name"),
Name: "name",
},
} }
} }
func (f *featureForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error { func (f *featureForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error {
f.ID = id f.ID = id
var name database.RecordArray
row := conn.QueryRow(ctx, ` row := conn.QueryRow(ctx, `
select array[icon_name] select array[icon_name]
, name , feature.name
from campsite_type_feature , array_agg((lang_tag, i18n.name))
from campsite_type_feature as feature
left join campsite_type_feature_i18n as i18n using (campsite_type_feature_id)
where campsite_type_feature_id = $1 where campsite_type_feature_id = $1
`, id) group by icon_name
return row.Scan(&f.Icon.Selected, &f.Name.Val) , feature.name
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, id)
if err := row.Scan(&f.Icon.Selected, &f.Name[f.DefaultLang].Val, &name); err != nil {
return err
}
if err := f.Name.FillArray(name); err != nil {
return err
}
return nil
} }
func (f *featureForm) Parse(r *http.Request) error { func (f *featureForm) Parse(r *http.Request) error {
@ -250,8 +256,8 @@ func (f *featureForm) Parse(r *http.Request) error {
func (f *featureForm) Valid(l *locale.Locale) bool { func (f *featureForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l) v := form.NewValidator(l)
v.CheckSelectedOptions(f.Icon, l.GettextNoop("Selected icon is not valid.")) v.CheckSelectedOptions(f.Icon, l.GettextNoop("Selected icon is not valid."))
if v.CheckRequired(f.Name, l.GettextNoop("Name can not be empty.")) { if v.CheckRequired(f.Name[f.DefaultLang], l.GettextNoop("Name can not be empty.")) {
v.CheckMinLength(f.Name, 1, l.GettextNoop("Name must have at least one letter.")) v.CheckMinLength(f.Name[f.DefaultLang], 1, l.GettextNoop("Name must have at least one letter."))
} }
return v.AllOK return v.AllOK
} }

View File

@ -1,270 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
* SPDX-License-Identifier: AGPL-3.0-only
*/
package types
import (
"context"
"net/http"
"dev.tandem.ws/tandem/camper/pkg/auth"
"dev.tandem.ws/tandem/camper/pkg/database"
"dev.tandem.ws/tandem/camper/pkg/form"
httplib "dev.tandem.ws/tandem/camper/pkg/http"
"dev.tandem.ws/tandem/camper/pkg/locale"
"dev.tandem.ws/tandem/camper/pkg/template"
)
type typeL10nForm struct {
Locale *locale.Locale
Slug string
Name *form.L10nInput
Spiel *form.L10nInput
Info *form.L10nInput
Facilities *form.L10nInput
Description *form.L10nInput
}
func newTypeL10nForm(f *typeForm, loc *locale.Locale) *typeL10nForm {
return &typeL10nForm{
Locale: loc,
Slug: f.Slug,
Name: f.Name.L10nInput(),
Spiel: f.Spiel.L10nInput(),
Info: f.Info.L10nInput(),
Facilities: f.Facilities.L10nInput(),
Description: f.Description.L10nInput(),
}
}
func (l10n *typeL10nForm) FillFromDatabase(ctx context.Context, conn *database.Conn) error {
row := conn.QueryRow(ctx, `
select coalesce(i18n.name, '') as l10n_name
, coalesce(i18n.spiel, '') as l10n_spiel
, coalesce(i18n.info, '') as l10n_info
, coalesce(i18n.facilities, '') as l10n_facilities
, coalesce(i18n.description, '') as l10n_description
from campsite_type
left join campsite_type_i18n as i18n on campsite_type.campsite_type_id = i18n.campsite_type_id and i18n.lang_tag = $1
where slug = $2
`, l10n.Locale.Language, l10n.Slug)
return row.Scan(&l10n.Name.Val, &l10n.Spiel.Val, &l10n.Info.Val, &l10n.Facilities.Val, &l10n.Description.Val)
}
func (l10n *typeL10nForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "campsite/type/l10n.gohtml", l10n)
}
func editTypeL10n(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, l10n *typeL10nForm) {
if ok, err := form.Handle(l10n, w, r, user); err != nil {
return
} else if !ok {
l10n.MustRender(w, r, user, company)
return
}
if err := conn.TranslateCampsiteType(r.Context(), l10n.Slug, l10n.Locale.Language, l10n.Name.Val, l10n.Spiel.Val, l10n.Info.Val, l10n.Facilities.Val, l10n.Description.Val); err != nil {
panic(err)
}
httplib.Redirect(w, r, "/admin/campsites/types", http.StatusSeeOther)
}
func (l10n *typeL10nForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
l10n.Name.FillValue(r)
l10n.Spiel.FillValue(r)
l10n.Info.FillValue(r)
l10n.Facilities.FillValue(r)
l10n.Description.FillValue(r)
return nil
}
func (l10n *typeL10nForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l)
v.CheckRequired(&l10n.Name.Input, l.GettextNoop("Name can not be empty."))
return v.AllOK
}
type optionL10nForm struct {
Locale *locale.Locale
TypeSlug string
ID int
Name *form.L10nInput
}
func newOptionL10nForm(f *optionForm, loc *locale.Locale) *optionL10nForm {
return &optionL10nForm{
Locale: loc,
TypeSlug: f.TypeSlug,
ID: f.ID,
Name: f.Name.L10nInput(),
}
}
func (l10n *optionL10nForm) FillFromDatabase(ctx context.Context, conn *database.Conn) error {
row := conn.QueryRow(ctx, `
select coalesce(i18n.name, '') as l10n_name
from campsite_type_option
left join campsite_type_option_i18n as i18n on campsite_type_option.campsite_type_option_id = i18n.campsite_type_option_id and i18n.lang_tag = $1
where campsite_type_option.campsite_type_option_id = $2
`, l10n.Locale.Language, l10n.ID)
return row.Scan(&l10n.Name.Val)
}
func (l10n *optionL10nForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "campsite/option/l10n.gohtml", l10n)
}
func editOptionL10n(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, l10n *optionL10nForm) {
if ok, err := form.Handle(l10n, w, r, user); err != nil {
return
} else if !ok {
l10n.MustRender(w, r, user, company)
return
}
if err := conn.TranslateCampsiteTypeOption(r.Context(), l10n.ID, l10n.Locale.Language, l10n.Name.Val); err != nil {
panic(err)
}
httplib.Redirect(w, r, "/admin/campsites/types/"+l10n.TypeSlug+"/options", http.StatusSeeOther)
}
func (l10n *optionL10nForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
l10n.Name.FillValue(r)
return nil
}
func (l10n *optionL10nForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l)
v.CheckRequired(&l10n.Name.Input, l.GettextNoop("Name can not be empty."))
return v.AllOK
}
type slideL10nForm struct {
Locale *locale.Locale
TypeSlug string
MediaID int
Caption *form.L10nInput
}
func newSlideL10nForm(f *slideForm, loc *locale.Locale) *slideL10nForm {
return &slideL10nForm{
Locale: loc,
TypeSlug: f.TypeSlug,
MediaID: f.MediaID,
Caption: f.Caption.L10nInput(),
}
}
func (l10n *slideL10nForm) FillFromDatabase(ctx context.Context, conn *database.Conn) error {
row := conn.QueryRow(ctx, `
select coalesce(i18n.caption, '') as l10n_caption
from campsite_type_carousel as carousel
join campsite_type using (campsite_type_id)
left join campsite_type_carousel_i18n as i18n
on carousel.campsite_type_id = i18n.campsite_type_id
and carousel.media_id = i18n.media_id
and i18n.lang_tag = $1
where campsite_type.slug = $2 and carousel.media_id = $3
`, l10n.Locale.Language, l10n.TypeSlug, l10n.MediaID)
return row.Scan(&l10n.Caption.Val)
}
func (l10n *slideL10nForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "campsite/carousel/l10n.gohtml", l10n)
}
func editSlideL10n(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, l10n *slideL10nForm) {
if err := l10n.Parse(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := user.VerifyCSRFToken(r); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if !l10n.Valid(user.Locale) {
if !httplib.IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity)
}
l10n.MustRender(w, r, user, company)
return
}
conn.MustExec(r.Context(), "select translate_campsite_type_carousel_slide($1, $2, $3, $4)", l10n.TypeSlug, l10n.MediaID, l10n.Locale.Language, l10n.Caption)
httplib.Redirect(w, r, "/admin/campsites/types/"+l10n.TypeSlug+"/slides", http.StatusSeeOther)
}
func (l10n *slideL10nForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
l10n.Caption.FillValue(r)
return nil
}
func (l10n *slideL10nForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l)
return v.AllOK
}
type featureL10nForm struct {
Locale *locale.Locale
TypeSlug string
ID int
Name *form.L10nInput
}
func newFeatureL10nForm(f *featureForm, loc *locale.Locale) *featureL10nForm {
return &featureL10nForm{
Locale: loc,
TypeSlug: f.TypeSlug,
ID: f.ID,
Name: f.Name.L10nInput(),
}
}
func (l10n *featureL10nForm) FillFromDatabase(ctx context.Context, conn *database.Conn) error {
row := conn.QueryRow(ctx, `
select coalesce(i18n.name, '') as l10n_name
from campsite_type_feature
left join campsite_type_feature_i18n as i18n on campsite_type_feature.campsite_type_feature_id = i18n.campsite_type_feature_id and i18n.lang_tag = $1
where campsite_type_feature.campsite_type_feature_id = $2
`, l10n.Locale.Language, l10n.ID)
return row.Scan(&l10n.Name.Val)
}
func (l10n *featureL10nForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "campsite/feature/l10n.gohtml", l10n)
}
func editFeatureL10n(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, l10n *featureL10nForm) {
if ok, err := form.Handle(l10n, w, r, user); err != nil {
return
} else if !ok {
l10n.MustRender(w, r, user, company)
return
}
if err := conn.TranslateCampsiteTypeFeature(r.Context(), l10n.ID, l10n.Locale.Language, l10n.Name.Val); err != nil {
panic(err)
}
httplib.Redirect(w, r, "/admin/campsites/types/"+l10n.TypeSlug+"/features", http.StatusSeeOther)
}
func (l10n *featureL10nForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
l10n.Name.FillValue(r)
return nil
}
func (l10n *featureL10nForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l)
v.CheckRequired(&l10n.Name.Input, l.GettextNoop("Name can not be empty."))
return v.AllOK
}

View File

@ -92,23 +92,7 @@ func (h *AdminHandler) optionHandler(user *auth.User, company *auth.Company, con
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut) httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
} }
default: default:
loc, ok := h.locales.Get(head)
if !ok {
http.NotFound(w, r) http.NotFound(w, r)
return
}
l10n := newOptionL10nForm(f, loc)
if err := l10n.FillFromDatabase(r.Context(), conn); err != nil {
panic(err)
}
switch r.Method {
case http.MethodGet:
l10n.MustRender(w, r, user, company)
case http.MethodPut:
editOptionL10n(w, r, user, company, conn, l10n)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
}
} }
}) })
} }
@ -130,20 +114,11 @@ func collectOptionEntries(ctx context.Context, conn *database.Conn, typeSlug str
select campsite_type_option_id select campsite_type_option_id
, '/admin/campsites/types/' || campsite_type.slug || '/options/' || campsite_type_option_id , '/admin/campsites/types/' || campsite_type.slug || '/options/' || campsite_type_option_id
, option.name , option.name
, array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_option_i18n as i18n where i18n.campsite_type_option_id = option.campsite_type_option_id and i18n.lang_tag = language.lang_tag)) order by endonym)
from campsite_type_option as option from campsite_type_option as option
join campsite_type using (campsite_type_id) join campsite_type using (campsite_type_id)
join company using (company_id) where campsite_type.slug = $1
, language
where lang_tag <> default_lang_tag
and language.selectable
and campsite_type.slug = $1
group by campsite_type_option_id
, campsite_type.slug
, option.position
, option.name
order by option.position, option.name order by option.position, option.name
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, typeSlug) `, typeSlug)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -152,17 +127,9 @@ func collectOptionEntries(ctx context.Context, conn *database.Conn, typeSlug str
var options []*optionEntry var options []*optionEntry
for rows.Next() { for rows.Next() {
option := &optionEntry{} option := &optionEntry{}
var translations database.RecordArray if err = rows.Scan(&option.ID, &option.URL, &option.Name); err != nil {
if err = rows.Scan(&option.ID, &option.URL, &option.Name, &translations); err != nil {
return nil, err return nil, err
} }
for _, el := range translations.Elements {
option.Translations = append(option.Translations, &locale.Translation{
URL: option.URL + "/" + el.Fields[0].Get().(string),
Endonym: el.Fields[1].Get().(string),
Missing: el.Fields[2].Get().(bool),
})
}
options = append(options, option) options = append(options, option)
} }
@ -173,7 +140,6 @@ type optionEntry struct {
ID int ID int
URL string URL string
Name string Name string
Translations []*locale.Translation
} }
type optionIndex struct { type optionIndex struct {
@ -191,17 +157,37 @@ func addOption(w http.ResponseWriter, r *http.Request, user *auth.User, company
panic(err) panic(err)
} }
processOptionForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error { processOptionForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
id, err := tx.AddCampsiteTypeOption(ctx, typeSlug, f.Name.Val, f.Min.Int(), f.Max.Int()) var err error
f.ID, err = tx.AddCampsiteTypeOption(ctx, typeSlug, f.Name[f.DefaultLang].Val, f.Min.Int(), f.Max.Int())
if err != nil { if err != nil {
return err return err
} }
return setOptionPrices(ctx, tx, id, f.Prices) if err := translateOptions(ctx, tx, company, f); err != nil {
return err
}
return setOptionPrices(ctx, tx, f.ID, f.Prices)
}) })
} }
func translateOptions(ctx context.Context, tx *database.Tx, company *auth.Company, f *optionForm) error {
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateCampsiteTypeOption(ctx, f.ID, lang, f.Name[l].Val); err != nil {
return err
}
}
return nil
}
func editOption(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *optionForm) { func editOption(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *optionForm) {
processOptionForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error { processOptionForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
if _, err := tx.EditCampsiteTypeOption(ctx, f.ID, f.Name.Val, f.Min.Int(), f.Max.Int()); err != nil { if _, err := tx.EditCampsiteTypeOption(ctx, f.ID, f.Name[f.DefaultLang].Val, f.Min.Int(), f.Max.Int()); err != nil {
return err
}
if err := translateOptions(ctx, tx, company, f); err != nil {
return err return err
} }
return setOptionPrices(ctx, tx, f.ID, f.Prices) return setOptionPrices(ctx, tx, f.ID, f.Prices)
@ -240,9 +226,10 @@ func setOptionPrices(ctx context.Context, tx *database.Tx, id int, prices map[in
} }
type optionForm struct { type optionForm struct {
DefaultLang string
ID int ID int
TypeSlug string TypeSlug string
Name *form.Input Name form.I18nInput
Min *form.Input Min *form.Input
Max *form.Input Max *form.Input
Prices map[int]*optionPriceForm Prices map[int]*optionPriceForm
@ -255,10 +242,9 @@ type optionPriceForm struct {
func newOptionForm(ctx context.Context, company *auth.Company, conn *database.Conn, typeSlug string) (*optionForm, error) { func newOptionForm(ctx context.Context, company *auth.Company, conn *database.Conn, typeSlug string) (*optionForm, error) {
f := &optionForm{ f := &optionForm{
DefaultLang: company.DefaultLanguage.String(),
TypeSlug: typeSlug, TypeSlug: typeSlug,
Name: &form.Input{ Name: form.NewI18nInput(company.Locales, "name"),
Name: "name",
},
Min: &form.Input{ Min: &form.Input{
Name: "min", Name: "min",
Val: "0", Val: "0",
@ -296,14 +282,22 @@ func newOptionForm(ctx context.Context, company *auth.Company, conn *database.Co
func (f *optionForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error { func (f *optionForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error {
f.ID = id f.ID = id
var name database.RecordArray
row := conn.QueryRow(ctx, ` row := conn.QueryRow(ctx, `
select name select option.name
, lower(range)::text , lower(range)::text
, (upper(range) - 1)::text , (upper(range) - 1)::text
from campsite_type_option , array_agg((lang_tag, i18n.name))
from campsite_type_option as option
left join campsite_type_option_i18n as i18n using (campsite_type_option_id)
where campsite_type_option_id = $1 where campsite_type_option_id = $1
`, id) group by option.name
if err := row.Scan(&f.Name.Val, &f.Min.Val, &f.Max.Val); err != nil { , range
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, id)
if err := row.Scan(&f.Name[f.DefaultLang].Val, &f.Min.Val, &f.Max.Val, &name); err != nil {
return err
}
if err := f.Name.FillArray(name); err != nil {
return err return err
} }
@ -347,8 +341,8 @@ func (f *optionForm) Parse(r *http.Request) error {
func (f *optionForm) Valid(l *locale.Locale) bool { func (f *optionForm) Valid(l *locale.Locale) bool {
v := form.NewValidator(l) v := form.NewValidator(l)
if v.CheckRequired(f.Name, l.GettextNoop("Name can not be empty.")) { if v.CheckRequired(f.Name[f.DefaultLang], l.GettextNoop("Name can not be empty.")) {
v.CheckMinLength(f.Name, 1, l.GettextNoop("Name must have at least one letter.")) v.CheckMinLength(f.Name[f.DefaultLang], 1, l.GettextNoop("Name must have at least one letter."))
} }
minValidInt := false minValidInt := false
if v.CheckRequired(f.Min, l.GettextNoop("Minimum can not be empty.")) { if v.CheckRequired(f.Min, l.GettextNoop("Minimum can not be empty.")) {

View File

@ -24,8 +24,8 @@ func (c *Conn) OrderCampsiteTypes(ctx context.Context, slugs []string) error {
return err return err
} }
func (c *Conn) TranslateCampsiteType(ctx context.Context, slug string, langTag language.Tag, name string, spiel string, info string, facilities string, description string) error { func (tx *Tx) TranslateCampsiteType(ctx context.Context, slug string, langTag language.Tag, name string, spiel string, info string, facilities string, description string) error {
_, err := c.Exec(ctx, "select translate_campsite_type($1, $2, $3, $4, $5, $6, $7)", slug, langTag, name, spiel, info, facilities, description) _, err := tx.Exec(ctx, "select translate_campsite_type($1, $2, $3, $4, $5, $6, $7)", slug, langTag, name, spiel, info, facilities, description)
return err return err
} }
func (tx *Tx) SetCampsiteTypeCost(ctx context.Context, slug string, seasonID int, minNights int, costPerNight string) error { func (tx *Tx) SetCampsiteTypeCost(ctx context.Context, slug string, seasonID int, minNights int, costPerNight string) error {
@ -46,8 +46,8 @@ func (tx *Tx) SetCampsiteTypeOptionCost(ctx context.Context, id int, seasonID in
return err return err
} }
func (c *Conn) TranslateCampsiteTypeOption(ctx context.Context, id int, langTag language.Tag, name string) error { func (tx *Tx) TranslateCampsiteTypeOption(ctx context.Context, id int, langTag language.Tag, name string) error {
_, err := c.Exec(ctx, "select translate_campsite_type_option($1, $2, $3)", id, langTag, name) _, err := tx.Exec(ctx, "select translate_campsite_type_option($1, $2, $3)", id, langTag, name)
return err return err
} }
@ -61,16 +61,16 @@ func (c *Conn) OrderCampsiteTypeCarousel(ctx context.Context, typeSlug string, m
return err return err
} }
func (c *Conn) AddCampsiteTypeFeature(ctx context.Context, typeSlug string, iconName string, name string) (int, error) { func (tx *Tx) AddCampsiteTypeFeature(ctx context.Context, typeSlug string, iconName string, name string) (int, error) {
return c.GetInt(ctx, "select add_campsite_type_feature($1, $2, $3)", typeSlug, iconName, name) return tx.GetInt(ctx, "select add_campsite_type_feature($1, $2, $3)", typeSlug, iconName, name)
} }
func (c *Conn) EditCampsiteTypeFeature(ctx context.Context, id int, iconName string, name string) (int, error) { func (tx *Tx) EditCampsiteTypeFeature(ctx context.Context, id int, iconName string, name string) (int, error) {
return c.GetInt(ctx, "select edit_campsite_type_feature($1, $2, $3)", id, iconName, name) return tx.GetInt(ctx, "select edit_campsite_type_feature($1, $2, $3)", id, iconName, name)
} }
func (c *Conn) TranslateCampsiteTypeFeature(ctx context.Context, id int, langTag language.Tag, name string) error { func (tx *Tx) TranslateCampsiteTypeFeature(ctx context.Context, id int, langTag language.Tag, name string) error {
_, err := c.Exec(ctx, "select translate_campsite_type_feature($1, $2, $3)", id, langTag, name) _, err := tx.Exec(ctx, "select translate_campsite_type_feature($1, $2, $3)", id, langTag, name)
return err return err
} }
@ -79,6 +79,16 @@ func (c *Conn) OrderCampsiteTypeFeatures(ctx context.Context, ids []int) error {
return err return err
} }
func (tx *Tx) AddCampsiteTypeCarouselSlide(ctx context.Context, typeSlug string, mediaID int, caption string) error {
_, err := tx.Exec(ctx, "select add_campsite_type_carousel_slide($1, $2, $3)", typeSlug, mediaID, caption)
return err
}
func (tx *Tx) TranslateCampsiteTypeCarouselSlide(ctx context.Context, typeSlug string, mediaID int, langTag language.Tag, caption string) error {
_, err := tx.Exec(ctx, "select translate_campsite_type_carousel_slide($1, $2, $3, $4)", typeSlug, mediaID, langTag, caption)
return err
}
func (c *Conn) SetupRedsys(ctx context.Context, companyID int, merchantCode string, terminalNumber int, environment string, integration string, encryptKey string) error { func (c *Conn) SetupRedsys(ctx context.Context, companyID int, merchantCode string, terminalNumber int, environment string, integration string, encryptKey string) error {
var encryptKeyParam interface{} var encryptKeyParam interface{}
if encryptKey != "" { if encryptKey != "" {

221
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-10 19:33+0100\n" "POT-Creation-Date: 2024-01-10 21:49+0100\n"
"PO-Revision-Date: 2023-07-22 23:45+0200\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n" "Language-Team: Catalan <ca@dodds.net>\n"
@ -131,8 +131,8 @@ msgid "Calendar"
msgstr "Calendari" msgstr "Calendari"
#: web/templates/public/campsite/type.gohtml:73 #: web/templates/public/campsite/type.gohtml:73
#: web/templates/admin/campsite/option/form.gohtml:58 #: web/templates/admin/campsite/option/form.gohtml:63
#: web/templates/admin/campsite/type/form.gohtml:73 #: web/templates/admin/campsite/type/form.gohtml:78
msgctxt "title" msgctxt "title"
msgid "Prices" msgid "Prices"
msgstr "Preus" msgstr "Preus"
@ -419,11 +419,8 @@ msgstr "Àlies"
#: web/templates/admin/legal/form.gohtml:46 #: web/templates/admin/legal/form.gohtml:46
#: web/templates/admin/campsite/feature/form.gohtml:52 #: web/templates/admin/campsite/feature/form.gohtml:52
#: web/templates/admin/campsite/feature/l10n.gohtml:20
#: web/templates/admin/campsite/option/form.gohtml:34 #: web/templates/admin/campsite/option/form.gohtml:34
#: web/templates/admin/campsite/option/l10n.gohtml:20
#: web/templates/admin/campsite/type/form.gohtml:46 #: web/templates/admin/campsite/type/form.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:20
#: web/templates/admin/season/form.gohtml:46 #: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/season/l10n.gohtml:20 #: web/templates/admin/season/l10n.gohtml:20
#: web/templates/admin/services/form.gohtml:52 #: web/templates/admin/services/form.gohtml:52
@ -440,11 +437,11 @@ msgstr "Contingut"
#: web/templates/admin/legal/form.gohtml:84 #: web/templates/admin/legal/form.gohtml:84
#: web/templates/admin/carousel/form.gohtml:47 #: web/templates/admin/carousel/form.gohtml:47
#: web/templates/admin/campsite/feature/form.gohtml:62 #: web/templates/admin/campsite/feature/form.gohtml:67
#: web/templates/admin/campsite/carousel/form.gohtml:47 #: web/templates/admin/campsite/carousel/form.gohtml:52
#: web/templates/admin/campsite/form.gohtml:70 #: web/templates/admin/campsite/form.gohtml:70
#: web/templates/admin/campsite/option/form.gohtml:78 #: web/templates/admin/campsite/option/form.gohtml:83
#: web/templates/admin/campsite/type/form.gohtml:129 #: web/templates/admin/campsite/type/form.gohtml:158
#: web/templates/admin/season/form.gohtml:64 #: web/templates/admin/season/form.gohtml:64
#: web/templates/admin/services/form.gohtml:69 #: web/templates/admin/services/form.gohtml:69
#: web/templates/admin/media/form.gohtml:35 #: web/templates/admin/media/form.gohtml:35
@ -454,11 +451,11 @@ msgstr "Actualitza"
#: web/templates/admin/legal/form.gohtml:86 #: web/templates/admin/legal/form.gohtml:86
#: web/templates/admin/carousel/form.gohtml:49 #: web/templates/admin/carousel/form.gohtml:49
#: web/templates/admin/campsite/feature/form.gohtml:64 #: web/templates/admin/campsite/feature/form.gohtml:69
#: web/templates/admin/campsite/carousel/form.gohtml:49 #: web/templates/admin/campsite/carousel/form.gohtml:54
#: web/templates/admin/campsite/form.gohtml:72 #: web/templates/admin/campsite/form.gohtml:72
#: web/templates/admin/campsite/option/form.gohtml:80 #: web/templates/admin/campsite/option/form.gohtml:85
#: web/templates/admin/campsite/type/form.gohtml:131 #: web/templates/admin/campsite/type/form.gohtml:160
#: web/templates/admin/season/form.gohtml:66 #: web/templates/admin/season/form.gohtml:66
#: web/templates/admin/services/form.gohtml:71 #: web/templates/admin/services/form.gohtml:71
msgctxt "action" msgctxt "action"
@ -505,7 +502,6 @@ msgstr "Nova diapositiva del carrusel"
#: web/templates/admin/carousel/form.gohtml:37 #: web/templates/admin/carousel/form.gohtml:37
#: web/templates/admin/carousel/l10n.gohtml:20 #: web/templates/admin/carousel/l10n.gohtml:20
#: web/templates/admin/campsite/carousel/form.gohtml:37 #: web/templates/admin/campsite/carousel/form.gohtml:37
#: web/templates/admin/campsite/carousel/l10n.gohtml:20
msgctxt "input" msgctxt "input"
msgid "Caption" msgid "Caption"
msgstr "Llegenda" msgstr "Llegenda"
@ -517,14 +513,6 @@ msgid "Translate Carousel Slide to %s"
msgstr "Traducció de la diapositiva del carrusel a %s" msgstr "Traducció de la diapositiva del carrusel a %s"
#: web/templates/admin/carousel/l10n.gohtml:21 #: web/templates/admin/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/feature/l10n.gohtml:21
#: web/templates/admin/campsite/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/option/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:33
#: web/templates/admin/campsite/type/l10n.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:59
#: web/templates/admin/campsite/type/l10n.gohtml:72
#: web/templates/admin/season/l10n.gohtml:21 #: web/templates/admin/season/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:21 #: web/templates/admin/services/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:33 #: web/templates/admin/services/l10n.gohtml:33
@ -532,14 +520,6 @@ msgid "Source:"
msgstr "Origen:" msgstr "Origen:"
#: web/templates/admin/carousel/l10n.gohtml:23 #: web/templates/admin/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/feature/l10n.gohtml:23
#: web/templates/admin/campsite/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/option/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:36
#: web/templates/admin/campsite/type/l10n.gohtml:49
#: web/templates/admin/campsite/type/l10n.gohtml:62
#: web/templates/admin/campsite/type/l10n.gohtml:75
#: web/templates/admin/season/l10n.gohtml:23 #: web/templates/admin/season/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:23 #: web/templates/admin/services/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:36 #: web/templates/admin/services/l10n.gohtml:36
@ -548,10 +528,6 @@ msgid "Translation:"
msgstr "Traducció:" msgstr "Traducció:"
#: web/templates/admin/carousel/l10n.gohtml:32 #: web/templates/admin/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/feature/l10n.gohtml:32
#: web/templates/admin/campsite/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/option/l10n.gohtml:32
#: web/templates/admin/campsite/type/l10n.gohtml:84
#: web/templates/admin/season/l10n.gohtml:32 #: web/templates/admin/season/l10n.gohtml:32
#: web/templates/admin/services/l10n.gohtml:45 #: web/templates/admin/services/l10n.gohtml:45
msgctxt "action" msgctxt "action"
@ -614,28 +590,10 @@ msgctxt "action"
msgid "Add Feature" msgid "Add Feature"
msgstr "Afegeix característica" msgstr "Afegeix característica"
#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/feature/index.gohtml:43
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/campsite/option/index.gohtml:26
#: web/templates/admin/campsite/type/index.gohtml:26
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traduccions"
#: web/templates/admin/campsite/feature/index.gohtml:53
msgid "No campsite type features added yet." msgid "No campsite type features added yet."
msgstr "No sha afegit cap característica al tipus dallotjament encara." msgstr "No sha afegit cap característica al tipus dallotjament encara."
#: web/templates/admin/campsite/feature/l10n.gohtml:7
#: web/templates/admin/campsite/feature/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Feature to %s"
msgstr "Traducció de la característica del tipus dallotjament a %s"
#: web/templates/admin/campsite/carousel/form.gohtml:8 #: web/templates/admin/campsite/carousel/form.gohtml:8
#: web/templates/admin/campsite/carousel/form.gohtml:25 #: web/templates/admin/campsite/carousel/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -675,7 +633,7 @@ msgctxt "header"
msgid "Caption" msgid "Caption"
msgstr "Llegenda" msgstr "Llegenda"
#: web/templates/admin/campsite/carousel/index.gohtml:28 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/services/index.gohtml:74 #: web/templates/admin/services/index.gohtml:74
#: web/templates/admin/home/index.gohtml:28 #: web/templates/admin/home/index.gohtml:28
@ -683,13 +641,13 @@ msgctxt "header"
msgid "Actions" msgid "Actions"
msgstr "Accions" msgstr "Accions"
#: web/templates/admin/campsite/carousel/index.gohtml:32 #: web/templates/admin/campsite/carousel/index.gohtml:31
#: web/templates/admin/services/index.gohtml:32 #: web/templates/admin/services/index.gohtml:32
#: web/templates/admin/home/index.gohtml:32 #: web/templates/admin/home/index.gohtml:32
msgid "Are you sure you wish to delete this slide?" msgid "Are you sure you wish to delete this slide?"
msgstr "Esteu segur de voler esborrar aquesta diapositiva?" msgstr "Esteu segur de voler esborrar aquesta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:55 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:54 #: web/templates/admin/services/index.gohtml:54
#: web/templates/admin/services/index.gohtml:93 #: web/templates/admin/services/index.gohtml:93
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
@ -697,18 +655,12 @@ msgctxt "action"
msgid "Delete" msgid "Delete"
msgstr "Esborra" msgstr "Esborra"
#: web/templates/admin/campsite/carousel/index.gohtml:64 #: web/templates/admin/campsite/carousel/index.gohtml:54
#: web/templates/admin/services/index.gohtml:63 #: web/templates/admin/services/index.gohtml:63
#: web/templates/admin/home/index.gohtml:63 #: web/templates/admin/home/index.gohtml:63
msgid "No slides added yet." msgid "No slides added yet."
msgstr "No sha afegit cap diapositiva encara." msgstr "No sha afegit cap diapositiva encara."
#: web/templates/admin/campsite/carousel/l10n.gohtml:7
#: web/templates/admin/campsite/carousel/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Carousel Slide to %s"
msgstr "Traducció de la diapositiva del carrusel del tipus dallotjament a %s"
#: web/templates/admin/campsite/form.gohtml:8 #: web/templates/admin/campsite/form.gohtml:8
#: web/templates/admin/campsite/form.gohtml:25 #: web/templates/admin/campsite/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -753,18 +705,18 @@ msgctxt "title"
msgid "New Campsite Type Option" msgid "New Campsite Type Option"
msgstr "Nova opció del tipus dallotjament" msgstr "Nova opció del tipus dallotjament"
#: web/templates/admin/campsite/option/form.gohtml:42 #: web/templates/admin/campsite/option/form.gohtml:47
msgctxt "input" msgctxt "input"
msgid "Minimum" msgid "Minimum"
msgstr "Mínim" msgstr "Mínim"
#: web/templates/admin/campsite/option/form.gohtml:50 #: web/templates/admin/campsite/option/form.gohtml:55
msgctxt "input" msgctxt "input"
msgid "Maximum" msgid "Maximum"
msgstr "Màxim" msgstr "Màxim"
#: web/templates/admin/campsite/option/form.gohtml:64 #: web/templates/admin/campsite/option/form.gohtml:69
#: web/templates/admin/campsite/type/form.gohtml:79 #: web/templates/admin/campsite/type/form.gohtml:84
msgctxt "input" msgctxt "input"
msgid "Price per night" msgid "Price per night"
msgstr "Preu per nit" msgstr "Preu per nit"
@ -780,16 +732,10 @@ msgctxt "action"
msgid "Add Option" msgid "Add Option"
msgstr "Afegeix opció" msgstr "Afegeix opció"
#: web/templates/admin/campsite/option/index.gohtml:52 #: web/templates/admin/campsite/option/index.gohtml:42
msgid "No campsite type options added yet." msgid "No campsite type options added yet."
msgstr "No sha afegit cap opció al tipus dallotjament encara." msgstr "No sha afegit cap opció al tipus dallotjament encara."
#: web/templates/admin/campsite/option/l10n.gohtml:7
#: web/templates/admin/campsite/option/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Option to %s"
msgstr "Traducció de la opció del tipus dallotjament a %s"
#: web/templates/admin/campsite/index.gohtml:11 #: web/templates/admin/campsite/index.gohtml:11
msgctxt "action" msgctxt "action"
msgid "Add Campsite" msgid "Add Campsite"
@ -806,13 +752,13 @@ msgid "Type"
msgstr "Tipus" msgstr "Tipus"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "Yes" msgid "Yes"
msgstr "Sí" msgstr "Sí"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "No" msgid "No"
msgstr "No" msgstr "No"
@ -834,46 +780,42 @@ msgid "New Campsite Type"
msgstr "Nou tipus dallotjament" msgstr "Nou tipus dallotjament"
#: web/templates/admin/campsite/type/form.gohtml:37 #: web/templates/admin/campsite/type/form.gohtml:37
#: web/templates/admin/campsite/type/index.gohtml:30 #: web/templates/admin/campsite/type/index.gohtml:29
msgctxt "campsite type" msgctxt "campsite type"
msgid "Active" msgid "Active"
msgstr "Actiu" msgstr "Actiu"
#: web/templates/admin/campsite/type/form.gohtml:57 #: web/templates/admin/campsite/type/form.gohtml:62
msgctxt "input" msgctxt "input"
msgid "Maximum number of campers" msgid "Maximum number of campers"
msgstr "Número màxim de persones" msgstr "Número màxim de persones"
#: web/templates/admin/campsite/type/form.gohtml:67 #: web/templates/admin/campsite/type/form.gohtml:72
msgctxt "input" msgctxt "input"
msgid "Dogs allowed" msgid "Dogs allowed"
msgstr "Es permeten gossos" msgstr "Es permeten gossos"
#: web/templates/admin/campsite/type/form.gohtml:87 #: web/templates/admin/campsite/type/form.gohtml:92
msgctxt "input" msgctxt "input"
msgid "Minimum number of nights" msgid "Minimum number of nights"
msgstr "Número mínim de nits" msgstr "Número mínim de nits"
#: web/templates/admin/campsite/type/form.gohtml:99 #: web/templates/admin/campsite/type/form.gohtml:104
#: web/templates/admin/campsite/type/l10n.gohtml:32
msgctxt "input" msgctxt "input"
msgid "Spiel" msgid "Spiel"
msgstr "Introducció" msgstr "Introducció"
#: web/templates/admin/campsite/type/form.gohtml:106 #: web/templates/admin/campsite/type/form.gohtml:117
#: web/templates/admin/campsite/type/l10n.gohtml:45
msgctxt "input" msgctxt "input"
msgid "Info" msgid "Info"
msgstr "Informació" msgstr "Informació"
#: web/templates/admin/campsite/type/form.gohtml:113 #: web/templates/admin/campsite/type/form.gohtml:130
#: web/templates/admin/campsite/type/l10n.gohtml:58
msgctxt "input" msgctxt "input"
msgid "Facilities" msgid "Facilities"
msgstr "Equipaments" msgstr "Equipaments"
#: web/templates/admin/campsite/type/form.gohtml:120 #: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/campsite/type/l10n.gohtml:71
#: web/templates/admin/services/form.gohtml:60 #: web/templates/admin/services/form.gohtml:60
#: web/templates/admin/services/l10n.gohtml:32 #: web/templates/admin/services/l10n.gohtml:32
msgctxt "input" msgctxt "input"
@ -892,46 +834,40 @@ msgctxt "action"
msgid "Add Type" msgid "Add Type"
msgstr "Afegeix tipus" msgstr "Afegeix tipus"
#: web/templates/admin/campsite/type/index.gohtml:27 #: web/templates/admin/campsite/type/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Features" msgid "Features"
msgstr "Característiques" msgstr "Característiques"
#: web/templates/admin/campsite/type/index.gohtml:28 #: web/templates/admin/campsite/type/index.gohtml:27
msgctxt "header" msgctxt "header"
msgid "Options" msgid "Options"
msgstr "Opcions" msgstr "Opcions"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:28
msgctxt "header" msgctxt "header"
msgid "Carousel" msgid "Carousel"
msgstr "Carrusel" msgstr "Carrusel"
#: web/templates/admin/campsite/type/index.gohtml:51 #: web/templates/admin/campsite/type/index.gohtml:41
msgctxt "action" msgctxt "action"
msgid "Edit Features" msgid "Edit Features"
msgstr "Edita les característiques" msgstr "Edita les característiques"
#: web/templates/admin/campsite/type/index.gohtml:54 #: web/templates/admin/campsite/type/index.gohtml:44
msgctxt "action" msgctxt "action"
msgid "Edit Options" msgid "Edit Options"
msgstr "Edita les opcions" msgstr "Edita les opcions"
#: web/templates/admin/campsite/type/index.gohtml:57 #: web/templates/admin/campsite/type/index.gohtml:47
msgctxt "action" msgctxt "action"
msgid "Edit Carousel" msgid "Edit Carousel"
msgstr "Edita el carrusel" msgstr "Edita el carrusel"
#: web/templates/admin/campsite/type/index.gohtml:66 #: web/templates/admin/campsite/type/index.gohtml:56
msgid "No campsite types added yet." msgid "No campsite types added yet."
msgstr "No sha afegit cap tipus dallotjament encara." msgstr "No sha afegit cap tipus dallotjament encara."
#: web/templates/admin/campsite/type/l10n.gohtml:7
#: web/templates/admin/campsite/type/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type to %s"
msgstr "Traducció del tipus dallotjament a %s"
#: web/templates/admin/season/form.gohtml:8 #: web/templates/admin/season/form.gohtml:8
#: web/templates/admin/season/form.gohtml:25 #: web/templates/admin/season/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -972,6 +908,14 @@ msgctxt "header"
msgid "Color" msgid "Color"
msgstr "Color" msgstr "Color"
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traduccions"
#: web/templates/admin/season/index.gohtml:56 #: web/templates/admin/season/index.gohtml:56
msgid "No seasons added yet." msgid "No seasons added yet."
msgstr "No sha afegit cap temporada encara." msgstr "No sha afegit cap temporada encara."
@ -1278,25 +1222,24 @@ msgctxt "title"
msgid "Upload Media" msgid "Upload Media"
msgstr "Pujada de mèdia" msgstr "Pujada de mèdia"
#: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:453
#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/season/l10n.go:69 pkg/season/admin.go:405 pkg/services/l10n.go:73
#: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/services/admin.go:266
#: pkg/season/admin.go:405 pkg/services/l10n.go:73 pkg/services/admin.go:266
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc." msgstr "No podeu deixar el nom en blanc."
#: pkg/legal/admin.go:256 pkg/campsite/types/option.go:351 #: pkg/legal/admin.go:256 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:254 pkg/campsite/types/admin.go:448 #: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:454
msgid "Name must have at least one letter." msgid "Name must have at least one letter."
msgstr "El nom ha de tenir com a mínim una lletra." msgstr "El nom ha de tenir com a mínim una lletra."
#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 #: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:223
msgctxt "input" msgctxt "input"
msgid "Slide image" msgid "Slide image"
msgstr "Imatge de la diapositiva" msgstr "Imatge de la diapositiva"
#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 #: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:224
msgctxt "action" msgctxt "action"
msgid "Set slide image" msgid "Set slide image"
msgstr "Estableix la imatge de la diapositiva" msgstr "Estableix la imatge de la diapositiva"
@ -1348,85 +1291,85 @@ msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida."
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Accés prohibit" msgstr "Accés prohibit"
#: pkg/campsite/types/option.go:354 #: pkg/campsite/types/option.go:348
msgid "Minimum can not be empty." msgid "Minimum can not be empty."
msgstr "No podeu deixar el mínim en blanc." msgstr "No podeu deixar el mínim en blanc."
#: pkg/campsite/types/option.go:355 #: pkg/campsite/types/option.go:349
msgid "Minimum must be an integer number." msgid "Minimum must be an integer number."
msgstr "El valor del mínim ha de ser un número enter." msgstr "El valor del mínim ha de ser un número enter."
#: pkg/campsite/types/option.go:357 #: pkg/campsite/types/option.go:351
msgid "Minimum must be zero or greater." msgid "Minimum must be zero or greater."
msgstr "El valor del mínim ha de ser com a mínim zero." msgstr "El valor del mínim ha de ser com a mínim zero."
#: pkg/campsite/types/option.go:360 #: pkg/campsite/types/option.go:354
msgid "Maximum can not be empty." msgid "Maximum can not be empty."
msgstr "No podeu deixar el màxim en blanc." msgstr "No podeu deixar el màxim en blanc."
#: pkg/campsite/types/option.go:361 #: pkg/campsite/types/option.go:355
msgid "Maximum must be an integer number." msgid "Maximum must be an integer number."
msgstr "El valor del màxim ha de ser un número enter." msgstr "El valor del màxim ha de ser un número enter."
#: pkg/campsite/types/option.go:363 #: pkg/campsite/types/option.go:357
msgid "Maximum must be equal or greater than minimum." msgid "Maximum must be equal or greater than minimum."
msgstr "El valor del màxim ha de ser igual o superir al del mínim." msgstr "El valor del màxim ha de ser igual o superir al del mínim."
#: pkg/campsite/types/option.go:367 pkg/campsite/types/admin.go:461 #: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:467
msgid "Price per night can not be empty." msgid "Price per night can not be empty."
msgstr "No podeu deixar el preu per nit en blanc." msgstr "No podeu deixar el preu per nit en blanc."
#: pkg/campsite/types/option.go:368 pkg/campsite/types/admin.go:462 #: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:468
msgid "Price per night must be a decimal number." msgid "Price per night must be a decimal number."
msgstr "El preu per nit ha de ser un número decimal." msgstr "El preu per nit ha de ser un número decimal."
#: pkg/campsite/types/option.go:369 pkg/campsite/types/admin.go:463 #: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:469
msgid "Price per night must be zero or greater." msgid "Price per night must be zero or greater."
msgstr "El preu per nit ha de ser com a mínim zero." msgstr "El preu per nit ha de ser com a mínim zero."
#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 #: pkg/campsite/types/feature.go:258 pkg/services/admin.go:265
msgid "Selected icon is not valid." msgid "Selected icon is not valid."
msgstr "La icona escollida no és vàlida." msgstr "La icona escollida no és vàlida."
#: pkg/campsite/types/admin.go:323 #: pkg/campsite/types/admin.go:304
msgctxt "input" msgctxt "input"
msgid "Cover image" msgid "Cover image"
msgstr "Imatge de portada" msgstr "Imatge de portada"
#: pkg/campsite/types/admin.go:324 #: pkg/campsite/types/admin.go:305
msgctxt "action" msgctxt "action"
msgid "Set campsite type cover" msgid "Set campsite type cover"
msgstr "Estableix la portada del tipus dallotjament" msgstr "Estableix la portada del tipus dallotjament"
#: pkg/campsite/types/admin.go:450 #: pkg/campsite/types/admin.go:456
msgid "Cover image can not be empty." msgid "Cover image can not be empty."
msgstr "No podeu deixar la imatge de portada en blanc." msgstr "No podeu deixar la imatge de portada en blanc."
#: pkg/campsite/types/admin.go:451 #: pkg/campsite/types/admin.go:457
msgid "Cover image must be an image media type." msgid "Cover image must be an image media type."
msgstr "La imatge de portada ha de ser un mèdia de tipus imatge." msgstr "La imatge de portada ha de ser un mèdia de tipus imatge."
#: pkg/campsite/types/admin.go:455 #: pkg/campsite/types/admin.go:461
msgid "Maximum number of campers can not be empty." msgid "Maximum number of campers can not be empty."
msgstr "No podeu deixar el número màxim de persones en blanc." msgstr "No podeu deixar el número màxim de persones en blanc."
#: pkg/campsite/types/admin.go:456 #: pkg/campsite/types/admin.go:462
msgid "Maximum number of campers must be an integer number." msgid "Maximum number of campers must be an integer number."
msgstr "El número màxim de persones ha de ser enter." msgstr "El número màxim de persones ha de ser enter."
#: pkg/campsite/types/admin.go:457 #: pkg/campsite/types/admin.go:463
msgid "Maximum number of campers must be one or greater." msgid "Maximum number of campers must be one or greater."
msgstr "El número màxim de persones no pot ser zero." msgstr "El número màxim de persones no pot ser zero."
#: pkg/campsite/types/admin.go:466 #: pkg/campsite/types/admin.go:472
msgid "Minimum number of nights can not be empty." msgid "Minimum number of nights can not be empty."
msgstr "No podeu deixar el número mínim de nits en blanc." msgstr "No podeu deixar el número mínim de nits en blanc."
#: pkg/campsite/types/admin.go:467 #: pkg/campsite/types/admin.go:473
msgid "Minimum number of nights must be an integer." msgid "Minimum number of nights must be an integer."
msgstr "El número mínim de nits ha de ser enter." msgstr "El número mínim de nits ha de ser enter."
#: pkg/campsite/types/admin.go:468 #: pkg/campsite/types/admin.go:474
msgid "Minimum number of nights must be one or greater." msgid "Minimum number of nights must be one or greater."
msgstr "El número mínim de nits no pot ser zero." msgstr "El número mínim de nits no pot ser zero."
@ -1707,6 +1650,22 @@ msgstr "El valor de %s ha de ser com a mínim %d."
msgid "%s must be at most %d." msgid "%s must be at most %d."
msgstr "El valor de %s ha de ser com a màxim %d." msgstr "El valor de %s ha de ser com a màxim %d."
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Feature to %s"
#~ msgstr "Traducció de la característica del tipus dallotjament a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Carousel Slide to %s"
#~ msgstr "Traducció de la diapositiva del carrusel del tipus dallotjament a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Option to %s"
#~ msgstr "Traducció de la opció del tipus dallotjament a %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type to %s"
#~ msgstr "Traducció del tipus dallotjament a %s"
#~ msgid "Starting from %s €/night" #~ msgid "Starting from %s €/night"
#~ msgstr "A partir de %s €/nit" #~ msgstr "A partir de %s €/nit"

221
po/es.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-10 19:33+0100\n" "POT-Creation-Date: 2024-01-10 21:49+0100\n"
"PO-Revision-Date: 2023-07-22 23:46+0200\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n" "Language-Team: Spanish <es@tp.org.es>\n"
@ -131,8 +131,8 @@ msgid "Calendar"
msgstr "Calendario" msgstr "Calendario"
#: web/templates/public/campsite/type.gohtml:73 #: web/templates/public/campsite/type.gohtml:73
#: web/templates/admin/campsite/option/form.gohtml:58 #: web/templates/admin/campsite/option/form.gohtml:63
#: web/templates/admin/campsite/type/form.gohtml:73 #: web/templates/admin/campsite/type/form.gohtml:78
msgctxt "title" msgctxt "title"
msgid "Prices" msgid "Prices"
msgstr "Precios" msgstr "Precios"
@ -419,11 +419,8 @@ msgstr "Álias"
#: web/templates/admin/legal/form.gohtml:46 #: web/templates/admin/legal/form.gohtml:46
#: web/templates/admin/campsite/feature/form.gohtml:52 #: web/templates/admin/campsite/feature/form.gohtml:52
#: web/templates/admin/campsite/feature/l10n.gohtml:20
#: web/templates/admin/campsite/option/form.gohtml:34 #: web/templates/admin/campsite/option/form.gohtml:34
#: web/templates/admin/campsite/option/l10n.gohtml:20
#: web/templates/admin/campsite/type/form.gohtml:46 #: web/templates/admin/campsite/type/form.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:20
#: web/templates/admin/season/form.gohtml:46 #: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/season/l10n.gohtml:20 #: web/templates/admin/season/l10n.gohtml:20
#: web/templates/admin/services/form.gohtml:52 #: web/templates/admin/services/form.gohtml:52
@ -440,11 +437,11 @@ msgstr "Contenido"
#: web/templates/admin/legal/form.gohtml:84 #: web/templates/admin/legal/form.gohtml:84
#: web/templates/admin/carousel/form.gohtml:47 #: web/templates/admin/carousel/form.gohtml:47
#: web/templates/admin/campsite/feature/form.gohtml:62 #: web/templates/admin/campsite/feature/form.gohtml:67
#: web/templates/admin/campsite/carousel/form.gohtml:47 #: web/templates/admin/campsite/carousel/form.gohtml:52
#: web/templates/admin/campsite/form.gohtml:70 #: web/templates/admin/campsite/form.gohtml:70
#: web/templates/admin/campsite/option/form.gohtml:78 #: web/templates/admin/campsite/option/form.gohtml:83
#: web/templates/admin/campsite/type/form.gohtml:129 #: web/templates/admin/campsite/type/form.gohtml:158
#: web/templates/admin/season/form.gohtml:64 #: web/templates/admin/season/form.gohtml:64
#: web/templates/admin/services/form.gohtml:69 #: web/templates/admin/services/form.gohtml:69
#: web/templates/admin/media/form.gohtml:35 #: web/templates/admin/media/form.gohtml:35
@ -454,11 +451,11 @@ msgstr "Actualizar"
#: web/templates/admin/legal/form.gohtml:86 #: web/templates/admin/legal/form.gohtml:86
#: web/templates/admin/carousel/form.gohtml:49 #: web/templates/admin/carousel/form.gohtml:49
#: web/templates/admin/campsite/feature/form.gohtml:64 #: web/templates/admin/campsite/feature/form.gohtml:69
#: web/templates/admin/campsite/carousel/form.gohtml:49 #: web/templates/admin/campsite/carousel/form.gohtml:54
#: web/templates/admin/campsite/form.gohtml:72 #: web/templates/admin/campsite/form.gohtml:72
#: web/templates/admin/campsite/option/form.gohtml:80 #: web/templates/admin/campsite/option/form.gohtml:85
#: web/templates/admin/campsite/type/form.gohtml:131 #: web/templates/admin/campsite/type/form.gohtml:160
#: web/templates/admin/season/form.gohtml:66 #: web/templates/admin/season/form.gohtml:66
#: web/templates/admin/services/form.gohtml:71 #: web/templates/admin/services/form.gohtml:71
msgctxt "action" msgctxt "action"
@ -505,7 +502,6 @@ msgstr "Nueva diapositiva del carrusel"
#: web/templates/admin/carousel/form.gohtml:37 #: web/templates/admin/carousel/form.gohtml:37
#: web/templates/admin/carousel/l10n.gohtml:20 #: web/templates/admin/carousel/l10n.gohtml:20
#: web/templates/admin/campsite/carousel/form.gohtml:37 #: web/templates/admin/campsite/carousel/form.gohtml:37
#: web/templates/admin/campsite/carousel/l10n.gohtml:20
msgctxt "input" msgctxt "input"
msgid "Caption" msgid "Caption"
msgstr "Leyenda" msgstr "Leyenda"
@ -517,14 +513,6 @@ msgid "Translate Carousel Slide to %s"
msgstr "Traducción de la diapositiva de carrusel a %s" msgstr "Traducción de la diapositiva de carrusel a %s"
#: web/templates/admin/carousel/l10n.gohtml:21 #: web/templates/admin/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/feature/l10n.gohtml:21
#: web/templates/admin/campsite/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/option/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:33
#: web/templates/admin/campsite/type/l10n.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:59
#: web/templates/admin/campsite/type/l10n.gohtml:72
#: web/templates/admin/season/l10n.gohtml:21 #: web/templates/admin/season/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:21 #: web/templates/admin/services/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:33 #: web/templates/admin/services/l10n.gohtml:33
@ -532,14 +520,6 @@ msgid "Source:"
msgstr "Origen:" msgstr "Origen:"
#: web/templates/admin/carousel/l10n.gohtml:23 #: web/templates/admin/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/feature/l10n.gohtml:23
#: web/templates/admin/campsite/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/option/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:36
#: web/templates/admin/campsite/type/l10n.gohtml:49
#: web/templates/admin/campsite/type/l10n.gohtml:62
#: web/templates/admin/campsite/type/l10n.gohtml:75
#: web/templates/admin/season/l10n.gohtml:23 #: web/templates/admin/season/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:23 #: web/templates/admin/services/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:36 #: web/templates/admin/services/l10n.gohtml:36
@ -548,10 +528,6 @@ msgid "Translation:"
msgstr "Traducción" msgstr "Traducción"
#: web/templates/admin/carousel/l10n.gohtml:32 #: web/templates/admin/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/feature/l10n.gohtml:32
#: web/templates/admin/campsite/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/option/l10n.gohtml:32
#: web/templates/admin/campsite/type/l10n.gohtml:84
#: web/templates/admin/season/l10n.gohtml:32 #: web/templates/admin/season/l10n.gohtml:32
#: web/templates/admin/services/l10n.gohtml:45 #: web/templates/admin/services/l10n.gohtml:45
msgctxt "action" msgctxt "action"
@ -614,28 +590,10 @@ msgctxt "action"
msgid "Add Feature" msgid "Add Feature"
msgstr "Añadir características" msgstr "Añadir características"
#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/feature/index.gohtml:43
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/campsite/option/index.gohtml:26
#: web/templates/admin/campsite/type/index.gohtml:26
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traducciones"
#: web/templates/admin/campsite/feature/index.gohtml:53
msgid "No campsite type features added yet." msgid "No campsite type features added yet."
msgstr "No se ha añadido ninguna característica al tipo de alojamiento todavía." msgstr "No se ha añadido ninguna característica al tipo de alojamiento todavía."
#: web/templates/admin/campsite/feature/l10n.gohtml:7
#: web/templates/admin/campsite/feature/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Feature to %s"
msgstr "Traducción de la característica del tipo de alojamiento a %s"
#: web/templates/admin/campsite/carousel/form.gohtml:8 #: web/templates/admin/campsite/carousel/form.gohtml:8
#: web/templates/admin/campsite/carousel/form.gohtml:25 #: web/templates/admin/campsite/carousel/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -675,7 +633,7 @@ msgctxt "header"
msgid "Caption" msgid "Caption"
msgstr "Leyenda" msgstr "Leyenda"
#: web/templates/admin/campsite/carousel/index.gohtml:28 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/services/index.gohtml:74 #: web/templates/admin/services/index.gohtml:74
#: web/templates/admin/home/index.gohtml:28 #: web/templates/admin/home/index.gohtml:28
@ -683,13 +641,13 @@ msgctxt "header"
msgid "Actions" msgid "Actions"
msgstr "Acciones" msgstr "Acciones"
#: web/templates/admin/campsite/carousel/index.gohtml:32 #: web/templates/admin/campsite/carousel/index.gohtml:31
#: web/templates/admin/services/index.gohtml:32 #: web/templates/admin/services/index.gohtml:32
#: web/templates/admin/home/index.gohtml:32 #: web/templates/admin/home/index.gohtml:32
msgid "Are you sure you wish to delete this slide?" msgid "Are you sure you wish to delete this slide?"
msgstr "¿Estáis seguro de querer borrar esta diapositiva?" msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:55 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:54 #: web/templates/admin/services/index.gohtml:54
#: web/templates/admin/services/index.gohtml:93 #: web/templates/admin/services/index.gohtml:93
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
@ -697,18 +655,12 @@ msgctxt "action"
msgid "Delete" msgid "Delete"
msgstr "Borrar" msgstr "Borrar"
#: web/templates/admin/campsite/carousel/index.gohtml:64 #: web/templates/admin/campsite/carousel/index.gohtml:54
#: web/templates/admin/services/index.gohtml:63 #: web/templates/admin/services/index.gohtml:63
#: web/templates/admin/home/index.gohtml:63 #: web/templates/admin/home/index.gohtml:63
msgid "No slides added yet." msgid "No slides added yet."
msgstr "No se ha añadido ninguna diapositiva todavía." msgstr "No se ha añadido ninguna diapositiva todavía."
#: web/templates/admin/campsite/carousel/l10n.gohtml:7
#: web/templates/admin/campsite/carousel/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Carousel Slide to %s"
msgstr "Traducción de la diapositiva de carrusel del tipo de alojamiento a %s"
#: web/templates/admin/campsite/form.gohtml:8 #: web/templates/admin/campsite/form.gohtml:8
#: web/templates/admin/campsite/form.gohtml:25 #: web/templates/admin/campsite/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -753,18 +705,18 @@ msgctxt "title"
msgid "New Campsite Type Option" msgid "New Campsite Type Option"
msgstr "Nueva opción del tipo de alojamiento" msgstr "Nueva opción del tipo de alojamiento"
#: web/templates/admin/campsite/option/form.gohtml:42 #: web/templates/admin/campsite/option/form.gohtml:47
msgctxt "input" msgctxt "input"
msgid "Minimum" msgid "Minimum"
msgstr "Mínimo" msgstr "Mínimo"
#: web/templates/admin/campsite/option/form.gohtml:50 #: web/templates/admin/campsite/option/form.gohtml:55
msgctxt "input" msgctxt "input"
msgid "Maximum" msgid "Maximum"
msgstr "Màximo" msgstr "Màximo"
#: web/templates/admin/campsite/option/form.gohtml:64 #: web/templates/admin/campsite/option/form.gohtml:69
#: web/templates/admin/campsite/type/form.gohtml:79 #: web/templates/admin/campsite/type/form.gohtml:84
msgctxt "input" msgctxt "input"
msgid "Price per night" msgid "Price per night"
msgstr "Precio por noche" msgstr "Precio por noche"
@ -780,16 +732,10 @@ msgctxt "action"
msgid "Add Option" msgid "Add Option"
msgstr "Añadir opción" msgstr "Añadir opción"
#: web/templates/admin/campsite/option/index.gohtml:52 #: web/templates/admin/campsite/option/index.gohtml:42
msgid "No campsite type options added yet." msgid "No campsite type options added yet."
msgstr "No se ha añadido ninguna opció al tipo de alojamiento todavía." msgstr "No se ha añadido ninguna opció al tipo de alojamiento todavía."
#: web/templates/admin/campsite/option/l10n.gohtml:7
#: web/templates/admin/campsite/option/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Option to %s"
msgstr "Traducción de la opción del tipo de alojamiento a %s"
#: web/templates/admin/campsite/index.gohtml:11 #: web/templates/admin/campsite/index.gohtml:11
msgctxt "action" msgctxt "action"
msgid "Add Campsite" msgid "Add Campsite"
@ -806,13 +752,13 @@ msgid "Type"
msgstr "Tipo" msgstr "Tipo"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "Yes" msgid "Yes"
msgstr "Sí" msgstr "Sí"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "No" msgid "No"
msgstr "No" msgstr "No"
@ -834,46 +780,42 @@ msgid "New Campsite Type"
msgstr "Nuevo tipo de alojamiento" msgstr "Nuevo tipo de alojamiento"
#: web/templates/admin/campsite/type/form.gohtml:37 #: web/templates/admin/campsite/type/form.gohtml:37
#: web/templates/admin/campsite/type/index.gohtml:30 #: web/templates/admin/campsite/type/index.gohtml:29
msgctxt "campsite type" msgctxt "campsite type"
msgid "Active" msgid "Active"
msgstr "Activo" msgstr "Activo"
#: web/templates/admin/campsite/type/form.gohtml:57 #: web/templates/admin/campsite/type/form.gohtml:62
msgctxt "input" msgctxt "input"
msgid "Maximum number of campers" msgid "Maximum number of campers"
msgstr "Número máximo de personas" msgstr "Número máximo de personas"
#: web/templates/admin/campsite/type/form.gohtml:67 #: web/templates/admin/campsite/type/form.gohtml:72
msgctxt "input" msgctxt "input"
msgid "Dogs allowed" msgid "Dogs allowed"
msgstr "Se permiten perros" msgstr "Se permiten perros"
#: web/templates/admin/campsite/type/form.gohtml:87 #: web/templates/admin/campsite/type/form.gohtml:92
msgctxt "input" msgctxt "input"
msgid "Minimum number of nights" msgid "Minimum number of nights"
msgstr "Número mínimos de noches" msgstr "Número mínimos de noches"
#: web/templates/admin/campsite/type/form.gohtml:99 #: web/templates/admin/campsite/type/form.gohtml:104
#: web/templates/admin/campsite/type/l10n.gohtml:32
msgctxt "input" msgctxt "input"
msgid "Spiel" msgid "Spiel"
msgstr "Introducción" msgstr "Introducción"
#: web/templates/admin/campsite/type/form.gohtml:106 #: web/templates/admin/campsite/type/form.gohtml:117
#: web/templates/admin/campsite/type/l10n.gohtml:45
msgctxt "input" msgctxt "input"
msgid "Info" msgid "Info"
msgstr "Información" msgstr "Información"
#: web/templates/admin/campsite/type/form.gohtml:113 #: web/templates/admin/campsite/type/form.gohtml:130
#: web/templates/admin/campsite/type/l10n.gohtml:58
msgctxt "input" msgctxt "input"
msgid "Facilities" msgid "Facilities"
msgstr "Equipamento" msgstr "Equipamento"
#: web/templates/admin/campsite/type/form.gohtml:120 #: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/campsite/type/l10n.gohtml:71
#: web/templates/admin/services/form.gohtml:60 #: web/templates/admin/services/form.gohtml:60
#: web/templates/admin/services/l10n.gohtml:32 #: web/templates/admin/services/l10n.gohtml:32
msgctxt "input" msgctxt "input"
@ -892,46 +834,40 @@ msgctxt "action"
msgid "Add Type" msgid "Add Type"
msgstr "Añadir tipo" msgstr "Añadir tipo"
#: web/templates/admin/campsite/type/index.gohtml:27 #: web/templates/admin/campsite/type/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Features" msgid "Features"
msgstr "Características" msgstr "Características"
#: web/templates/admin/campsite/type/index.gohtml:28 #: web/templates/admin/campsite/type/index.gohtml:27
msgctxt "header" msgctxt "header"
msgid "Options" msgid "Options"
msgstr "Opciones" msgstr "Opciones"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:28
msgctxt "header" msgctxt "header"
msgid "Carousel" msgid "Carousel"
msgstr "Carrusel" msgstr "Carrusel"
#: web/templates/admin/campsite/type/index.gohtml:51 #: web/templates/admin/campsite/type/index.gohtml:41
msgctxt "action" msgctxt "action"
msgid "Edit Features" msgid "Edit Features"
msgstr "Editar las características" msgstr "Editar las características"
#: web/templates/admin/campsite/type/index.gohtml:54 #: web/templates/admin/campsite/type/index.gohtml:44
msgctxt "action" msgctxt "action"
msgid "Edit Options" msgid "Edit Options"
msgstr "Editar opciones" msgstr "Editar opciones"
#: web/templates/admin/campsite/type/index.gohtml:57 #: web/templates/admin/campsite/type/index.gohtml:47
msgctxt "action" msgctxt "action"
msgid "Edit Carousel" msgid "Edit Carousel"
msgstr "Editar el carrusel" msgstr "Editar el carrusel"
#: web/templates/admin/campsite/type/index.gohtml:66 #: web/templates/admin/campsite/type/index.gohtml:56
msgid "No campsite types added yet." msgid "No campsite types added yet."
msgstr "No se ha añadido ningún tipo de alojamiento todavía." msgstr "No se ha añadido ningún tipo de alojamiento todavía."
#: web/templates/admin/campsite/type/l10n.gohtml:7
#: web/templates/admin/campsite/type/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type to %s"
msgstr "Traducción de tipo de alojamiento a %s"
#: web/templates/admin/season/form.gohtml:8 #: web/templates/admin/season/form.gohtml:8
#: web/templates/admin/season/form.gohtml:25 #: web/templates/admin/season/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -972,6 +908,14 @@ msgctxt "header"
msgid "Color" msgid "Color"
msgstr "Color" msgstr "Color"
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traducciones"
#: web/templates/admin/season/index.gohtml:56 #: web/templates/admin/season/index.gohtml:56
msgid "No seasons added yet." msgid "No seasons added yet."
msgstr "No se ha añadido ninguna temporada todavía." msgstr "No se ha añadido ninguna temporada todavía."
@ -1278,25 +1222,24 @@ msgctxt "title"
msgid "Upload Media" msgid "Upload Media"
msgstr "Subida de medio" msgstr "Subida de medio"
#: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:453
#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/season/l10n.go:69 pkg/season/admin.go:405 pkg/services/l10n.go:73
#: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/services/admin.go:266
#: pkg/season/admin.go:405 pkg/services/l10n.go:73 pkg/services/admin.go:266
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco." msgstr "No podéis dejar el nombre en blanco."
#: pkg/legal/admin.go:256 pkg/campsite/types/option.go:351 #: pkg/legal/admin.go:256 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:254 pkg/campsite/types/admin.go:448 #: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:454
msgid "Name must have at least one letter." msgid "Name must have at least one letter."
msgstr "El nombre tiene que tener como mínimo una letra." msgstr "El nombre tiene que tener como mínimo una letra."
#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 #: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:223
msgctxt "input" msgctxt "input"
msgid "Slide image" msgid "Slide image"
msgstr "Imagen de la diapositiva" msgstr "Imagen de la diapositiva"
#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 #: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:224
msgctxt "action" msgctxt "action"
msgid "Set slide image" msgid "Set slide image"
msgstr "Establecer la imagen de la diapositiva" msgstr "Establecer la imagen de la diapositiva"
@ -1348,85 +1291,85 @@ msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Acceso prohibido" msgstr "Acceso prohibido"
#: pkg/campsite/types/option.go:354 #: pkg/campsite/types/option.go:348
msgid "Minimum can not be empty." msgid "Minimum can not be empty."
msgstr "No podéis dejar el mínimo en blanco." msgstr "No podéis dejar el mínimo en blanco."
#: pkg/campsite/types/option.go:355 #: pkg/campsite/types/option.go:349
msgid "Minimum must be an integer number." msgid "Minimum must be an integer number."
msgstr "El valor de mínimo tiene que ser un número entero." msgstr "El valor de mínimo tiene que ser un número entero."
#: pkg/campsite/types/option.go:357 #: pkg/campsite/types/option.go:351
msgid "Minimum must be zero or greater." msgid "Minimum must be zero or greater."
msgstr "El valor de mínimo tiene que ser como mínimo cero." msgstr "El valor de mínimo tiene que ser como mínimo cero."
#: pkg/campsite/types/option.go:360 #: pkg/campsite/types/option.go:354
msgid "Maximum can not be empty." msgid "Maximum can not be empty."
msgstr "No podéis dejar el máxmimo en blanco." msgstr "No podéis dejar el máxmimo en blanco."
#: pkg/campsite/types/option.go:361 #: pkg/campsite/types/option.go:355
msgid "Maximum must be an integer number." msgid "Maximum must be an integer number."
msgstr "El valor del máximo tiene que ser un número entero." msgstr "El valor del máximo tiene que ser un número entero."
#: pkg/campsite/types/option.go:363 #: pkg/campsite/types/option.go:357
msgid "Maximum must be equal or greater than minimum." 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." msgstr "El valor del máximo tiene que ser igual o mayor al del mínimo."
#: pkg/campsite/types/option.go:367 pkg/campsite/types/admin.go:461 #: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:467
msgid "Price per night can not be empty." msgid "Price per night can not be empty."
msgstr "No podéis dejar el precio por noche en blanco." msgstr "No podéis dejar el precio por noche en blanco."
#: pkg/campsite/types/option.go:368 pkg/campsite/types/admin.go:462 #: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:468
msgid "Price per night must be a decimal number." msgid "Price per night must be a decimal number."
msgstr "El precio por noche tien que ser un número decimal." msgstr "El precio por noche tien que ser un número decimal."
#: pkg/campsite/types/option.go:369 pkg/campsite/types/admin.go:463 #: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:469
msgid "Price per night must be zero or greater." msgid "Price per night must be zero or greater."
msgstr "El precio por noche tiene que ser como mínimo cero." msgstr "El precio por noche tiene que ser como mínimo cero."
#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 #: pkg/campsite/types/feature.go:258 pkg/services/admin.go:265
msgid "Selected icon is not valid." msgid "Selected icon is not valid."
msgstr "El icono escogido no es válido." msgstr "El icono escogido no es válido."
#: pkg/campsite/types/admin.go:323 #: pkg/campsite/types/admin.go:304
msgctxt "input" msgctxt "input"
msgid "Cover image" msgid "Cover image"
msgstr "Imagen de portada" msgstr "Imagen de portada"
#: pkg/campsite/types/admin.go:324 #: pkg/campsite/types/admin.go:305
msgctxt "action" msgctxt "action"
msgid "Set campsite type cover" msgid "Set campsite type cover"
msgstr "Establecer la portada del tipo de alojamiento" msgstr "Establecer la portada del tipo de alojamiento"
#: pkg/campsite/types/admin.go:450 #: pkg/campsite/types/admin.go:456
msgid "Cover image can not be empty." msgid "Cover image can not be empty."
msgstr "No podéis dejar la imagen de portada en blanco." msgstr "No podéis dejar la imagen de portada en blanco."
#: pkg/campsite/types/admin.go:451 #: pkg/campsite/types/admin.go:457
msgid "Cover image must be an image media type." msgid "Cover image must be an image media type."
msgstr "La imagen de portada tiene que ser un medio de tipo imagen." msgstr "La imagen de portada tiene que ser un medio de tipo imagen."
#: pkg/campsite/types/admin.go:455 #: pkg/campsite/types/admin.go:461
msgid "Maximum number of campers can not be empty." msgid "Maximum number of campers can not be empty."
msgstr "No podéis dejar el número máximo de personas en blanco." msgstr "No podéis dejar el número máximo de personas en blanco."
#: pkg/campsite/types/admin.go:456 #: pkg/campsite/types/admin.go:462
msgid "Maximum number of campers must be an integer number." msgid "Maximum number of campers must be an integer number."
msgstr "El número máximo de personas tiene que ser entero." msgstr "El número máximo de personas tiene que ser entero."
#: pkg/campsite/types/admin.go:457 #: pkg/campsite/types/admin.go:463
msgid "Maximum number of campers must be one or greater." msgid "Maximum number of campers must be one or greater."
msgstr "El número máximo de personas no puede ser cero." msgstr "El número máximo de personas no puede ser cero."
#: pkg/campsite/types/admin.go:466 #: pkg/campsite/types/admin.go:472
msgid "Minimum number of nights can not be empty." msgid "Minimum number of nights can not be empty."
msgstr "No podéis dejar el número mínimo de noches en blanco." msgstr "No podéis dejar el número mínimo de noches en blanco."
#: pkg/campsite/types/admin.go:467 #: pkg/campsite/types/admin.go:473
msgid "Minimum number of nights must be an integer." msgid "Minimum number of nights must be an integer."
msgstr "El número mínimo de noches tiene que ser entero." msgstr "El número mínimo de noches tiene que ser entero."
#: pkg/campsite/types/admin.go:468 #: pkg/campsite/types/admin.go:474
msgid "Minimum number of nights must be one or greater." msgid "Minimum number of nights must be one or greater."
msgstr "El número mínimo de noches no puede ser cero." msgstr "El número mínimo de noches no puede ser cero."
@ -1707,6 +1650,22 @@ msgstr "%s tiene que ser como mínimo %d."
msgid "%s must be at most %d." msgid "%s must be at most %d."
msgstr "%s tiene que ser como máximo %d" msgstr "%s tiene que ser como máximo %d"
#~ 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"
#~ msgid "Starting from %s €/night" #~ msgid "Starting from %s €/night"
#~ msgstr "A partir de %s €/noche" #~ msgstr "A partir de %s €/noche"

221
po/fr.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-10 19:33+0100\n" "POT-Creation-Date: 2024-01-10 21:49+0100\n"
"PO-Revision-Date: 2023-12-20 10:13+0100\n" "PO-Revision-Date: 2023-12-20 10:13+0100\n"
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n" "Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
"Language-Team: French <traduc@traduc.org>\n" "Language-Team: French <traduc@traduc.org>\n"
@ -132,8 +132,8 @@ msgid "Calendar"
msgstr "Calendrier" msgstr "Calendrier"
#: web/templates/public/campsite/type.gohtml:73 #: web/templates/public/campsite/type.gohtml:73
#: web/templates/admin/campsite/option/form.gohtml:58 #: web/templates/admin/campsite/option/form.gohtml:63
#: web/templates/admin/campsite/type/form.gohtml:73 #: web/templates/admin/campsite/type/form.gohtml:78
msgctxt "title" msgctxt "title"
msgid "Prices" msgid "Prices"
msgstr "Prix" msgstr "Prix"
@ -420,11 +420,8 @@ msgstr "Slug"
#: web/templates/admin/legal/form.gohtml:46 #: web/templates/admin/legal/form.gohtml:46
#: web/templates/admin/campsite/feature/form.gohtml:52 #: web/templates/admin/campsite/feature/form.gohtml:52
#: web/templates/admin/campsite/feature/l10n.gohtml:20
#: web/templates/admin/campsite/option/form.gohtml:34 #: web/templates/admin/campsite/option/form.gohtml:34
#: web/templates/admin/campsite/option/l10n.gohtml:20
#: web/templates/admin/campsite/type/form.gohtml:46 #: web/templates/admin/campsite/type/form.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:20
#: web/templates/admin/season/form.gohtml:46 #: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/season/l10n.gohtml:20 #: web/templates/admin/season/l10n.gohtml:20
#: web/templates/admin/services/form.gohtml:52 #: web/templates/admin/services/form.gohtml:52
@ -441,11 +438,11 @@ msgstr "Contenu"
#: web/templates/admin/legal/form.gohtml:84 #: web/templates/admin/legal/form.gohtml:84
#: web/templates/admin/carousel/form.gohtml:47 #: web/templates/admin/carousel/form.gohtml:47
#: web/templates/admin/campsite/feature/form.gohtml:62 #: web/templates/admin/campsite/feature/form.gohtml:67
#: web/templates/admin/campsite/carousel/form.gohtml:47 #: web/templates/admin/campsite/carousel/form.gohtml:52
#: web/templates/admin/campsite/form.gohtml:70 #: web/templates/admin/campsite/form.gohtml:70
#: web/templates/admin/campsite/option/form.gohtml:78 #: web/templates/admin/campsite/option/form.gohtml:83
#: web/templates/admin/campsite/type/form.gohtml:129 #: web/templates/admin/campsite/type/form.gohtml:158
#: web/templates/admin/season/form.gohtml:64 #: web/templates/admin/season/form.gohtml:64
#: web/templates/admin/services/form.gohtml:69 #: web/templates/admin/services/form.gohtml:69
#: web/templates/admin/media/form.gohtml:35 #: web/templates/admin/media/form.gohtml:35
@ -455,11 +452,11 @@ msgstr "Mettre à jour"
#: web/templates/admin/legal/form.gohtml:86 #: web/templates/admin/legal/form.gohtml:86
#: web/templates/admin/carousel/form.gohtml:49 #: web/templates/admin/carousel/form.gohtml:49
#: web/templates/admin/campsite/feature/form.gohtml:64 #: web/templates/admin/campsite/feature/form.gohtml:69
#: web/templates/admin/campsite/carousel/form.gohtml:49 #: web/templates/admin/campsite/carousel/form.gohtml:54
#: web/templates/admin/campsite/form.gohtml:72 #: web/templates/admin/campsite/form.gohtml:72
#: web/templates/admin/campsite/option/form.gohtml:80 #: web/templates/admin/campsite/option/form.gohtml:85
#: web/templates/admin/campsite/type/form.gohtml:131 #: web/templates/admin/campsite/type/form.gohtml:160
#: web/templates/admin/season/form.gohtml:66 #: web/templates/admin/season/form.gohtml:66
#: web/templates/admin/services/form.gohtml:71 #: web/templates/admin/services/form.gohtml:71
msgctxt "action" msgctxt "action"
@ -506,7 +503,6 @@ msgstr "Nouveau toboggan carrousel"
#: web/templates/admin/carousel/form.gohtml:37 #: web/templates/admin/carousel/form.gohtml:37
#: web/templates/admin/carousel/l10n.gohtml:20 #: web/templates/admin/carousel/l10n.gohtml:20
#: web/templates/admin/campsite/carousel/form.gohtml:37 #: web/templates/admin/campsite/carousel/form.gohtml:37
#: web/templates/admin/campsite/carousel/l10n.gohtml:20
msgctxt "input" msgctxt "input"
msgid "Caption" msgid "Caption"
msgstr "Légende" msgstr "Légende"
@ -518,14 +514,6 @@ msgid "Translate Carousel Slide to %s"
msgstr "Traduire la diapositive Carousel en %s" msgstr "Traduire la diapositive Carousel en %s"
#: web/templates/admin/carousel/l10n.gohtml:21 #: web/templates/admin/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/feature/l10n.gohtml:21
#: web/templates/admin/campsite/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/option/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:33
#: web/templates/admin/campsite/type/l10n.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:59
#: web/templates/admin/campsite/type/l10n.gohtml:72
#: web/templates/admin/season/l10n.gohtml:21 #: web/templates/admin/season/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:21 #: web/templates/admin/services/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:33 #: web/templates/admin/services/l10n.gohtml:33
@ -533,14 +521,6 @@ msgid "Source:"
msgstr "Source :" msgstr "Source :"
#: web/templates/admin/carousel/l10n.gohtml:23 #: web/templates/admin/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/feature/l10n.gohtml:23
#: web/templates/admin/campsite/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/option/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:36
#: web/templates/admin/campsite/type/l10n.gohtml:49
#: web/templates/admin/campsite/type/l10n.gohtml:62
#: web/templates/admin/campsite/type/l10n.gohtml:75
#: web/templates/admin/season/l10n.gohtml:23 #: web/templates/admin/season/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:23 #: web/templates/admin/services/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:36 #: web/templates/admin/services/l10n.gohtml:36
@ -549,10 +529,6 @@ msgid "Translation:"
msgstr "Traduction :" msgstr "Traduction :"
#: web/templates/admin/carousel/l10n.gohtml:32 #: web/templates/admin/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/feature/l10n.gohtml:32
#: web/templates/admin/campsite/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/option/l10n.gohtml:32
#: web/templates/admin/campsite/type/l10n.gohtml:84
#: web/templates/admin/season/l10n.gohtml:32 #: web/templates/admin/season/l10n.gohtml:32
#: web/templates/admin/services/l10n.gohtml:45 #: web/templates/admin/services/l10n.gohtml:45
msgctxt "action" msgctxt "action"
@ -615,28 +591,10 @@ msgctxt "action"
msgid "Add Feature" msgid "Add Feature"
msgstr "Ajouter une fonctionnalité" msgstr "Ajouter une fonctionnalité"
#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/feature/index.gohtml:43
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/campsite/option/index.gohtml:26
#: web/templates/admin/campsite/type/index.gohtml:26
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traductions"
#: web/templates/admin/campsite/feature/index.gohtml:53
msgid "No campsite type features added yet." msgid "No campsite type features added yet."
msgstr "Aucune fonctionnalité de type camping na encore été ajoutée." msgstr "Aucune fonctionnalité de type camping na encore été ajoutée."
#: web/templates/admin/campsite/feature/l10n.gohtml:7
#: web/templates/admin/campsite/feature/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Feature to %s"
msgstr "Traduire Caractéristique de type de camping en %s"
#: web/templates/admin/campsite/carousel/form.gohtml:8 #: web/templates/admin/campsite/carousel/form.gohtml:8
#: web/templates/admin/campsite/carousel/form.gohtml:25 #: web/templates/admin/campsite/carousel/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -676,7 +634,7 @@ msgctxt "header"
msgid "Caption" msgid "Caption"
msgstr "Légende" msgstr "Légende"
#: web/templates/admin/campsite/carousel/index.gohtml:28 #: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/services/index.gohtml:74 #: web/templates/admin/services/index.gohtml:74
#: web/templates/admin/home/index.gohtml:28 #: web/templates/admin/home/index.gohtml:28
@ -684,13 +642,13 @@ msgctxt "header"
msgid "Actions" msgid "Actions"
msgstr "Actions" msgstr "Actions"
#: web/templates/admin/campsite/carousel/index.gohtml:32 #: web/templates/admin/campsite/carousel/index.gohtml:31
#: web/templates/admin/services/index.gohtml:32 #: web/templates/admin/services/index.gohtml:32
#: web/templates/admin/home/index.gohtml:32 #: web/templates/admin/home/index.gohtml:32
msgid "Are you sure you wish to delete this slide?" msgid "Are you sure you wish to delete this slide?"
msgstr "Êtes-vous sûr de vouloir supprimer cette diapositive ?" msgstr "Êtes-vous sûr de vouloir supprimer cette diapositive ?"
#: web/templates/admin/campsite/carousel/index.gohtml:55 #: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:54 #: web/templates/admin/services/index.gohtml:54
#: web/templates/admin/services/index.gohtml:93 #: web/templates/admin/services/index.gohtml:93
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
@ -698,18 +656,12 @@ msgctxt "action"
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: web/templates/admin/campsite/carousel/index.gohtml:64 #: web/templates/admin/campsite/carousel/index.gohtml:54
#: web/templates/admin/services/index.gohtml:63 #: web/templates/admin/services/index.gohtml:63
#: web/templates/admin/home/index.gohtml:63 #: web/templates/admin/home/index.gohtml:63
msgid "No slides added yet." msgid "No slides added yet."
msgstr "Aucune diapositive na encore été ajoutée." msgstr "Aucune diapositive na encore été ajoutée."
#: web/templates/admin/campsite/carousel/l10n.gohtml:7
#: web/templates/admin/campsite/carousel/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Carousel Slide to %s"
msgstr "Convertir Glissière de carrousel de type camping en %s"
#: web/templates/admin/campsite/form.gohtml:8 #: web/templates/admin/campsite/form.gohtml:8
#: web/templates/admin/campsite/form.gohtml:25 #: web/templates/admin/campsite/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -754,18 +706,18 @@ msgctxt "title"
msgid "New Campsite Type Option" msgid "New Campsite Type Option"
msgstr "Nouvelle option de type demplacement de camping" msgstr "Nouvelle option de type demplacement de camping"
#: web/templates/admin/campsite/option/form.gohtml:42 #: web/templates/admin/campsite/option/form.gohtml:47
msgctxt "input" msgctxt "input"
msgid "Minimum" msgid "Minimum"
msgstr "Minimum" msgstr "Minimum"
#: web/templates/admin/campsite/option/form.gohtml:50 #: web/templates/admin/campsite/option/form.gohtml:55
msgctxt "input" msgctxt "input"
msgid "Maximum" msgid "Maximum"
msgstr "Maximum" msgstr "Maximum"
#: web/templates/admin/campsite/option/form.gohtml:64 #: web/templates/admin/campsite/option/form.gohtml:69
#: web/templates/admin/campsite/type/form.gohtml:79 #: web/templates/admin/campsite/type/form.gohtml:84
msgctxt "input" msgctxt "input"
msgid "Price per night" msgid "Price per night"
msgstr "Prix par nuit" msgstr "Prix par nuit"
@ -781,16 +733,10 @@ msgctxt "action"
msgid "Add Option" msgid "Add Option"
msgstr "Ajouter une option" msgstr "Ajouter une option"
#: web/templates/admin/campsite/option/index.gohtml:52 #: web/templates/admin/campsite/option/index.gohtml:42
msgid "No campsite type options added yet." msgid "No campsite type options added yet."
msgstr "Aucune option de type de camping na encore été ajoutée." msgstr "Aucune option de type de camping na encore été ajoutée."
#: web/templates/admin/campsite/option/l10n.gohtml:7
#: web/templates/admin/campsite/option/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type Option to %s"
msgstr "Traduire loption Type de camping en %s"
#: web/templates/admin/campsite/index.gohtml:11 #: web/templates/admin/campsite/index.gohtml:11
msgctxt "action" msgctxt "action"
msgid "Add Campsite" msgid "Add Campsite"
@ -807,13 +753,13 @@ msgid "Type"
msgstr "Type" msgstr "Type"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "Yes" msgid "Yes"
msgstr "Oui" msgstr "Oui"
#: web/templates/admin/campsite/index.gohtml:28 #: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:59 #: web/templates/admin/campsite/type/index.gohtml:49
#: web/templates/admin/season/index.gohtml:49 #: web/templates/admin/season/index.gohtml:49
msgid "No" msgid "No"
msgstr "Non" msgstr "Non"
@ -835,46 +781,42 @@ msgid "New Campsite Type"
msgstr "Nouveau type demplacement de camping" msgstr "Nouveau type demplacement de camping"
#: web/templates/admin/campsite/type/form.gohtml:37 #: web/templates/admin/campsite/type/form.gohtml:37
#: web/templates/admin/campsite/type/index.gohtml:30 #: web/templates/admin/campsite/type/index.gohtml:29
msgctxt "campsite type" msgctxt "campsite type"
msgid "Active" msgid "Active"
msgstr "Actif" msgstr "Actif"
#: web/templates/admin/campsite/type/form.gohtml:57 #: web/templates/admin/campsite/type/form.gohtml:62
msgctxt "input" msgctxt "input"
msgid "Maximum number of campers" msgid "Maximum number of campers"
msgstr "Nombre maximum de campeurs" msgstr "Nombre maximum de campeurs"
#: web/templates/admin/campsite/type/form.gohtml:67 #: web/templates/admin/campsite/type/form.gohtml:72
msgctxt "input" msgctxt "input"
msgid "Dogs allowed" msgid "Dogs allowed"
msgstr "Chiens acceptés" msgstr "Chiens acceptés"
#: web/templates/admin/campsite/type/form.gohtml:87 #: web/templates/admin/campsite/type/form.gohtml:92
msgctxt "input" msgctxt "input"
msgid "Minimum number of nights" msgid "Minimum number of nights"
msgstr "Nombre minimum de nuits" msgstr "Nombre minimum de nuits"
#: web/templates/admin/campsite/type/form.gohtml:99 #: web/templates/admin/campsite/type/form.gohtml:104
#: web/templates/admin/campsite/type/l10n.gohtml:32
msgctxt "input" msgctxt "input"
msgid "Spiel" msgid "Spiel"
msgstr "Boniment" msgstr "Boniment"
#: web/templates/admin/campsite/type/form.gohtml:106 #: web/templates/admin/campsite/type/form.gohtml:117
#: web/templates/admin/campsite/type/l10n.gohtml:45
msgctxt "input" msgctxt "input"
msgid "Info" msgid "Info"
msgstr "Info" msgstr "Info"
#: web/templates/admin/campsite/type/form.gohtml:113 #: web/templates/admin/campsite/type/form.gohtml:130
#: web/templates/admin/campsite/type/l10n.gohtml:58
msgctxt "input" msgctxt "input"
msgid "Facilities" msgid "Facilities"
msgstr "Installations" msgstr "Installations"
#: web/templates/admin/campsite/type/form.gohtml:120 #: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/campsite/type/l10n.gohtml:71
#: web/templates/admin/services/form.gohtml:60 #: web/templates/admin/services/form.gohtml:60
#: web/templates/admin/services/l10n.gohtml:32 #: web/templates/admin/services/l10n.gohtml:32
msgctxt "input" msgctxt "input"
@ -893,46 +835,40 @@ msgctxt "action"
msgid "Add Type" msgid "Add Type"
msgstr "Ajouter un type" msgstr "Ajouter un type"
#: web/templates/admin/campsite/type/index.gohtml:27 #: web/templates/admin/campsite/type/index.gohtml:26
msgctxt "header" msgctxt "header"
msgid "Features" msgid "Features"
msgstr "Caractéristiques" msgstr "Caractéristiques"
#: web/templates/admin/campsite/type/index.gohtml:28 #: web/templates/admin/campsite/type/index.gohtml:27
msgctxt "header" msgctxt "header"
msgid "Options" msgid "Options"
msgstr "Options" msgstr "Options"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:28
msgctxt "header" msgctxt "header"
msgid "Carousel" msgid "Carousel"
msgstr "Carrousel" msgstr "Carrousel"
#: web/templates/admin/campsite/type/index.gohtml:51 #: web/templates/admin/campsite/type/index.gohtml:41
msgctxt "action" msgctxt "action"
msgid "Edit Features" msgid "Edit Features"
msgstr "Edit Caractéristiques" msgstr "Edit Caractéristiques"
#: web/templates/admin/campsite/type/index.gohtml:54 #: web/templates/admin/campsite/type/index.gohtml:44
msgctxt "action" msgctxt "action"
msgid "Edit Options" msgid "Edit Options"
msgstr "Modifier les options" msgstr "Modifier les options"
#: web/templates/admin/campsite/type/index.gohtml:57 #: web/templates/admin/campsite/type/index.gohtml:47
msgctxt "action" msgctxt "action"
msgid "Edit Carousel" msgid "Edit Carousel"
msgstr "Modifier le carrousel" msgstr "Modifier le carrousel"
#: web/templates/admin/campsite/type/index.gohtml:66 #: web/templates/admin/campsite/type/index.gohtml:56
msgid "No campsite types added yet." msgid "No campsite types added yet."
msgstr "Aucun type demplacement na encore été ajouté." msgstr "Aucun type demplacement na encore été ajouté."
#: web/templates/admin/campsite/type/l10n.gohtml:7
#: web/templates/admin/campsite/type/l10n.gohtml:14
msgctxt "title"
msgid "Translate Campsite Type to %s"
msgstr "Traduire Type de camping en %s"
#: web/templates/admin/season/form.gohtml:8 #: web/templates/admin/season/form.gohtml:8
#: web/templates/admin/season/form.gohtml:25 #: web/templates/admin/season/form.gohtml:25
msgctxt "title" msgctxt "title"
@ -973,6 +909,14 @@ msgctxt "header"
msgid "Color" msgid "Color"
msgstr "Couleur" msgstr "Couleur"
#: web/templates/admin/season/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Translations"
msgstr "Traductions"
#: web/templates/admin/season/index.gohtml:56 #: web/templates/admin/season/index.gohtml:56
msgid "No seasons added yet." msgid "No seasons added yet."
msgstr "Aucune saison na encore été ajoutée." msgstr "Aucune saison na encore été ajoutée."
@ -1279,25 +1223,24 @@ msgctxt "title"
msgid "Upload Media" msgid "Upload Media"
msgstr "Envoyer un fichier" msgstr "Envoyer un fichier"
#: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/legal/admin.go:255 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:453
#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/season/l10n.go:69 pkg/season/admin.go:405 pkg/services/l10n.go:73
#: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/services/admin.go:266
#: pkg/season/admin.go:405 pkg/services/l10n.go:73 pkg/services/admin.go:266
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "Le nom ne peut pas être laissé vide." msgstr "Le nom ne peut pas être laissé vide."
#: pkg/legal/admin.go:256 pkg/campsite/types/option.go:351 #: pkg/legal/admin.go:256 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:254 pkg/campsite/types/admin.go:448 #: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:454
msgid "Name must have at least one letter." msgid "Name must have at least one letter."
msgstr "Le nom doit comporter au moins une lettre." msgstr "Le nom doit comporter au moins une lettre."
#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 #: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:223
msgctxt "input" msgctxt "input"
msgid "Slide image" msgid "Slide image"
msgstr "Image du diaporama" msgstr "Image du diaporama"
#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 #: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:224
msgctxt "action" msgctxt "action"
msgid "Set slide image" msgid "Set slide image"
msgstr "Définir limage de la diapositive" msgstr "Définir limage de la diapositive"
@ -1349,85 +1292,85 @@ msgstr "Le fichier doit être une image PNG ou JPEG valide."
msgid "Access forbidden" msgid "Access forbidden"
msgstr "Accès interdit" msgstr "Accès interdit"
#: pkg/campsite/types/option.go:354 #: pkg/campsite/types/option.go:348
msgid "Minimum can not be empty." msgid "Minimum can not be empty."
msgstr "Le minimum ne peut pas être vide." msgstr "Le minimum ne peut pas être vide."
#: pkg/campsite/types/option.go:355 #: pkg/campsite/types/option.go:349
msgid "Minimum must be an integer number." msgid "Minimum must be an integer number."
msgstr "Le minimum doit être un nombre entier." msgstr "Le minimum doit être un nombre entier."
#: pkg/campsite/types/option.go:357 #: pkg/campsite/types/option.go:351
msgid "Minimum must be zero or greater." msgid "Minimum must be zero or greater."
msgstr "Le minimum doit être égal ou supérieur à zéro." msgstr "Le minimum doit être égal ou supérieur à zéro."
#: pkg/campsite/types/option.go:360 #: pkg/campsite/types/option.go:354
msgid "Maximum can not be empty." msgid "Maximum can not be empty."
msgstr "Le maximum ne peut pas être vide." msgstr "Le maximum ne peut pas être vide."
#: pkg/campsite/types/option.go:361 #: pkg/campsite/types/option.go:355
msgid "Maximum must be an integer number." msgid "Maximum must be an integer number."
msgstr "Le maximum doit être un nombre entier." msgstr "Le maximum doit être un nombre entier."
#: pkg/campsite/types/option.go:363 #: pkg/campsite/types/option.go:357
msgid "Maximum must be equal or greater than minimum." msgid "Maximum must be equal or greater than minimum."
msgstr "Le maximum doit être égal ou supérieur au minimum." msgstr "Le maximum doit être égal ou supérieur au minimum."
#: pkg/campsite/types/option.go:367 pkg/campsite/types/admin.go:461 #: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:467
msgid "Price per night can not be empty." msgid "Price per night can not be empty."
msgstr "Le prix par nuit ne peut pas être vide." msgstr "Le prix par nuit ne peut pas être vide."
#: pkg/campsite/types/option.go:368 pkg/campsite/types/admin.go:462 #: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:468
msgid "Price per night must be a decimal number." msgid "Price per night must be a decimal number."
msgstr "Le prix par nuit doit être un nombre décimal." msgstr "Le prix par nuit doit être un nombre décimal."
#: pkg/campsite/types/option.go:369 pkg/campsite/types/admin.go:463 #: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:469
msgid "Price per night must be zero or greater." msgid "Price per night must be zero or greater."
msgstr "Le prix par nuit doit être égal ou supérieur." msgstr "Le prix par nuit doit être égal ou supérieur."
#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 #: pkg/campsite/types/feature.go:258 pkg/services/admin.go:265
msgid "Selected icon is not valid." msgid "Selected icon is not valid."
msgstr "Licône sélectionnée nest pas valide." msgstr "Licône sélectionnée nest pas valide."
#: pkg/campsite/types/admin.go:323 #: pkg/campsite/types/admin.go:304
msgctxt "input" msgctxt "input"
msgid "Cover image" msgid "Cover image"
msgstr "Image de couverture" msgstr "Image de couverture"
#: pkg/campsite/types/admin.go:324 #: pkg/campsite/types/admin.go:305
msgctxt "action" msgctxt "action"
msgid "Set campsite type cover" msgid "Set campsite type cover"
msgstr "Définir une couverture type camping" msgstr "Définir une couverture type camping"
#: pkg/campsite/types/admin.go:450 #: pkg/campsite/types/admin.go:456
msgid "Cover image can not be empty." msgid "Cover image can not be empty."
msgstr "Limage de couverture ne peut pas être vide." msgstr "Limage de couverture ne peut pas être vide."
#: pkg/campsite/types/admin.go:451 #: pkg/campsite/types/admin.go:457
msgid "Cover image must be an image media type." msgid "Cover image must be an image media type."
msgstr "Limage de couverture doit être de type média dimage." msgstr "Limage de couverture doit être de type média dimage."
#: pkg/campsite/types/admin.go:455 #: pkg/campsite/types/admin.go:461
msgid "Maximum number of campers can not be empty." msgid "Maximum number of campers can not be empty."
msgstr "Le nombre maximum de campeurs ne peut pas être vide." msgstr "Le nombre maximum de campeurs ne peut pas être vide."
#: pkg/campsite/types/admin.go:456 #: pkg/campsite/types/admin.go:462
msgid "Maximum number of campers must be an integer number." msgid "Maximum number of campers must be an integer number."
msgstr "Le nombre maximum de campeurs doit être un nombre entier." msgstr "Le nombre maximum de campeurs doit être un nombre entier."
#: pkg/campsite/types/admin.go:457 #: pkg/campsite/types/admin.go:463
msgid "Maximum number of campers must be one or greater." msgid "Maximum number of campers must be one or greater."
msgstr "Le nombre maximum de campeurs doit être égal ou supérieur à un campeur." msgstr "Le nombre maximum de campeurs doit être égal ou supérieur à un campeur."
#: pkg/campsite/types/admin.go:466 #: pkg/campsite/types/admin.go:472
msgid "Minimum number of nights can not be empty." msgid "Minimum number of nights can not be empty."
msgstr "Le nombre minimum de nuits ne peut pas être vide." msgstr "Le nombre minimum de nuits ne peut pas être vide."
#: pkg/campsite/types/admin.go:467 #: pkg/campsite/types/admin.go:473
msgid "Minimum number of nights must be an integer." msgid "Minimum number of nights must be an integer."
msgstr "Le nombre minimum de nuits doit être un entier." msgstr "Le nombre minimum de nuits doit être un entier."
#: pkg/campsite/types/admin.go:468 #: pkg/campsite/types/admin.go:474
msgid "Minimum number of nights must be one or greater." msgid "Minimum number of nights must be one or greater."
msgstr "Le nombre minimum de nuits doit être supérieur ou égal à une nuit." msgstr "Le nombre minimum de nuits doit être supérieur ou égal à une nuit."
@ -1708,6 +1651,22 @@ msgstr "%s doit être %d ou plus."
msgid "%s must be at most %d." msgid "%s must be at most %d."
msgstr "%s doit être tout au plus %d." msgstr "%s doit être tout au plus %d."
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Feature to %s"
#~ msgstr "Traduire Caractéristique de type de camping en %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Carousel Slide to %s"
#~ msgstr "Convertir Glissière de carrousel de type camping en %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type Option to %s"
#~ msgstr "Traduire loption Type de camping en %s"
#~ msgctxt "title"
#~ msgid "Translate Campsite Type to %s"
#~ msgstr "Traduire Type de camping en %s"
#~ msgid "Starting from %s €/night" #~ msgid "Starting from %s €/night"
#~ msgstr "À partir de %s €/nuit" #~ msgstr "À partir de %s €/nuit"

View File

@ -28,17 +28,22 @@
{{ end }} {{ end }}
</h2> </h2>
{{ CSRFInput }} {{ CSRFInput }}
<fieldset> <fieldset x-data="{ lang: '{{ .DefaultLang }}' }">
{{ with .Media -}} {{ with .Media -}}
{{ template "media-picker" . }} {{ template "media-picker" . }}
{{- end }} {{- end }}
{{ with .Caption -}} {{ with .Caption -}}
<label> <fieldset>
{{( pgettext "Caption" "input")}}<br> <legend>{{( pgettext "Caption" "input")}}</legend>
<input type="text" name="{{ .Name }}" value="{{ .Val }}" {{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br> {{ template "error-attrs" . }}><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
</fieldset> </fieldset>
<footer> <footer>

View File

@ -24,7 +24,6 @@
<tr> <tr>
<th scope="col">{{( pgettext "Image" "header" )}}</th> <th scope="col">{{( pgettext "Image" "header" )}}</th>
<th scope="col">{{( pgettext "Caption" "header" )}}</th> <th scope="col">{{( pgettext "Caption" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
<th scope="col">{{( pgettext "Actions" "header" )}}</th> <th scope="col">{{( pgettext "Actions" "header" )}}</th>
</tr> </tr>
</thead> </thead>
@ -39,15 +38,6 @@
alt=""></a> alt=""></a>
</td> </td>
<td><a href="/admin/campsites/types/{{ $.TypeSlug }}/slides/{{ .ID }}">{{ .Caption }}</a></td> <td><a href="/admin/campsites/types/{{ $.TypeSlug }}/slides/{{ .ID }}">{{ .Caption }}</a></td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="/admin/campsites/types/{{ $.TypeSlug }}/slides/{{ $slide.ID }}/{{ .Language }}">{{ .Endonym }}</a>
{{ end }}
</td>
<td> <td>
<form data-hx-delete="/admin/campsites/types/{{ $.TypeSlug }}/slides/{{ .ID }}" <form data-hx-delete="/admin/campsites/types/{{ $.TypeSlug }}/slides/{{ .ID }}"
data-hx-confirm="{{ $confirm }}" data-hx-confirm="{{ $confirm }}"

View File

@ -1,35 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.slideL10nForm*/ -}}
{{printf (pgettext "Translate Campsite Type Carousel Slide to %s" "title") .Locale.Endonym }}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.slideL10nForm*/ -}}
<form data-hx-put="/admin/campsites/types/{{ .TypeSlug }}/slides/{{ .MediaID }}/{{ .Locale.Language }}">
<h2>
{{printf (pgettext "Translate Campsite Type Carousel Slide to %s" "title") .Locale.Endonym }}
</h2>
{{ CSRFInput }}
<fieldset>
{{ with .Caption -}}
<fieldset>
<legend>{{( pgettext "Caption" "input")}}</legend>
{{( gettext "Source:" )}} {{ .Source }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
{{ template "error-attrs" . }}><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
</fieldset>
<footer>
<button type="submit">{{( pgettext "Translate" "action" )}}</button>
</footer>
</form>
{{- end }}

View File

@ -28,7 +28,7 @@
{{ end }} {{ end }}
</h2> </h2>
{{ CSRFInput }} {{ CSRFInput }}
<fieldset> <fieldset x-data="{ lang: '{{ .DefaultLang }}' }">
{{ with $field := .Icon -}} {{ with $field := .Icon -}}
<fieldset class="icon-input"> <fieldset class="icon-input">
<legend>{{( pgettext "Icon" "input")}}</legend> <legend>{{( pgettext "Icon" "input")}}</legend>
@ -48,12 +48,17 @@
</fieldset> </fieldset>
{{- end }} {{- end }}
{{ with .Name -}} {{ with .Name -}}
<label> <fieldset>
{{( pgettext "Name" "input")}}<br> <legend>{{( pgettext "Name" "input")}}</legend>
<input type="text" name="{{ .Name }}" value="{{ .Val }}" {{ template "lang-selector" . }}
required {{ template "error-attrs" . }}><br> {{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
</fieldset> </fieldset>
<footer> <footer>

View File

@ -24,7 +24,6 @@
<tr> <tr>
<th scope="col" style="width: 1.5em"></th> <th scope="col" style="width: 1.5em"></th>
<th scope="col">{{( pgettext "Name" "header" )}}</th> <th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -35,15 +34,6 @@
<input type="hidden" name="feature_id" value="{{ .ID }}"> <input type="hidden" name="feature_id" value="{{ .ID }}">
</td> </td>
<td class="icon_{{ .Icon }}"><a href="{{ .URL }}">{{ .Name }}</a></td> <td class="icon_{{ .Icon }}"><a href="{{ .URL }}">{{ .Name }}</a></td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="{{ .URL }}">{{ .Endonym }}</a>
{{ end }}
</td>
</tr> </tr>
{{- end }} {{- end }}
</tbody> </tbody>

View File

@ -1,35 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureL10nForm*/ -}}
{{printf (pgettext "Translate Campsite Type Feature to %s" "title") .Locale.Endonym }}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureL10nForm*/ -}}
<form data-hx-put="/admin/campsites/types/{{ .TypeSlug }}/features/{{ .ID }}/{{ .Locale.Language }}">
<h2>
{{printf (pgettext "Translate Campsite Type Feature to %s" "title") .Locale.Endonym }}
</h2>
{{ CSRFInput }}
<fieldset>
{{ with .Name -}}
<fieldset>
<legend>{{( pgettext "Name" "input")}}</legend>
{{( gettext "Source:" )}} {{ .Source }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
required {{ template "error-attrs" . }}><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
</fieldset>
<footer>
<button type="submit">{{( pgettext "Translate" "action" )}}</button>
</footer>
</form>
{{- end }}

View File

@ -28,14 +28,19 @@
{{ end }} {{ end }}
</h2> </h2>
{{ CSRFInput }} {{ CSRFInput }}
<fieldset> <fieldset x-data="{ lang: '{{ .DefaultLang }}' }">
{{ with .Name -}} {{ with .Name -}}
<label> <fieldset>
{{( pgettext "Name" "input")}}<br> <legend>{{( pgettext "Name" "input")}}</legend>
<input type="text" name="{{ .Name }}" value="{{ .Val }}" {{ template "lang-selector" . }}
required {{ template "error-attrs" . }}><br> {{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label> </label>
{{- end}}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
{{ with .Min -}} {{ with .Min -}}
<label> <label>

View File

@ -23,7 +23,6 @@
<thead> <thead>
<tr> <tr>
<th scope="col">{{( pgettext "Name" "header" )}}</th> <th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -34,15 +33,6 @@
<input type="hidden" name="option_id" value="{{ .ID }}"> <input type="hidden" name="option_id" value="{{ .ID }}">
<a href="{{ .URL }}">{{ .Name }}</a> <a href="{{ .URL }}">{{ .Name }}</a>
</td> </td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="{{ .URL }}">{{ .Endonym }}</a>
{{ end }}
</td>
</tr> </tr>
{{- end }} {{- end }}
</tbody> </tbody>

View File

@ -1,35 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.optionL10nForm*/ -}}
{{printf (pgettext "Translate Campsite Type Option to %s" "title") .Locale.Endonym }}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.optionL10nForm*/ -}}
<form data-hx-put="/admin/campsites/types/{{ .TypeSlug }}/options/{{ .ID }}/{{ .Locale.Language }}">
<h2>
{{printf (pgettext "Translate Campsite Type Option to %s" "title") .Locale.Endonym }}
</h2>
{{ CSRFInput }}
<fieldset>
{{ with .Name -}}
<fieldset>
<legend>{{( pgettext "Name" "input")}}</legend>
{{( gettext "Source:" )}} {{ .Source }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
required {{ template "error-attrs" . }}><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
</fieldset>
<footer>
<button type="submit">{{( pgettext "Translate" "action" )}}</button>
</footer>
</form>
{{- end }}

View File

@ -28,7 +28,7 @@
{{ end }} {{ end }}
</h2> </h2>
{{ CSRFInput }} {{ CSRFInput }}
<fieldset> <fieldset x-data="{ lang: '{{ .DefaultLang }}' }">
{{ if .Slug }} {{ if .Slug }}
{{ with .Active -}} {{ with .Active -}}
<label> <label>
@ -42,12 +42,17 @@
<input type="hidden" name="{{ .Active.Name }}" value="true"> <input type="hidden" name="{{ .Active.Name }}" value="true">
{{ end }} {{ end }}
{{ with .Name -}} {{ with .Name -}}
<label> <fieldset>
{{( pgettext "Name" "input")}}<br> <legend>{{( pgettext "Name" "input")}}</legend>
<input type="text" name="{{ .Name }}" value="{{ .Val }}" {{ template "lang-selector" . }}
required {{ template "error-attrs" . }}><br> {{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
{{ with .Media -}} {{ with .Media -}}
{{ template "media-picker" . }} {{ template "media-picker" . }}
@ -95,32 +100,56 @@
</fieldset> </fieldset>
{{- end }} {{- end }}
{{ with .Spiel -}} {{ with .Spiel -}}
<label> <fieldset>
{{( pgettext "Spiel" "input")}}<br> <legend>{{( pgettext "Spiel" "input")}}</legend>
<textarea class="html" name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br> {{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<textarea class="html"
name="{{ $input.Name }}" {{ template "error-attrs" . }}>{{ $input.Val }}</textarea><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
{{ with .Info -}} {{ with .Info -}}
<label> <fieldset>
{{( pgettext "Info" "input")}}<br> <legend>{{( pgettext "Info" "input")}}<br></legend>
<textarea class="html" name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br> {{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
{{ with .Facilities -}} {{ with .Facilities -}}
<label> <fieldset>
{{( pgettext "Facilities" "input")}}<br> <legend>{{( pgettext "Facilities" "input")}}<br></legend>
<textarea class="html" name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br> {{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
{{ with .Description -}} {{ with .Description -}}
<label> <fieldset>
{{( pgettext "Description" "input")}}<br> <legend>{{( pgettext "Description" "input")}}<br></legend>
<textarea class="html" name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br> {{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label> </label>
{{- end }}
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset>
{{- end }} {{- end }}
</fieldset> </fieldset>
<footer> <footer>

View File

@ -23,7 +23,6 @@
<thead> <thead>
<tr> <tr>
<th scope="col">{{( pgettext "Name" "header" )}}</th> <th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
<th scope="col">{{( pgettext "Features" "header" )}}</th> <th scope="col">{{( pgettext "Features" "header" )}}</th>
<th scope="col">{{( pgettext "Options" "header" )}}</th> <th scope="col">{{( pgettext "Options" "header" )}}</th>
<th scope="col">{{( pgettext "Carousel" "header" )}}</th> <th scope="col">{{( pgettext "Carousel" "header" )}}</th>
@ -38,15 +37,6 @@
<input type="hidden" name="slug" value="{{ .Slug }}"> <input type="hidden" name="slug" value="{{ .Slug }}">
<a href="/admin/campsites/types/{{ .Slug }}">{{ .Name }}</a> <a href="/admin/campsites/types/{{ .Slug }}">{{ .Name }}</a>
</td> </td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="/admin/campsites/types/{{ $type.Slug }}/{{ .Language }}">{{ .Endonym }}</a>
{{ end }}
</td>
<td> <td>
<a href="/admin/campsites/types/{{ .Slug }}/features">{{( pgettext "Edit Features" "action" )}}</a> <a href="/admin/campsites/types/{{ .Slug }}/features">{{( pgettext "Edit Features" "action" )}}</a>
</td> </td>

View File

@ -1,87 +0,0 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.typeL10nForm*/ -}}
{{printf (pgettext "Translate Campsite Type to %s" "title") .Locale.Endonym }}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.typeL10nForm*/ -}}
<form data-hx-put="/admin/campsites/types/{{ .Slug }}/{{ .Locale.Language }}">
<h2>
{{printf (pgettext "Translate Campsite Type to %s" "title") .Locale.Endonym }}
</h2>
{{ CSRFInput }}
<fieldset>
{{ with .Name -}}
<fieldset>
<legend>{{( pgettext "Name" "input")}}</legend>
{{( gettext "Source:" )}} {{ .Source }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
required {{ template "error-attrs" . }}><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Spiel -}}
<fieldset>
<legend{{( pgettext "Spiel" "input")}}></legend>
{{( gettext "Source:" )}}<br>
{{ .Source | raw }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Info -}}
<fieldset>
<legend{{( pgettext "Info" "input")}}></legend>
{{( gettext "Source:" )}}<br>
{{ .Source | raw }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Facilities -}}
<fieldset>
<legend{{( pgettext "Facilities" "input")}}></legend>
{{( gettext "Source:" )}}<br>
{{ .Source | raw }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Description -}}
<fieldset>
<legend{{( pgettext "Description" "input")}}></legend>
{{( gettext "Source:" )}}<br>
{{ .Source | raw }}<br>
<label>
{{( pgettext "Translation:" "input" )}}
<textarea class="html"
name="{{ .Name }}" {{ template "error-attrs" . }}>{{ .Val }}</textarea><br>
</label>
{{ template "error-message" . }}
</fieldset>
{{- end }}
</fieldset>
<footer>
<button type="submit">{{( pgettext "Translate" "action" )}}</button>
</footer>
</form>
{{- end }}

View File

@ -41,3 +41,12 @@
{{ template "error-message" . }} {{ template "error-message" . }}
</fieldset> </fieldset>
{{- end }} {{- end }}
{{ define "lang-selector" -}}
<div class="lang-selector" role="toolbar">
{{ range $lang, $input := . -}}
<button :aria-pressed="lang === '{{ $lang }}'"
@click.prevent="lang = '{{ $lang }}'">{{ $lang }}</button>
{{- end }}
</div>
{{- end }}