fix(wasm): keep server i18n out of js builds
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
8a3f28aff3
commit
0e976b3a87
7 changed files with 47 additions and 18 deletions
14
context.go
14
context.go
|
|
@ -1,6 +1,12 @@
|
|||
package html
|
||||
|
||||
import i18n "dappco.re/go/core/i18n"
|
||||
// Translator provides Text() lookups for a rendering context.
|
||||
//
|
||||
// The default server build uses go-i18n. Alternate builds, including WASM,
|
||||
// can provide any implementation with the same T() method.
|
||||
type Translator interface {
|
||||
T(key string, args ...any) string
|
||||
}
|
||||
|
||||
// Context carries rendering state through the node tree.
|
||||
type Context struct {
|
||||
|
|
@ -8,7 +14,7 @@ type Context struct {
|
|||
Locale string
|
||||
Entitlements func(feature string) bool
|
||||
Data map[string]any
|
||||
service *i18n.Service
|
||||
service Translator
|
||||
}
|
||||
|
||||
// NewContext creates a new rendering context with sensible defaults.
|
||||
|
|
@ -18,8 +24,8 @@ func NewContext() *Context {
|
|||
}
|
||||
}
|
||||
|
||||
// NewContextWithService creates a rendering context backed by a specific i18n service.
|
||||
func NewContextWithService(svc *i18n.Service) *Context {
|
||||
// NewContextWithService creates a rendering context backed by a specific translator.
|
||||
func NewContextWithService(svc Translator) *Context {
|
||||
return &Context{
|
||||
Data: make(map[string]any),
|
||||
service: svc,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ All concrete node types are unexported structs with exported constructor functio
|
|||
|-------------|-----------|
|
||||
| `El(tag, ...Node)` | HTML element with children. Void elements (`br`, `img`, `input`, etc.) never emit a closing tag. |
|
||||
| `Attr(Node, key, value)` | Sets an attribute on an `El` node. Traverses through `If`, `Unless`, and `Entitled` wrappers. Returns the node for chaining. |
|
||||
| `Text(key, ...any)` | Translated text via `go-i18n`. Output is always HTML-escaped. |
|
||||
| `Text(key, ...any)` | Translated text via the active context translator. Server builds fall back to global `go-i18n`; JS builds fall back to the key. Output is always HTML-escaped. |
|
||||
| `Raw(content)` | Unescaped trusted content. Explicit escape hatch. |
|
||||
| `If(cond, Node)` | Renders the child only when the condition function returns true. |
|
||||
| `Unless(cond, Node)` | Renders the child only when the condition function returns false. |
|
||||
|
|
@ -50,16 +50,16 @@ type Context struct {
|
|||
Locale string // BCP 47 locale string
|
||||
Entitlements func(feature string) bool // feature gate callback
|
||||
Data map[string]any // arbitrary per-request data
|
||||
service *i18n.Service // unexported; set via constructor
|
||||
service Translator // unexported; set via constructor
|
||||
}
|
||||
```
|
||||
|
||||
Two constructors are provided:
|
||||
|
||||
- `NewContext()` creates a context with sensible defaults and an empty `Data` map.
|
||||
- `NewContextWithService(svc)` creates a context backed by a specific `i18n.Service` instance.
|
||||
- `NewContextWithService(svc)` creates a context backed by any translator implementing `T(key, ...any) string` such as `*i18n.Service`.
|
||||
|
||||
The `service` field is intentionally unexported. When nil, `Text` nodes fall back to the global `i18n.T()` default. This prevents callers from setting the service inconsistently after construction.
|
||||
The `service` field is intentionally unexported. When nil, server builds fall back to the global `i18n.T()` default while JS builds render the key unchanged. This prevents callers from setting the service inconsistently after construction while keeping the WASM import graph lean.
|
||||
|
||||
## HLCRF Layout
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,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 i18n service injection requires `NewContextWithService()`. There is no way to swap the service after construction.
|
||||
- `Context.service` is unexported. Custom translation injection requires `NewContextWithService()`. There is no way to swap the translator after construction.
|
||||
- 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()` iterates a `map`, so the order of class definitions in the output is non-deterministic. This does not affect correctness but may cause cosmetic diffs between runs.
|
||||
|
|
|
|||
10
node.go
10
node.go
|
|
@ -6,8 +6,6 @@ import (
|
|||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
i18n "dappco.re/go/core/i18n"
|
||||
)
|
||||
|
||||
// Node is anything renderable.
|
||||
|
|
@ -152,13 +150,7 @@ func Text(key string, args ...any) Node {
|
|||
}
|
||||
|
||||
func (n *textNode) Render(ctx *Context) string {
|
||||
var text string
|
||||
if ctx != nil && ctx.service != nil {
|
||||
text = ctx.service.T(n.key, n.args...)
|
||||
} else {
|
||||
text = i18n.T(n.key, n.args...)
|
||||
}
|
||||
return escapeHTML(text)
|
||||
return escapeHTML(translateText(ctx, n.key, n.args...))
|
||||
}
|
||||
|
||||
// --- ifNode ---
|
||||
|
|
|
|||
11
text_translate.go
Normal file
11
text_translate.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
|
||||
package html
|
||||
|
||||
func translateText(ctx *Context, key string, args ...any) string {
|
||||
if ctx != nil && ctx.service != nil {
|
||||
return ctx.service.T(key, args...)
|
||||
}
|
||||
|
||||
return translateDefault(key, args...)
|
||||
}
|
||||
11
text_translate_default.go
Normal file
11
text_translate_default.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//go:build !js
|
||||
|
||||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
|
||||
package html
|
||||
|
||||
import i18n "dappco.re/go/core/i18n"
|
||||
|
||||
func translateDefault(key string, args ...any) string {
|
||||
return i18n.T(key, args...)
|
||||
}
|
||||
9
text_translate_js.go
Normal file
9
text_translate_js.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//go:build js
|
||||
|
||||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
|
||||
package html
|
||||
|
||||
func translateDefault(key string, _ ...any) string {
|
||||
return key
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue