fix(html): share pluralisation args across builds
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
fc4bae09cc
commit
fb13048db2
7 changed files with 159 additions and 102 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@
|
|||
.vscode/
|
||||
*.log
|
||||
.core/
|
||||
dist/
|
||||
|
|
|
|||
23
context.go
23
context.go
|
|
@ -85,3 +85,26 @@ func (ctx *Context) SetLocale(locale string) *Context {
|
|||
applyLocaleToService(ctx.service, ctx.Locale)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func cloneContext(ctx *Context) *Context {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
clone := *ctx
|
||||
clone.Data = cloneMetadataMap(ctx.Data)
|
||||
clone.Metadata = cloneMetadataMap(ctx.Metadata)
|
||||
return &clone
|
||||
}
|
||||
|
||||
func cloneMetadataMap(src map[string]any) map[string]any {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
dst := make(map[string]any, len(src))
|
||||
for key, value := range src {
|
||||
dst[key] = value
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,23 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
i18n "dappco.re/go/core/i18n"
|
||||
)
|
||||
|
||||
type recordingTranslator struct {
|
||||
key string
|
||||
args []any
|
||||
}
|
||||
|
||||
func (r *recordingTranslator) T(key string, args ...any) string {
|
||||
r.key = key
|
||||
r.args = append(r.args[:0], args...)
|
||||
return "translated"
|
||||
}
|
||||
|
||||
func TestNewContext_OptionalLocale_Good(t *testing.T) {
|
||||
ctx := NewContext("en-GB")
|
||||
|
||||
|
|
@ -61,6 +73,26 @@ func TestTextNode_UsesMetadataAliasWhenDataNil_Good(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTextNode_CustomTranslatorReceivesCountArgs_Good(t *testing.T) {
|
||||
ctx := NewContextWithService(&recordingTranslator{})
|
||||
ctx.Metadata["count"] = 3
|
||||
|
||||
got := Text("i18n.count.file", "ignored").Render(ctx)
|
||||
if got != "translated" {
|
||||
t.Fatalf("Text with custom translator = %q, want %q", got, "translated")
|
||||
}
|
||||
|
||||
svc := ctx.service.(*recordingTranslator)
|
||||
if svc.key != "i18n.count.file" {
|
||||
t.Fatalf("custom translator key = %q, want %q", svc.key, "i18n.count.file")
|
||||
}
|
||||
|
||||
wantArgs := []any{3, "ignored"}
|
||||
if !reflect.DeepEqual(svc.args, wantArgs) {
|
||||
t.Fatalf("custom translator args = %#v, want %#v", svc.args, wantArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext_SetService_AppliesLocale_Good(t *testing.T) {
|
||||
svc, _ := i18n.New()
|
||||
ctx := NewContext("fr-FR")
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func CompareVariants(r *Responsive, ctx *Context) map[string]float64 {
|
|||
if v.layout == nil {
|
||||
continue
|
||||
}
|
||||
imp := Imprint(v.layout, ctx)
|
||||
imp := Imprint(v.layout, cloneContext(ctx))
|
||||
imprints = append(imprints, named{name: v.name, imp: imp})
|
||||
}
|
||||
|
||||
|
|
|
|||
102
text_translate_args.go
Normal file
102
text_translate_args.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func translationArgs(ctx *Context, key string, args []any) []any {
|
||||
if ctx == nil {
|
||||
return args
|
||||
}
|
||||
|
||||
count, ok := contextCount(ctx)
|
||||
if !ok {
|
||||
return args
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return []any{count}
|
||||
}
|
||||
if strings.HasPrefix(key, "i18n.count.") && !isCountLike(args[0]) {
|
||||
return append([]any{count}, args...)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func contextCount(ctx *Context) (int, bool) {
|
||||
if ctx == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if n, ok := contextCountMap(ctx.Data); ok {
|
||||
return n, true
|
||||
}
|
||||
if n, ok := contextCountMap(ctx.Metadata); ok {
|
||||
return n, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func contextCountMap(data map[string]any) (int, bool) {
|
||||
if len(data) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if v, ok := data["Count"]; ok {
|
||||
if n, ok := countInt(v); ok {
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
if v, ok := data["count"]; ok {
|
||||
if n, ok := countInt(v); ok {
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func countInt(v any) (int, bool) {
|
||||
switch n := v.(type) {
|
||||
case int:
|
||||
return n, true
|
||||
case int8:
|
||||
return int(n), true
|
||||
case int16:
|
||||
return int(n), true
|
||||
case int32:
|
||||
return int(n), true
|
||||
case int64:
|
||||
return int(n), true
|
||||
case uint:
|
||||
return int(n), true
|
||||
case uint8:
|
||||
return int(n), true
|
||||
case uint16:
|
||||
return int(n), true
|
||||
case uint32:
|
||||
return int(n), true
|
||||
case uint64:
|
||||
return int(n), true
|
||||
case float32:
|
||||
return int(n), true
|
||||
case float64:
|
||||
return int(n), true
|
||||
case string:
|
||||
n = strings.TrimSpace(n)
|
||||
if n == "" {
|
||||
return 0, false
|
||||
}
|
||||
if parsed, err := strconv.Atoi(n); err == nil {
|
||||
return parsed, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func isCountLike(v any) bool {
|
||||
_, ok := countInt(v)
|
||||
return ok
|
||||
}
|
||||
|
|
@ -5,106 +5,9 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
i18n "dappco.re/go/core/i18n"
|
||||
)
|
||||
|
||||
func translationArgs(ctx *Context, key string, args []any) []any {
|
||||
if ctx == nil {
|
||||
return args
|
||||
}
|
||||
|
||||
count, ok := contextCount(ctx)
|
||||
if !ok {
|
||||
return args
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return []any{count}
|
||||
}
|
||||
if strings.HasPrefix(key, "i18n.count.") && !isCountLike(args[0]) {
|
||||
return append([]any{count}, args...)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func contextCount(ctx *Context) (int, bool) {
|
||||
if ctx == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if n, ok := contextCountMap(ctx.Data); ok {
|
||||
return n, true
|
||||
}
|
||||
if n, ok := contextCountMap(ctx.Metadata); ok {
|
||||
return n, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func contextCountMap(data map[string]any) (int, bool) {
|
||||
if len(data) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if v, ok := data["Count"]; ok {
|
||||
if n, ok := countInt(v); ok {
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
if v, ok := data["count"]; ok {
|
||||
if n, ok := countInt(v); ok {
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func countInt(v any) (int, bool) {
|
||||
switch n := v.(type) {
|
||||
case int:
|
||||
return n, true
|
||||
case int8:
|
||||
return int(n), true
|
||||
case int16:
|
||||
return int(n), true
|
||||
case int32:
|
||||
return int(n), true
|
||||
case int64:
|
||||
return int(n), true
|
||||
case uint:
|
||||
return int(n), true
|
||||
case uint8:
|
||||
return int(n), true
|
||||
case uint16:
|
||||
return int(n), true
|
||||
case uint32:
|
||||
return int(n), true
|
||||
case uint64:
|
||||
return int(n), true
|
||||
case float32:
|
||||
return int(n), true
|
||||
case float64:
|
||||
return int(n), true
|
||||
case string:
|
||||
n = strings.TrimSpace(n)
|
||||
if n == "" {
|
||||
return 0, false
|
||||
}
|
||||
if parsed, err := strconv.Atoi(n); err == nil {
|
||||
return parsed, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func isCountLike(v any) bool {
|
||||
_, ok := countInt(v)
|
||||
return ok
|
||||
}
|
||||
|
||||
func translateDefault(key string, args ...any) string {
|
||||
return i18n.T(key, args...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@
|
|||
|
||||
package html
|
||||
|
||||
func translationArgs(_ *Context, _ string, args []any) []any {
|
||||
return args
|
||||
}
|
||||
|
||||
func translateDefault(key string, _ ...any) string {
|
||||
return key
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue