I do not want to use floats in the Go lang application, because it is not supposed to do anything with these values other than to print and retrieve them from the user; all computations will be performed by PostgreSQL in cents. That means i have to “convert” from the price format that users expect to see (e.g., 1.234,56) to cents (e.g., 123456) and back when passing data between Go and PostgreSQL, and that conversion depends on the currency’s decimal places. At first i did everything in Go, but saw that i would need to do it in a loop when retrieving the list of products, and immediately knew it was a mistake—i needed a PL/pgSQL function for that. I still need to convert from string to float, however, when printing the value to the user. Because the string representation is in C, but i need to format it according to the locale with golang/x/text. That package has the information of how to correctly format numbers, but it is in an internal package that i can not use, and numbers.Digit only accepts numeric types, not a string.
85 lines
2.4 KiB
Go
85 lines
2.4 KiB
Go
package pkg
|
|
|
|
import (
|
|
"fmt"
|
|
"golang.org/x/text/message"
|
|
"golang.org/x/text/number"
|
|
"html/template"
|
|
"io"
|
|
"math"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
const overrideMethodName = "_method"
|
|
|
|
func templateFile(name string) string {
|
|
return "web/template/" + name
|
|
}
|
|
|
|
func mustRenderTemplate(wr io.Writer, r *http.Request, layout string, filename string, data interface{}) {
|
|
locale := getLocale(r)
|
|
company := getCompany(r)
|
|
user := getUser(r)
|
|
t := template.New(filename)
|
|
t.Funcs(template.FuncMap{
|
|
"gettext": locale.Get,
|
|
"pgettext": locale.GetC,
|
|
"currentLocale": func() string {
|
|
return locale.Language.String()
|
|
},
|
|
"companyURI": func(uri string) string {
|
|
return companyURI(company, uri)
|
|
},
|
|
"formatPrice": func(price string) string {
|
|
p := message.NewPrinter(locale.Language)
|
|
f, err := strconv.ParseFloat(price, 64)
|
|
if err != nil {
|
|
f = math.NaN()
|
|
}
|
|
return p.Sprintf("%.*f", company.DecimalDigits, number.Decimal(f))
|
|
},
|
|
"csrfToken": func() template.HTML {
|
|
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`, csrfTokenField, user.CsrfToken))
|
|
},
|
|
"addInputAttr": func(attr string, field *InputField) *InputField {
|
|
field.Attributes = append(field.Attributes, template.HTMLAttr(attr))
|
|
return field
|
|
},
|
|
"addSelectAttr": func(attr string, field *SelectField) *SelectField {
|
|
field.Attributes = append(field.Attributes, template.HTMLAttr(attr))
|
|
return field
|
|
},
|
|
"deleteMethod": func() template.HTML {
|
|
return overrideMethodField(http.MethodDelete)
|
|
},
|
|
"putMethod": func() template.HTML {
|
|
return overrideMethodField(http.MethodPut)
|
|
},
|
|
})
|
|
if _, err := t.ParseFiles(templateFile(filename), templateFile(layout), templateFile("form.gohtml")); err != nil {
|
|
panic(err)
|
|
}
|
|
if err := t.ExecuteTemplate(wr, layout, data); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func companyURI(company *Company, uri string) string {
|
|
if company == nil {
|
|
return uri
|
|
}
|
|
return "/company/" + company.Slug + uri
|
|
}
|
|
|
|
func overrideMethodField(method string) template.HTML {
|
|
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`, overrideMethodName, method))
|
|
}
|
|
func mustRenderAppTemplate(w io.Writer, r *http.Request, filename string, data interface{}) {
|
|
mustRenderTemplate(w, r, "app.gohtml", filename, data)
|
|
}
|
|
|
|
func mustRenderWebTemplate(w io.Writer, r *http.Request, filename string, data interface{}) {
|
|
mustRenderTemplate(w, r, "web.gohtml", filename, data)
|
|
}
|