feat(html): add context locale setter
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-03 16:48:59 +00:00
parent 58380d3d87
commit afa0337bbd
3 changed files with 122 additions and 13 deletions

View file

@ -21,7 +21,7 @@ func renderToString(_ js.Value, args []js.Value) any {
ctx := html.NewContext()
if len(args) >= 2 {
ctx.Locale = args[1].String()
ctx.SetLocale(args[1].String())
}
layout := html.NewLayout(variant)

View file

@ -1,6 +1,9 @@
package html
import i18n "dappco.re/go/core/i18n"
// Translator provides Text() lookups for a rendering context.
type Translator interface {
T(key string, args ...any) string
}
// Context carries rendering state through the node tree.
type Context struct {
@ -8,7 +11,24 @@ type Context struct {
Locale string
Entitlements func(feature string) bool
Data map[string]any
service *i18n.Service
service Translator
}
func applyLocaleToService(svc Translator, locale string) {
if svc == nil || locale == "" {
return
}
if setter, ok := svc.(interface{ SetLanguage(string) error }); ok {
base := locale
for i := 0; i < len(base); i++ {
if base[i] == '-' || base[i] == '_' {
base = base[:i]
break
}
}
_ = setter.SetLanguage(base)
}
}
// NewContext creates a new rendering context with sensible defaults.
@ -18,20 +38,37 @@ func NewContext(locale ...string) *Context {
Data: make(map[string]any),
}
if len(locale) > 0 {
ctx.Locale = locale[0]
ctx.SetLocale(locale[0])
}
return ctx
}
// NewContextWithService creates a rendering context backed by a specific i18n service.
// NewContextWithService creates a rendering context backed by a specific translator.
// An optional locale may be provided as the second argument.
func NewContextWithService(svc *i18n.Service, locale ...string) *Context {
ctx := &Context{
Data: make(map[string]any),
service: svc,
}
if len(locale) > 0 {
ctx.Locale = locale[0]
}
func NewContextWithService(svc Translator, locale ...string) *Context {
ctx := NewContext(locale...)
ctx.SetService(svc)
return ctx
}
// SetService swaps the translator used by the context.
func (ctx *Context) SetService(svc Translator) *Context {
if ctx == nil {
return nil
}
ctx.service = svc
applyLocaleToService(svc, ctx.Locale)
return ctx
}
// SetLocale updates the context locale and reapplies it to the active translator.
func (ctx *Context) SetLocale(locale string) *Context {
if ctx == nil {
return nil
}
ctx.Locale = locale
applyLocaleToService(ctx.service, ctx.Locale)
return ctx
}

72
context_test.go Normal file
View file

@ -0,0 +1,72 @@
// SPDX-Licence-Identifier: EUPL-1.2
package html
import "testing"
type localeTranslator struct {
language string
}
func (t *localeTranslator) T(key string, args ...any) string {
if key == "prompt.yes" && t.language == "fr" {
return "o"
}
if key == "prompt.yes" && t.language == "en" {
return "y"
}
return key
}
func (t *localeTranslator) SetLanguage(language string) error {
t.language = language
return nil
}
func TestContext_SetService_AppliesLocale(t *testing.T) {
svc := &localeTranslator{}
ctx := NewContext("fr-FR")
if got := ctx.SetService(svc); got != ctx {
t.Fatal("SetService should return the same context for chaining")
}
if svc.language != "fr" {
t.Fatalf("SetService should apply locale to translator, got %q", svc.language)
}
if got := Text("prompt.yes").Render(ctx); got != "o" {
t.Fatalf("SetService locale translation = %q, want %q", got, "o")
}
}
func TestContext_SetLocale_AppliesLocale(t *testing.T) {
svc := &localeTranslator{}
ctx := NewContextWithService(svc)
if got := ctx.SetLocale("en-GB"); got != ctx {
t.Fatal("SetLocale should return the same context for chaining")
}
if svc.language != "en" {
t.Fatalf("SetLocale should apply locale to translator, got %q", svc.language)
}
if got := Text("prompt.yes").Render(ctx); got != "y" {
t.Fatalf("SetLocale translation = %q, want %q", got, "y")
}
}
func TestContext_SetService_NilContext(t *testing.T) {
var ctx *Context
if got := ctx.SetService(nil); got != nil {
t.Fatal("SetService on nil context should return nil")
}
}
func TestContext_SetLocale_NilContext(t *testing.T) {
var ctx *Context
if got := ctx.SetLocale("en-GB"); got != nil {
t.Fatal("SetLocale on nil context should return nil")
}
}