go-i18n/loader_test.go

264 lines
6 KiB
Go
Raw Permalink Normal View History

package i18n
import (
"testing"
"testing/fstest"
)
func TestFSLoaderLanguages(t *testing.T) {
loader := NewFSLoader(localeFS, "locales")
langs := loader.Languages()
if len(langs) == 0 {
t.Fatal("FSLoader.Languages() returned empty")
}
found := false
for _, l := range langs {
if l == "en" {
found = true
break
}
}
if !found {
t.Errorf("Languages() = %v, expected 'en' in list", langs)
}
}
func TestFSLoaderLoad(t *testing.T) {
loader := NewFSLoader(localeFS, "locales")
messages, grammar, err := loader.Load("en")
if err != nil {
t.Fatalf("Load(en) error: %v", err)
}
// Should have messages from the JSON
if len(messages) == 0 {
t.Error("Load(en) returned 0 messages")
}
// Grammar data should be extracted from nested JSON
if grammar == nil {
t.Fatal("Load(en) returned nil grammar")
}
// Verbs from gram.verb.*
if len(grammar.Verbs) == 0 {
t.Error("grammar has 0 verbs")
}
if v, ok := grammar.Verbs["build"]; !ok {
t.Error("grammar missing verb 'build'")
} else {
if v.Past != "built" {
t.Errorf("build.past = %q, want 'built'", v.Past)
}
if v.Gerund != "building" {
t.Errorf("build.gerund = %q, want 'building'", v.Gerund)
}
}
// Nouns from gram.noun.*
if len(grammar.Nouns) == 0 {
t.Error("grammar has 0 nouns")
}
if n, ok := grammar.Nouns["file"]; !ok {
t.Error("grammar missing noun 'file'")
} else {
if n.One != "file" {
t.Errorf("file.one = %q, want 'file'", n.One)
}
if n.Other != "files" {
t.Errorf("file.other = %q, want 'files'", n.Other)
}
}
// Articles from gram.article
if grammar.Articles.IndefiniteDefault != "a" {
t.Errorf("article.indefinite.default = %q, want 'a'", grammar.Articles.IndefiniteDefault)
}
if grammar.Articles.IndefiniteVowel != "an" {
t.Errorf("article.indefinite.vowel = %q, want 'an'", grammar.Articles.IndefiniteVowel)
}
if grammar.Articles.Definite != "the" {
t.Errorf("article.definite = %q, want 'the'", grammar.Articles.Definite)
}
// Punctuation from gram.punct
if grammar.Punct.LabelSuffix != ":" {
t.Errorf("punct.label = %q, want ':'", grammar.Punct.LabelSuffix)
}
if grammar.Punct.ProgressSuffix != "..." {
t.Errorf("punct.progress = %q, want '...'", grammar.Punct.ProgressSuffix)
}
// Words from gram.word.*
if len(grammar.Words) == 0 {
t.Error("grammar has 0 words")
}
if grammar.Words["url"] != "URL" {
t.Errorf("word.url = %q, want 'URL'", grammar.Words["url"])
}
if grammar.Words["api"] != "API" {
t.Errorf("word.api = %q, want 'API'", grammar.Words["api"])
}
}
func TestFSLoaderLoadMissing(t *testing.T) {
loader := NewFSLoader(localeFS, "locales")
_, _, err := loader.Load("xx")
if err == nil {
t.Error("Load(xx) should fail for non-existent locale")
}
}
func TestFlattenWithGrammar(t *testing.T) {
messages := make(map[string]Message)
grammar := &GrammarData{
Verbs: make(map[string]VerbForms),
Nouns: make(map[string]NounForms),
Words: make(map[string]string),
}
raw := map[string]any{
"gram": map[string]any{
"verb": map[string]any{
"test": map[string]any{
"base": "test",
"past": "tested",
"gerund": "testing",
},
},
"noun": map[string]any{
"widget": map[string]any{
"one": "widget",
"other": "widgets",
},
},
"word": map[string]any{
"api": "API",
},
"punct": map[string]any{
"label": ":",
"progress": "...",
},
"article": map[string]any{
"indefinite": map[string]any{
"default": "a",
"vowel": "an",
},
"definite": "the",
},
},
"prompt": map[string]any{
"yes": "y",
"no": "n",
},
}
flattenWithGrammar("", raw, messages, grammar)
// Verb extracted
if v, ok := grammar.Verbs["test"]; !ok {
t.Error("verb 'test' not extracted")
} else {
if v.Past != "tested" {
t.Errorf("test.past = %q, want 'tested'", v.Past)
}
}
// Noun extracted
if n, ok := grammar.Nouns["widget"]; !ok {
t.Error("noun 'widget' not extracted")
} else {
if n.Other != "widgets" {
t.Errorf("widget.other = %q, want 'widgets'", n.Other)
}
}
// Word extracted
if grammar.Words["api"] != "API" {
t.Errorf("word 'api' = %q, want 'API'", grammar.Words["api"])
}
// Punct extracted
if grammar.Punct.LabelSuffix != ":" {
t.Errorf("punct.label = %q, want ':'", grammar.Punct.LabelSuffix)
}
// Articles extracted
if grammar.Articles.IndefiniteDefault != "a" {
t.Errorf("article.indefinite.default = %q, want 'a'", grammar.Articles.IndefiniteDefault)
}
// Regular keys flattened
if msg, ok := messages["prompt.yes"]; !ok || msg.Text != "y" {
t.Errorf("prompt.yes not flattened correctly, got %+v", messages["prompt.yes"])
}
}
func TestFlattenPluralObject(t *testing.T) {
messages := make(map[string]Message)
raw := map[string]any{
"time": map[string]any{
"ago": map[string]any{
"second": map[string]any{
"one": "{{.Count}} second ago",
"other": "{{.Count}} seconds ago",
},
},
},
}
flattenWithGrammar("", raw, messages, nil)
msg, ok := messages["time.ago.second"]
if !ok {
t.Fatal("time.ago.second not found")
}
if !msg.IsPlural() {
t.Error("time.ago.second should be plural")
}
if msg.One != "{{.Count}} second ago" {
t.Errorf("time.ago.second.one = %q", msg.One)
}
if msg.Other != "{{.Count}} seconds ago" {
t.Errorf("time.ago.second.other = %q", msg.Other)
}
}
func TestCustomFSLoader(t *testing.T) {
fs := fstest.MapFS{
"locales/test.json": &fstest.MapFile{
Data: []byte(`{
"gram": {
"verb": {
"zap": { "base": "zap", "past": "zapped", "gerund": "zapping" }
},
"word": {
"hello": "Hello"
}
},
"greeting": "Hello, world!"
}`),
},
}
svc, err := NewWithFS(fs, "locales", WithFallback("test"))
if err != nil {
t.Fatalf("NewWithFS failed: %v", err)
}
got := svc.T("greeting")
if got != "Hello, world!" {
t.Errorf("T(greeting) = %q, want 'Hello, world!'", got)
}
// Grammar should be loaded
gd := GetGrammarData("test")
if gd == nil {
t.Fatal("grammar data not loaded for 'test'")
}
if v, ok := gd.Verbs["zap"]; !ok || v.Past != "zapped" {
t.Errorf("verb 'zap' not loaded correctly")
}
}