feat(html): allow swapping context translators
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
c2ff591ec9
commit
b9e2630da3
4 changed files with 53 additions and 15 deletions
43
context.go
43
context.go
|
|
@ -19,6 +19,23 @@ type Context struct {
|
|||
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.
|
||||
// Usage example: html := Render(Text("welcome"), NewContext("en-GB"))
|
||||
func NewContext(locale ...string) *Context {
|
||||
|
|
@ -35,18 +52,18 @@ func NewContext(locale ...string) *Context {
|
|||
// Usage example: ctx := NewContextWithService(myTranslator, "en-GB")
|
||||
func NewContextWithService(svc Translator, locale ...string) *Context {
|
||||
ctx := NewContext(locale...)
|
||||
ctx.service = svc
|
||||
if len(locale) > 0 {
|
||||
if setter, ok := svc.(interface{ SetLanguage(string) error }); ok {
|
||||
base := locale[0]
|
||||
for i := 0; i < len(base); i++ {
|
||||
if base[i] == '-' || base[i] == '_' {
|
||||
base = base[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
_ = setter.SetLanguage(base)
|
||||
}
|
||||
}
|
||||
ctx.SetService(svc)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// SetService swaps the translator used by the context.
|
||||
// Usage example: ctx.SetService(myTranslator)
|
||||
func (ctx *Context) SetService(svc Translator) *Context {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.service = svc
|
||||
applyLocaleToService(svc, ctx.Locale)
|
||||
return ctx
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,3 +46,24 @@ func TestNewContextWithService_AppliesLocaleToService_Good(t *testing.T) {
|
|||
t.Fatalf("NewContextWithService locale translation = %q, want %q", got, "o")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext_SetService_AppliesLocale_Good(t *testing.T) {
|
||||
svc, _ := i18n.New()
|
||||
ctx := NewContext("fr-FR")
|
||||
|
||||
if got := ctx.SetService(svc); got != ctx {
|
||||
t.Fatal("SetService should return the same context for chaining")
|
||||
}
|
||||
|
||||
got := Text("prompt.yes").Render(ctx)
|
||||
if got != "o" {
|
||||
t.Fatalf("SetService locale translation = %q, want %q", got, "o")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext_SetService_NilContext_Ugly(t *testing.T) {
|
||||
var ctx *Context
|
||||
if got := ctx.SetService(nil); got != nil {
|
||||
t.Fatal("SetService on nil context should return nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,6 +309,6 @@ func TestGenerateClass_ValidTag(t *testing.T) {
|
|||
|
||||
- `NewLayout("XYZ")` silently produces empty output for unrecognised slot letters. Valid letters are `H`, `L`, `C`, `R`, `F`. There is no error or warning.
|
||||
- `Responsive.Variant()` accepts only `*Layout`, not arbitrary `Node` values. Arbitrary subtrees must be wrapped in a single-slot layout first.
|
||||
- `Context.service` is unexported. Custom translation injection requires `NewContextWithService()`. There is no way to swap the translator after construction.
|
||||
- `Context.service` is unexported. Custom translation injection uses `NewContextWithService()`, and `Context.SetService()` can swap the translator later while preserving locale-aware services.
|
||||
- The WASM module has no integration test for the JavaScript exports. `size_test.go` tests binary size only; it does not exercise `renderToString` behaviour from JavaScript.
|
||||
- `codegen.GenerateBundle()` now renders output classes in sorted slot-key order so generated bundles are stable between runs.
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ These are not regressions; they are design choices or deferred work recorded for
|
|||
|
||||
3. **Responsive accepts only Layout.** `Responsive.Variant()` takes `*Layout` rather than `Node`. The rationale is that `CompareVariants` in the pipeline needs access to the slot structure. Accepting `Node` would require a different approach to variant analysis.
|
||||
|
||||
4. **Context.service is private.** The i18n service cannot be set after construction or swapped. This is a conservative choice; relaxing it requires deciding whether mutation should be safe for concurrent use.
|
||||
4. **Context.service is private.** The i18n service is still unexported, but callers can now swap it explicitly with `Context.SetService()`. This keeps the field encapsulated while allowing controlled mutation.
|
||||
|
||||
5. **TypeScript definitions not generated.** `codegen.GenerateBundle()` produces JS only. A `.d.ts` companion would benefit TypeScript consumers of the generated Web Components.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue