Raw
 1package web
 2
 3import (
 4	"errors"
 5	"fmt"
 6	"html/template"
 7	"strings"
 8
 9	"tug/internal/transport/web/text"
10)
11
12type Ident string
13
14const identMarker = "{ident}"
15
16var errNoMarker = errors.New("catalog sentence has no identifier marker")
17
18func identHTML(v Ident) template.HTML {
19	return template.HTML(`<code class="ident">` + template.HTMLEscapeString(string(v)) + `</code>`)
20}
21
22func interpolate(sentence string, v Ident) (template.HTML, error) {
23	before, after, ok := strings.Cut(sentence, identMarker)
24	if !ok || strings.Contains(after, identMarker) {
25		return "", errNoMarker
26	}
27	return template.HTML(template.HTMLEscapeString(before)) + identHTML(v) + template.HTML(template.HTMLEscapeString(after)), nil
28}
29
30func lookup(k text.Key) (string, error) {
31	s, ok := text.Lookup(k)
32	if !ok {
33		return "", fmt.Errorf("unknown catalog key %q", k)
34	}
35	return s, nil
36}
37
38func translate(k text.Key, v Ident) (template.HTML, error) {
39	s, err := lookup(k)
40	if err != nil {
41		return "", err
42	}
43	out, err := interpolate(s, v)
44	if err != nil {
45		return "", fmt.Errorf("%w: %q", err, k)
46	}
47	return out, nil
48}
49
50func translateText(k text.Key, v Ident) (string, error) {
51	s, err := lookup(k)
52	if err != nil {
53		return "", err
54	}
55	before, after, ok := strings.Cut(s, identMarker)
56	if !ok || strings.Contains(after, identMarker) {
57		return "", fmt.Errorf("%w: %q", errNoMarker, k)
58	}
59	return before + string(v) + after, nil
60}
61
62func funcs() template.FuncMap {
63	return template.FuncMap{
64		"t":   lookup,
65		"tr":  translate,
66		"trt": translateText,
67		"id":  identHTML,
68	}
69}