diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app.go | 16 | ||||
-rw-r--r-- | src/email/email.go | 14 | ||||
-rw-r--r-- | src/http.go | 6 | ||||
-rw-r--r-- | src/i18n/i18n.go | 68 | ||||
-rw-r--r-- | src/templates.go | 6 | ||||
-rw-r--r-- | src/templates/coins-designs-ee.html.tmpl | 155 | ||||
-rw-r--r-- | src/templates/language.html.tmpl | 5 |
7 files changed, 221 insertions, 49 deletions
diff --git a/src/app.go b/src/app.go new file mode 100644 index 0000000..7b3d905 --- /dev/null +++ b/src/app.go @@ -0,0 +1,16 @@ +package app + +import ( + "os" + "syscall" + + "git.thomasvoss.com/euro-cash.eu/pkg/atexit" + . "git.thomasvoss.com/euro-cash.eu/pkg/try" +) + +func Restart() { + path := Try2(os.Executable()) + atexit.Exec() + Try(syscall.Exec(path, append([]string{path}, os.Args[1:]...), + os.Environ())) +} diff --git a/src/email/email.go b/src/email/email.go index 33b30e0..a1f7f0b 100644 --- a/src/email/email.go +++ b/src/email/email.go @@ -6,6 +6,8 @@ import ( "crypto/tls" "fmt" "math/rand/v2" + "log" + "errors" "net/smtp" "strconv" "time" @@ -29,14 +31,20 @@ Message-ID: <%s> %s` -func ServerError(fault error) error { +func Send(subject, body string) { + if err := send(subject, body); err != nil { + log.Print(err) + } +} + +func send(subject, body string) error { if Config.Disabled { - return fault + return errors.New(body) } msgid := strconv.FormatInt(rand.Int64(), 10) + "@" + Config.Host msg := fmt.Sprintf(emailTemplate, Config.FromAddr, Config.ToAddr, - "Error Report", time.Now().Format(time.RFC1123Z), msgid, fault) + subject, time.Now().Format(time.RFC1123Z), msgid, body) tlsConfig := &tls.Config{ InsecureSkipVerify: false, diff --git a/src/http.go b/src/http.go index b785bca..b0d5bcd 100644 --- a/src/http.go +++ b/src/http.go @@ -179,11 +179,7 @@ func setUserLanguage(w http.ResponseWriter, r *http.Request) { func throwError(status int, err error, w http.ResponseWriter, r *http.Request) { w.WriteHeader(status) - go func() { - if err := email.ServerError(err); err != nil { - log.Println(err) - } - }() + go email.Send("Server Error", err.Error()) errorTmpl.Execute(w, struct { Code int Msg string diff --git a/src/i18n/i18n.go b/src/i18n/i18n.go index b996681..cf82630 100644 --- a/src/i18n/i18n.go +++ b/src/i18n/i18n.go @@ -72,7 +72,7 @@ var ( Name: "Ελληνικά", DateFormat: "2/1/2006", Eurozone: true, - Enabled: true, + Enabled: false, GroupSeparator: '.', DecimalSeparator: ',', MonetaryPre: [2]string{"", "-"}, @@ -212,7 +212,7 @@ var ( Name: "Nederlands", DateFormat: "2-1-2006", Eurozone: true, - Enabled: true, + Enabled: false, GroupSeparator: '.', DecimalSeparator: ',', MonetaryPre: [2]string{"€ ", "€ -"}, @@ -254,7 +254,7 @@ var ( Name: "Svenska", DateFormat: "2006-01-02", Eurozone: true, - Enabled: false, + Enabled: true, GroupSeparator: ' ', DecimalSeparator: ',', MonetaryPre: [2]string{"", "-"}, @@ -266,23 +266,13 @@ var ( Name: "Български", DateFormat: "2.01.2006 г.", Eurozone: false, /* TODO(2026): Set to true */ - Enabled: true, + Enabled: false, GroupSeparator: ' ', DecimalSeparator: ',', MonetaryPre: [2]string{"", "-"}, MonetaryPost: " €", }, { - Bcp: "en-US", - Name: "English (US)", - DateFormat: "1/2/2006", - Eurozone: false, - Enabled: false, - GroupSeparator: ',', - DecimalSeparator: '.', - MonetaryPre: [2]string{"€", "-€"}, - }, - { Bcp: "ro", Name: "Română", DateFormat: "02.01.2006", @@ -305,9 +295,6 @@ var ( MonetaryPost: " €", }, } - /* Map of language codes to printers. We do this instead of just - using language.MustParse() directly so that we can easily see if a - language is supported or not. */ Printers map[string]Printer = make(map[string]Printer, len(locales)) DefaultPrinter Printer ) @@ -317,7 +304,9 @@ func Init() { if !li.Enabled { continue } - Printers[li.Bcp] = Printer{li, gotext.NewLocale("po", li.Bcp)} + gl := gotext.NewLocale("po", li.Bcp) + gl.AddDomain("messages") + Printers[li.Bcp] = Printer{li, gl} } DefaultPrinter = Printers["en"] @@ -340,10 +329,35 @@ func (l LocaleInfo) Language() string { return l.Bcp[:2] } +func (p Printer) Itoa(n int) string { + var bob strings.Builder + writeInt(&bob, n, p.LocaleInfo) + return bob.String() +} + +func (p Printer) Ftoa(n float64) string { + var bob strings.Builder + writeFloat(&bob, n, p.LocaleInfo) + return bob.String() +} + +func (p Printer) Mitoa(n int) string { + var bob strings.Builder + sprintfm(p.LocaleInfo, &bob, n) + return bob.String() +} + +func (p Printer) Mftoa(n float64) string { + var bob strings.Builder + sprintfm(p.LocaleInfo, &bob, n) + return bob.String() +} + func (p Printer) Sprintf(format string, args ...map[string]any) string { var bob strings.Builder vars := map[string]any{ "-": "a", + "Null": "", } for _, arg := range args { maps.Copy(vars, arg) @@ -410,9 +424,9 @@ func sprintfGeneric(li LocaleInfo, bob *strings.Builder, v any) error { case time.Time: htmlesc(bob, v.(time.Time).Format(li.DateFormat)) case int: - writeInt(bob, v.(int), li.GroupSeparator) + writeInt(bob, v.(int), li) case float64: - writeFloat(bob, v.(float64), li.GroupSeparator, li.DecimalSeparator) + writeFloat(bob, v.(float64), li) case string: htmlesc(bob, v.(string)) default: @@ -474,12 +488,12 @@ func sprintfm(li LocaleInfo, bob *strings.Builder, v any) error { case int: n := v.(int) htmlesc(bob, li.MonetaryPre[btoi(n >= 0)]) - writeInt(bob, abs(n), li.GroupSeparator) + writeInt(bob, abs(n), li) htmlesc(bob, li.MonetaryPost) case float64: n := v.(float64) htmlesc(bob, li.MonetaryPre[btoi(n >= 0)]) - writeFloat(bob, abs(n), li.GroupSeparator, li.DecimalSeparator) + writeFloat(bob, abs(n), li) htmlesc(bob, li.MonetaryPost) default: return errors.New("TODO") @@ -496,7 +510,7 @@ func sprintfr(li LocaleInfo, bob *strings.Builder, v any) error { return nil } -func writeInt(bob *strings.Builder, num int, sep rune) { +func writeInt(bob *strings.Builder, num int, li LocaleInfo) { s := fmt.Sprintf("%d", num) if s[0] == '-' { bob.WriteByte('-') @@ -511,13 +525,13 @@ func writeInt(bob *strings.Builder, num int, sep rune) { c++ bob.WriteByte(s[i]) if c == 3 && i+1 < n { - bob.WriteRune(sep) + bob.WriteRune(li.GroupSeparator) c = 0 } } } -func writeFloat(bob *strings.Builder, num float64, tsep, dsep rune) { +func writeFloat(bob *strings.Builder, num float64, li LocaleInfo) { s := fmt.Sprintf("%.2f", num) if s[0] == '-' { bob.WriteByte('-') @@ -533,12 +547,12 @@ func writeFloat(bob *strings.Builder, num float64, tsep, dsep rune) { c++ bob.WriteByte(s[i]) if c == 3 && i+1 < n { - bob.WriteRune(tsep) + bob.WriteRune(li.GroupSeparator) c = 0 } } - bob.WriteRune(dsep) + bob.WriteRune(li.DecimalSeparator) bob.WriteString(s[n+1:]) } diff --git a/src/templates.go b/src/templates.go index 20fcf79..353c755 100644 --- a/src/templates.go +++ b/src/templates.go @@ -46,6 +46,12 @@ func BuildTemplates(dir fs.FS, debugp bool) { buildAndSetTemplate(dir, name) if debugp { go watch.FileFS(dir, name, func() { + defer func() { + if p := recover(); p != nil { + log.Print(p) + } + }() + buildAndSetTemplate(dir, name) log.Printf("Template ‘%s’ updated\n", name) }) diff --git a/src/templates/coins-designs-ee.html.tmpl b/src/templates/coins-designs-ee.html.tmpl index 0624931..a6a62e9 100644 --- a/src/templates/coins-designs-ee.html.tmpl +++ b/src/templates/coins-designs-ee.html.tmpl @@ -1,18 +1,155 @@ {{ define "content" }} <header> {{ template "navbar" . }} - <h1>{{ .Get "German Euro Coin Designs" }}</h1> + <h1>{{ .Get "Estonian Euro Coin Designs" }}</h1> </header> <main> - <p> - {{ .Get "The Estonian euro coins all feature the same design across all eight denominations. The country’s outline is displayed above the text “EESTI”, the country’s name in its own language." }} - </p> - <div class="design-container"> - <img + <div class="design-container"> + <img alt="{{ .Get `Estonian €1 coin` }}" src="/designs/ee-100-1.avif" > - </div> -</main> -{{ end }} + </div> + <p> + {{ .Get "The Estonian euro coins feature the same design across all eight denominations. The country’s outline is prominently displayed above the country’s name in Estonian (‘{EstonianStart:r}EESTI{EstonianEnd:E}’)." + (map "EstonianStart" `<span lang="et"><em>` "EstonianEnd" "em,span") }} + </p> + <p> + {{ .Get "The design of the Estonian euro coins was chosen as part of a {EVLink:L}Eurovision{-:E}-style public televote where it competed and won against 9 other designs." + (map "EVLink" "https://en.wikipedia.org/wiki/Eurovision_Song_Contest" ) }} + </p> + <p> + {{ .Get "In June 2024 a public design competition was announced with a deadline for the 19th of October. In total 134 designs were submitted by the deadline and 10 designs were selected by a jury. These 10 designs were then voted on in a public vote over the course of one week. In total 45,453 people voted and the current design won with a total of 12,482 votes (27.46%)." }} + </p> + <p> + {{ .Get "The winner of the contest was awarded 50,000 KR (€3,196) while the other finalists were each awarded 20,000 KR (€1,278)." }} + </p> + + <!-- TODO: Add images of the other designs: https://web.archive.org/web/20070704210956/http://www.eestipank.info/pub/et/majandus/euroopaliit/euro/kavand/_1kava.html --> + <!-- Good description of one of the designs: http://www.worldofcoins.eu/forum/index.php/topic,21902.15.html?PHPSESSID=pc4qnnd3ng4etv8fp75u41erb1 --> + <table> + <thead> + <tr> + <th data-numeric style="width: 1%">{{ .Get "Position" }}</th> + <th>{{ .Get "Name" }}<br>{{ .Get "Translation" }}</th> + <th>{{ .Get "Author(s)" }}</th> + <th data-numeric>{{ .Get "Votes" }}</th> + <th data-numeric>{{ .Get "Votes (%)" }}</th> + </tr> + </thead> + <tbody> + {{ $args := (map "Break" "<br>") }} + <tr> + <td data-numeric>1</td> + {{/* TRANSLATORS: This is a place name. If you’re translating for a latin-script language, translate this to ‘{Null}’, otherwise transliterate this into your respective alphabet. */}} + <td>Hara 2{{ .Get "{Break:r}Hara 2" $args }}</td> + <td>{{ .Get "Lembit Lõhmus" }}</td> + <td data-numeric>{{ .Printer.Itoa 12482 }}</td> + <td data-numeric>{{ .Printer.Ftoa 27.46 }}</td> + </tr> + <tr> + <td data-numeric>2</td> + <td> + <span lang="et">Järjepidevus</span> + {{/* TRANSLATORS: Estonian translators should replace the entire translation with ‘{Null}’ */}} + {{ .Get "{Break:r}Consistency" $args }} + </td> + <td>{{ .Get "Tiit Jürna" }}</td> + <td data-numeric>{{ .Printer.Itoa 7477 }}</td> + <td data-numeric>{{ .Printer.Ftoa 16.45 }}</td> + </tr> + <tr> + <td data-numeric>3</td> + <td> + <span lang="la">In corpore</span> + {{ .Get "{Break:r}In the Body" $args }} + </td> + <td>{{ .Get "Jaan Meristo" }}</td> + <td data-numeric>{{ .Printer.Itoa 7284 }}</td> + <td data-numeric>{{ .Printer.Ftoa 16.03 }}</td> + </tr> + <tr> + <td data-numeric>4</td> + <td> + Tomson 5791 + {{/* TRANSLATORS: This name. If you’re translating for a latin-script language, translate this to ‘{Null}’, otherwise transliterate this into your respective alphabet. */}} + {{ .Get "{Break:r}Tomson 5791" $args }} + </td> + <td>{{ .Get "Taavi Torim" }}</td> + <td data-numeric>{{ .Printer.Itoa 6219 }}</td> + <td data-numeric>{{ .Printer.Ftoa 13.68 }}</td> + </tr> + <tr> + <td data-numeric>5</td> + <td> + <span lang="et">Eesti keel</span> + {{/* TRANSLATORS: Estonian translators should replace the entire translation with ‘{Null}’ */}} + {{ .Get "{Break:r}Estonian" $args }} + </td> + <td>{{ .Get "Jaak Peep, Villem Valme" }}</td> + <td data-numeric>{{ .Printer.Itoa 5997 }}</td> + <td data-numeric>{{ .Printer.Ftoa 13.19 }}</td> + </tr> + <tr> + <td data-numeric>6</td> + <td>261948</td> + <td>{{ .Get "Mai Järmut, Villu Järmut" }}</td> + <td data-numeric>{{ .Printer.Itoa 3036 }}</td> + <td data-numeric>{{ .Printer.Ftoa 6.68 }}</td> + </tr> + <tr> + <td data-numeric>7</td> + <td> + <span lang="et">Linnutee</span> + {{/* TRANSLATORS: Estonian translators should replace the entire translation with ‘{Null}’ */}} + {{ .Get "{Break:r}Bird Road" $args }} + </td> + <td>{{ .Get "Tiit Jürna" }}</td> + <td data-numeric>{{ .Printer.Itoa 1323 }}</td> + <td data-numeric>{{ .Printer.Ftoa 2.91 }}</td> + </tr> + <tr> + <td data-numeric>8</td> + <td> + <span lang="et">Leopardid-2</span> + {{/* TRANSLATORS: Estonian translators should replace the entire translation with ‘{Null}’ */}} + {{ .Get "{Break:r}Leopards-2" $args }} + </td> + <td>{{ .Get "Jaarno Ester" }}</td> + <td data-numeric>{{ .Printer.Itoa 759 }}</td> + <td data-numeric>{{ .Printer.Ftoa 1.67 }}</td> + </tr> + <tr> + <td data-numeric>9</td> + <td> + Nova + {{/* TRANSLATORS: This name. If you’re translating for a latin-script language, translate this to ‘{Null}’, otherwise transliterate this into your respective alphabet. */}} + {{ .Get "{Break:r}Nova" $args }} + </td> + <td>{{ .Get "Rene Haljasmäe" }}</td> + <td data-numeric>{{ .Printer.Itoa 498 }}</td> + <td data-numeric>{{ .Printer.Ftoa 1.1 }}</td> + </tr> + <tr> + <td data-numeric>10</td> + <td> + <span lang="et">Lill rukkis</span> + {{/* TRANSLATORS: Estonian translators should replace the entire translation with ‘{Null}’ */}} + {{ .Get "{Break:r}A Flower in the Rye" $args }} + </td> + <td>{{ .Get "Margus Kadarik" }}</td> + <td data-numeric>{{ .Printer.Itoa 378 }}</td> + <td data-numeric>{{ .Printer.Ftoa 0.83 }}</td> + </tr> + </tbody> + <tfoot> + <tr> + <th colspan="3">{{ .Get "Total" }}</th> + <th data-numeric>{{ .Printer.Itoa 45453 }}</th> + <th data-numeric>{{ .Printer.Ftoa 100.0 }}</th> + </tr> + </tfoot> + </table> +</main> +{{ end }}
\ No newline at end of file diff --git a/src/templates/language.html.tmpl b/src/templates/language.html.tmpl index f4b240a..13a8e85 100644 --- a/src/templates/language.html.tmpl +++ b/src/templates/language.html.tmpl @@ -7,11 +7,6 @@ <p> {{ .Get "Select your preferred language to use on the site." }} </p> - <p> - If you are an American user, it’s suggested that you select - American English instead of British English. This will ensure that - dates will be formatted with the month before the day. - </p> <hr /> <h2>{{ .Get "Eurozone Languages" }}</h2> {{ template "langgrid" true }} |