diff --git a/go.mod b/go.mod
index ebc9bc5..4f53f03 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
github.com/labstack/echo/v4 v4.13.4
github.com/labstack/gommon v0.4.2
github.com/sirupsen/logrus v1.9.3
+ golang.org/x/text v0.30.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -30,6 +31,5 @@ require (
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.11.0 // indirect
)
diff --git a/go.sum b/go.sum
index 4a11746..017d727 100644
--- a/go.sum
+++ b/go.sum
@@ -63,8 +63,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
-golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
+golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
+golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
diff --git a/ui/dialog.go b/ui/dialog.go
index 3104df0..547da8b 100644
--- a/ui/dialog.go
+++ b/ui/dialog.go
@@ -170,8 +170,13 @@ func (d *Dialog) Render(ctxt AmContext) (string, any, error) {
if fld.Required {
required = true // display the "required" blurb
}
- if fld.Type == "password" { // clear all "password" fields as a security measure
+ switch fld.Type {
+ case "password": // clear all "password" fields as a security measure
d.Fields[i].Value = ""
+ case "localelist": // default locale to en-US if we don't have one
+ if d.Fields[i].Value == "" {
+ d.Fields[i].Value = "en-US"
+ }
}
}
ctxt.VarMap().Set("amsterdam_required", required)
diff --git a/ui/languages.txt b/ui/languages.txt
new file mode 100644
index 0000000..9bc576e
--- /dev/null
+++ b/ui/languages.txt
@@ -0,0 +1,150 @@
+ja-JP
+es-PE
+en
+es-PA
+sr-BA
+mk
+es-GT
+ar-AE
+no-NO
+sq-AL
+bg
+ar-IQ
+ar-YE
+hu
+pt-PT
+el-CY
+ar-QA
+mk-MK
+sv
+de-CH
+en-US
+fi-FI
+is
+cs
+en-MT
+sl-SI
+sk-SK
+it
+tr-TR
+zh
+th
+ar-SA
+no
+en-GB
+sr-CS
+lt
+ro
+en-NZ
+nn-NO
+lt-LT
+es-NI
+nl
+ga-IE
+fr-BE
+es-ES
+ar-LB
+ko
+fr-CA
+et-EE
+ar-KW
+sr-RS
+es-US
+es-MX
+ar-SD
+in-ID
+ru
+lv
+es-UY
+lv-LV
+iw
+pt-BR
+ar-SY
+hr
+et
+es-DO
+fr-CH
+hi-IN
+es-VE
+ar-BH
+en-PH
+ar-TN
+fi
+de-AT
+es
+nl-NL
+es-EC
+zh-TW
+ar-JO
+be
+is-IS
+es-CO
+es-CR
+es-CL
+ar-EG
+en-ZA
+th-TH
+el-GR
+it-IT
+ca
+hu-HU
+fr
+en-IE
+uk-UA
+pl-PL
+fr-LU
+nl-BE
+en-IN
+ca-ES
+ar-MA
+es-BO
+en-AU
+sr
+zh-SG
+pt
+uk
+es-SV
+ru-RU
+ko-KR
+vi
+ar-DZ
+vi-VN
+sr-ME
+sq
+ar-LY
+ar
+zh-CN
+be-BY
+zh-HK
+ja
+iw-IL
+bg-BG
+in
+mt-MT
+es-PY
+sl
+fr-FR
+cs-CZ
+it-CH
+ro-RO
+es-PR
+en-CA
+de-DE
+ga
+de-LU
+de
+es-AR
+sk
+ms-MY
+hr-HR
+en-SG
+da
+mt
+pl
+ar-OM
+tr
+el
+ms
+sv-SE
+da-DK
+es-HN
\ No newline at end of file
diff --git a/ui/templates.go b/ui/templates.go
index 5275508..0e71877 100644
--- a/ui/templates.go
+++ b/ui/templates.go
@@ -22,6 +22,7 @@ import (
"sync"
"time"
"unicode"
+ _ "unsafe" // HACK HACK HACK
"git.erbosoft.com/amy/amsterdam/config"
"github.com/CloudyKit/jet/v6"
@@ -30,6 +31,8 @@ import (
"github.com/biter777/countries"
"github.com/labstack/echo/v4"
log "github.com/sirupsen/logrus"
+ "golang.org/x/text/language"
+ "golang.org/x/text/language/display"
)
//go:embed views/*
@@ -38,6 +41,56 @@ var static_views embed.FS
// views is the main Jet template repository.
var views *jet.Set
+//go:embed languages.txt
+var knownLanguages string
+
+// Language is a type for a list of all supportred languages.
+type Language struct {
+ Tag string // the BCP 47 tag, such as "en-US"
+ Name string // the human-readable name, like "American English"
+}
+
+// cachedLanguageList is the cached language list.
+var cachedLanguageList []Language = nil
+
+// languageListMutex controls access to internalGetLanguageList.
+var languageListMutex sync.Mutex
+
+// internalGetLanguageList is a wrapper around "allTags" that sorts it by language name.
+func internalGetLanguageList() []Language {
+ languageListMutex.Lock()
+ defer languageListMutex.Unlock()
+ if cachedLanguageList == nil {
+ langs := strings.Split(knownLanguages, "\n")
+ enNamer := display.English.Tags()
+ cachedLanguageList = make([]Language, 0, len(langs))
+ for _, l := range langs {
+ tag, err := language.Parse(l)
+ if err == nil {
+ cachedLanguageList = append(cachedLanguageList, Language{
+ Tag: tag.String(),
+ Name: enNamer.Name(tag),
+ })
+ } else {
+ log.Errorf("*** PUKE on parsing language tag %s: %v", l, err)
+ }
+ }
+
+ slices.SortFunc(cachedLanguageList, func(a Language, b Language) int {
+ return strings.Compare(a.Name, b.Name)
+ })
+ log.Infof("internalGetLanguageList() loaded %d languages", len(cachedLanguageList))
+ }
+ return cachedLanguageList
+}
+
+// getLanguageList is a wrapper around the list of languages that can be added to the template context.
+func getLanguageList(a jet.Arguments) reflect.Value {
+ rc := internalGetLanguageList()
+ log.Infof("GetLanguageList() provides %d items", len(rc))
+ return reflect.ValueOf(rc)
+}
+
// cachedCountryList is the cached country list after sorting.
var cachedCountryList []countries.CountryCode = nil
@@ -170,6 +223,7 @@ func SetupTemplates() {
views.AddGlobal("AmsterdamCopyright", config.AMSTERDAM_COPYRIGHT)
views.AddGlobal("GlobalConfig", config.GlobalConfig)
views.AddGlobalFunc("GetCountryList", getCountryList)
+ views.AddGlobalFunc("GetLanguageList", getLanguageList)
views.AddGlobalFunc("GetMonthList", getMonthList)
views.AddGlobalFunc("MakeIntRange", makeIntRange)
views.AddGlobalFunc("MakeYearRange", makeYearRange)
@@ -179,8 +233,9 @@ func SetupTemplates() {
return reflect.ValueOf(CapitalizeString(s))
})
- // preload the country list in the background
+ // preload the lists in the background
go internalGetCountryList()
+ go internalGetLanguageList()
}
// TemplateRenderer is the Renderer instance set into the Echo context at creation time, to render Jet templates.
diff --git a/ui/views/dialog.jet b/ui/views/dialog.jet
index 7da4c24..b7ddf32 100644
--- a/ui/views/dialog.jet
+++ b/ui/views/dialog.jet
@@ -130,9 +130,12 @@
{{ .Caption }}{{ if .Subcaption != "" }} {{ .Subcaption }}{{ end }}
{{ if .Required }}*{{ end }}
+ {{ v := .Value }}
{{ else if .Type == "tzlist" }}