From 3fa2a866648a8df93ba211b8d96b1efcb4ca5c31 Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 00:28:08 +0000 Subject: [PATCH] feat(html): add cloneable locale and service helpers Co-Authored-By: Virgil --- context.go | 22 ++++++++++++++++++ context_test.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/context.go b/context.go index d791855..9ebf698 100644 --- a/context.go +++ b/context.go @@ -166,6 +166,28 @@ func (ctx *Context) WithIdentity(identity string) *Context { return clone } +// WithLocale returns a cloned context with a different locale value. +// Example: next := ctx.WithLocale("fr-FR"). +func (ctx *Context) WithLocale(locale string) *Context { + clone := ctx.Clone() + if clone == nil { + return nil + } + clone.SetLocale(locale) + return clone +} + +// WithService returns a cloned context with a different translator. +// Example: next := ctx.WithService(svc). +func (ctx *Context) WithService(svc Translator) *Context { + clone := ctx.Clone() + if clone == nil { + return nil + } + clone.SetService(svc) + return clone +} + // SetLocale updates the context locale and reapplies it to the active // translator. // Example: ctx.SetLocale("en-US"). diff --git a/context_test.go b/context_test.go index 793ca50..63401be 100644 --- a/context_test.go +++ b/context_test.go @@ -202,6 +202,62 @@ func TestContext_WithIdentityReturnsClonedContext(t *testing.T) { } } +func TestContext_WithLocaleReturnsClonedContext(t *testing.T) { + svc := &localeTranslator{} + ctx := NewContextWithService(svc, "en-GB") + ctx.SetIdentity("user-001") + ctx.SetData("theme", "dark") + + next := ctx.WithLocale("fr-FR") + + if next == ctx { + t.Fatal("WithLocale should return a cloned context") + } + if got := ctx.Locale; got != "en-GB" { + t.Fatalf("WithLocale should not mutate the original context locale, got %q", got) + } + if got := next.Locale; got != "fr-FR" { + t.Fatalf("WithLocale should set the requested locale on the clone, got %q", got) + } + if got := next.service; got != ctx.service { + t.Fatal("WithLocale should preserve the active translator on the clone") + } + if svc.language != "fr" { + t.Fatalf("WithLocale should reapply locale to the cloned service, got %q", svc.language) + } + if got := next.Data["theme"]; got != "dark" { + t.Fatalf("WithLocale should preserve existing data on the clone, got %v", got) + } +} + +func TestContext_WithServiceReturnsClonedContext(t *testing.T) { + ctx := NewContext("fr-FR") + ctx.SetIdentity("user-001") + ctx.SetData("theme", "dark") + + svc := &localeTranslator{} + next := ctx.WithService(svc) + + if next == ctx { + t.Fatal("WithService should return a cloned context") + } + if got := ctx.service; got == svc { + t.Fatal("WithService should not mutate the original context service") + } + if got := next.service; got != svc { + t.Fatalf("WithService should set the requested service on the clone, got %v", got) + } + if svc.language != "fr" { + t.Fatalf("WithService should apply the existing locale to the new translator, got %q", svc.language) + } + if got := next.Data["theme"]; got != "dark" { + t.Fatalf("WithService should preserve existing data on the clone, got %v", got) + } + if got := next.Locale; got != "fr-FR" { + t.Fatalf("WithService should preserve the locale on the clone, got %q", got) + } +} + func TestContext_Setters_NilReceiver(t *testing.T) { var ctx *Context @@ -217,6 +273,12 @@ func TestContext_Setters_NilReceiver(t *testing.T) { if got := ctx.SetService(&localeTranslator{}); got != nil { t.Fatalf("nil Context.SetService should return nil, got %v", got) } + if got := ctx.WithLocale("en-GB"); got != nil { + t.Fatalf("nil Context.WithLocale should return nil, got %v", got) + } + if got := ctx.WithService(&localeTranslator{}); got != nil { + t.Fatalf("nil Context.WithService should return nil, got %v", got) + } } func TestText_RenderFallsBackToDefaultTranslator(t *testing.T) {