szabadpalya/api/internal/hu/format.go

94 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package hu holds the Hungarian-locale formatting the server needs for share
// metadata and share images. The browser keeps using Intl for everything it
// renders itself; this exists because og: tags and PNGs are produced here.
package hu
import (
"strconv"
"strings"
"time"
"unicode"
)
// groupSeparator is U+00A0, which is what Intl.NumberFormat("hu-HU") emits.
// A plain space here would make the share card disagree with the page.
const groupSeparator = " "
func FormatNumber(n int) string {
s := strconv.Itoa(n)
neg := strings.HasPrefix(s, "-")
s = strings.TrimPrefix(s, "-")
var b strings.Builder
for i, r := range s {
if i > 0 && (len(s)-i)%3 == 0 {
b.WriteString(groupSeparator)
}
b.WriteRune(r)
}
if neg {
return "-" + b.String()
}
return b.String()
}
// FormatHUF renders 1351600 as "1 351 600 Ft".
func FormatHUF(n int) string { return FormatNumber(n) + " Ft" }
func ProgressPct(raised, goal int) int {
if goal <= 0 {
return 0
}
return int(float64(raised)/float64(goal)*100 + 0.5)
}
// DaysLeft counts whole days until the end of the closing day in Budapest —
// SPEC.md section 6. Never negative: a finished campaign has zero days left,
// not a negative countdown.
func DaysLeft(endsAt string, loc *time.Location, now time.Time) int {
d, err := time.ParseInLocation("2006-01-02", endsAt, loc)
if err != nil {
return 0
}
end := d.Add(24*time.Hour - time.Second)
diff := end.Sub(now)
if diff <= 0 {
return 0
}
days := int(diff / (24 * time.Hour))
if diff%(24*time.Hour) > 0 {
days++
}
return days
}
var accentFolds = map[rune]rune{
'á': 'a', 'é': 'e', 'í': 'i', 'ó': 'o', 'ö': 'o', 'ő': 'o',
'ú': 'u', 'ü': 'u', 'ű': 'u',
}
// Slugify mirrors the browser-side helper so a slug the editor previews is the
// slug that gets stored.
func Slugify(input string) string {
var b strings.Builder
for _, r := range strings.ToLower(input) {
if folded, ok := accentFolds[r]; ok {
r = folded
}
if (r >= 'a' && r <= 'z') || unicode.IsDigit(r) {
b.WriteRune(r)
} else {
b.WriteRune('-')
}
}
slug := b.String()
for strings.Contains(slug, "--") {
slug = strings.ReplaceAll(slug, "--", "-")
}
slug = strings.Trim(slug, "-")
if len(slug) > 80 {
slug = strings.Trim(slug[:80], "-")
}
return slug
}