- Walk HasLang FS for lang/<locale>/<group>.yaml and flatten nested keys - Publish one phrasebook.Translator before Boot with en/en defaults - Hello plugin resolves en/pl vendor.plugin::group.key after Activate Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
3.5 KiB
Go
99 lines
3.5 KiB
Go
package phrasebook
|
|
|
|
import (
|
|
"io/fs"
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"git.golem15.com/golem15/summercms/backpack"
|
|
"git.golem15.com/golem15/summercms/compass"
|
|
)
|
|
|
|
func TestTranslationSmoke(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"lang/en/lang.yaml": {Data: []byte("greeting: Hello\nlabels:\n pluginName: Hello plugin\n")},
|
|
"lang/pl/lang.yaml": {Data: []byte("greeting: Cześć\nlabels:\n pluginName: Wtyczka Hello\n")},
|
|
}
|
|
cat := NewCatalog()
|
|
if err := cat.Load("golem15.hello", fsys); err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
tr := NewTranslator(cat, Options{})
|
|
if got := tr.GetIn("en", "golem15.hello::lang.labels.pluginName", nil); got != "Hello plugin" {
|
|
t.Fatalf("en nested = %q", got)
|
|
}
|
|
if got := tr.GetIn("pl", "golem15.hello::lang.labels.pluginName", nil); got != "Wtyczka Hello" {
|
|
t.Fatalf("pl nested = %q", got)
|
|
}
|
|
if got := tr.GetIn("en", "golem15.hello::lang.greeting", nil); got != "Hello" {
|
|
t.Fatalf("en greeting = %q", got)
|
|
}
|
|
if got := tr.GetIn("pl", "golem15.hello::lang.greeting", nil); got != "Cześć" {
|
|
t.Fatalf("pl greeting = %q", got)
|
|
}
|
|
|
|
t.Run("malformed path", func(t *testing.T) {
|
|
err := NewCatalog().Load("golem15.hello", fstest.MapFS{
|
|
"lang/en.yaml": {Data: []byte("greeting: Hello\n")},
|
|
})
|
|
if err == nil || !strings.Contains(err.Error(), "golem15.hello") || !strings.Contains(err.Error(), "malformed path") {
|
|
t.Fatalf("malformed path error = %v", err)
|
|
}
|
|
})
|
|
t.Run("non-string leaf", func(t *testing.T) {
|
|
err := NewCatalog().Load("golem15.hello", fstest.MapFS{
|
|
"lang/en/lang.yaml": {Data: []byte("count: 1\n")},
|
|
})
|
|
if err == nil || !strings.Contains(err.Error(), "golem15.hello") || !strings.Contains(err.Error(), "lang/en/lang.yaml") || !strings.Contains(err.Error(), "non-string leaf") {
|
|
t.Fatalf("non-string leaf error = %v", err)
|
|
}
|
|
})
|
|
t.Run("duplicate key", func(t *testing.T) {
|
|
err := NewCatalog().Load("golem15.hello", fstest.MapFS{
|
|
"lang/en/lang.yaml": {Data: []byte("labels:\n name: a\nlabels.name: b\n")},
|
|
})
|
|
if err == nil || !strings.Contains(err.Error(), "golem15.hello") || !strings.Contains(err.Error(), "duplicate key") {
|
|
t.Fatalf("duplicate key error = %v", err)
|
|
}
|
|
})
|
|
t.Run("duplicate namespace owner", func(t *testing.T) {
|
|
cat := NewCatalog()
|
|
fsys := fstest.MapFS{"lang/en/lang.yaml": {Data: []byte("greeting: Hello\n")}}
|
|
if err := cat.Load("golem15.hello", fsys); err != nil {
|
|
t.Fatalf("first Load: %v", err)
|
|
}
|
|
err := cat.Load("golem15.hello", fsys)
|
|
if err == nil || !strings.Contains(err.Error(), "golem15.hello") || !strings.Contains(err.Error(), "duplicate namespace owner") {
|
|
t.Fatalf("duplicate namespace error = %v", err)
|
|
}
|
|
})
|
|
t.Run("activate publishes translator", func(t *testing.T) {
|
|
app := backpack.New(&compass.Config{})
|
|
p := &langPlugin{id: "golem15.hello", fsys: fsys}
|
|
if err := Activate(app, []*langPlugin{p}); err != nil {
|
|
t.Fatalf("Activate: %v", err)
|
|
}
|
|
tr, ok := app.Lookup[*Translator]()
|
|
if !ok {
|
|
t.Fatal("translator not published")
|
|
}
|
|
if got := tr.GetIn("pl", "golem15.hello::lang.greeting", nil); got != "Cześć" {
|
|
t.Fatalf("activated pl = %q", got)
|
|
}
|
|
})
|
|
}
|
|
|
|
type langPlugin struct {
|
|
id string
|
|
fsys fstest.MapFS
|
|
}
|
|
|
|
func (p *langPlugin) ID() string { return p.id }
|
|
func (p *langPlugin) Requires() []string { return nil }
|
|
func (p *langPlugin) Register(*backpack.App) error { return nil }
|
|
func (p *langPlugin) Boot(*backpack.App) error { return nil }
|
|
func (p *langPlugin) LangFS() fs.FS { return p.fsys }
|