diff --git a/context_map.go b/context_map.go new file mode 100644 index 0000000..9ca670c --- /dev/null +++ b/context_map.go @@ -0,0 +1,82 @@ +package i18n + +import "dappco.re/go/core" + +func mapValueString(values any, key string) (string, bool) { + switch m := values.(type) { + case map[string]any: + raw, ok := m[key] + if !ok { + return "", false + } + text := core.Trim(core.Sprintf("%v", raw)) + if text == "" { + return "", false + } + return text, true + case map[string]string: + text, ok := m[key] + if !ok { + return "", false + } + text = core.Trim(text) + if text == "" { + return "", false + } + return text, true + default: + return "", false + } +} + +func contextMapValues(values any) map[string]any { + switch m := values.(type) { + case map[string]any: + return contextMapValuesAny(m) + case map[string]string: + return contextMapValuesString(m) + default: + return nil + } +} + +func contextMapValuesAny(values map[string]any) map[string]any { + if len(values) == 0 { + return nil + } + extra := make(map[string]any, len(values)) + for key, value := range values { + switch key { + case "Context", "Gender", "Location", "Formality": + continue + case "Extra", "extra", "Extras", "extras": + mergeContextExtra(extra, value) + continue + default: + extra[key] = value + } + } + if len(extra) == 0 { + return nil + } + return extra +} + +func contextMapValuesString(values map[string]string) map[string]any { + if len(values) == 0 { + return nil + } + extra := make(map[string]any, len(values)) + for key, value := range values { + switch key { + case "Context", "Gender", "Location", "Formality", "Extra", "extra", "Extras", "extras": + continue + default: + extra[key] = value + } + } + if len(extra) == 0 { + return nil + } + return extra +} diff --git a/handler.go b/handler.go index c1fb65f..fe2ffd4 100644 --- a/handler.go +++ b/handler.go @@ -238,6 +238,8 @@ func subjectArgText(arg any) string { return "" case map[string]any: return contextArgText(v) + case map[string]string: + return contextArgText(v) case fmt.Stringer: return v.String() default: @@ -245,15 +247,10 @@ func subjectArgText(arg any) string { } } -func contextArgText(values map[string]any) string { - if len(values) == 0 { - return "" - } +func contextArgText(values any) string { for _, key := range []string{"Subject", "subject", "Value", "value", "Text", "text", "Context", "context", "Noun", "noun"} { - if raw, ok := values[key]; ok { - if text := core.Trim(core.Sprintf("%v", raw)); text != "" { - return text - } + if text, ok := mapValueString(values, key); ok { + return text } } return "" diff --git a/handler_test.go b/handler_test.go index aba4496..2b7b473 100644 --- a/handler_test.go +++ b/handler_test.go @@ -63,6 +63,11 @@ func TestProgressHandler(t *testing.T) { if got != "Building project..." { t.Errorf("ProgressHandler.Handle(build, map[Subject:project]) = %q, want %q", got, "Building project...") } + + got = h.Handle("i18n.progress.build", []any{map[string]string{"Subject": "project"}}, nil) + if got != "Building project..." { + t.Errorf("ProgressHandler.Handle(build, map[string]string[Subject:project]) = %q, want %q", got, "Building project...") + } } func TestCountHandler(t *testing.T) { @@ -148,6 +153,11 @@ func TestDoneHandler(t *testing.T) { t.Errorf("DoneHandler.Handle(delete, map[Subject:config.yaml]) = %q, want %q", got, "Config.yaml deleted") } + got = h.Handle("i18n.done.delete", []any{map[string]string{"Subject": "config.yaml"}}, nil) + if got != "Config.yaml deleted" { + t.Errorf("DoneHandler.Handle(delete, map[string]string[Subject:config.yaml]) = %q, want %q", got, "Config.yaml deleted") + } + // Without subject — just past tense got = h.Handle("i18n.done.delete", nil, nil) if got != "Deleted" { @@ -182,6 +192,11 @@ func TestFailHandler(t *testing.T) { t.Errorf("FailHandler.Handle(push, map[Subject:commits]) = %q, want %q", got, "Failed to push commits") } + got = h.Handle("i18n.fail.push", []any{map[string]string{"Subject": "commits"}}, nil) + if got != "Failed to push commits" { + t.Errorf("FailHandler.Handle(push, map[string]string[Subject:commits]) = %q, want %q", got, "Failed to push commits") + } + got = h.Handle("i18n.fail.push", nil, nil) if got != "Failed to push" { t.Errorf("FailHandler.Handle(push) = %q, want %q", got, "Failed to push") diff --git a/service.go b/service.go index 3c83ccf..89e8306 100644 --- a/service.go +++ b/service.go @@ -453,14 +453,14 @@ func (s *Service) getEffectiveContextGenderLocationAndFormality(data any) (strin var gender string location := s.location formality := s.formality - if v, ok := m["Context"].(string); ok { - context = core.Trim(v) + if v, ok := mapValueString(m, "Context"); ok { + context = v } - if v, ok := m["Gender"].(string); ok { - gender = core.Trim(v) + if v, ok := mapValueString(m, "Gender"); ok { + gender = v } - if v, ok := m["Location"].(string); ok { - location = core.Trim(v) + if v, ok := mapValueString(m, "Location"); ok { + location = v } if v, ok := m["Formality"]; ok { switch f := v.(type) { @@ -479,6 +479,30 @@ func (s *Service) getEffectiveContextGenderLocationAndFormality(data any) (strin } return context, gender, location, formality } + if m, ok := data.(map[string]string); ok { + var context string + var gender string + location := s.location + formality := s.formality + if v, ok := mapValueString(m, "Context"); ok { + context = v + } + if v, ok := mapValueString(m, "Gender"); ok { + gender = v + } + if v, ok := mapValueString(m, "Location"); ok { + location = v + } + if v, ok := mapValueString(m, "Formality"); ok { + switch core.Lower(v) { + case "formal": + formality = FormalityFormal + case "informal": + formality = FormalityInformal + } + } + return context, gender, location, formality + } return "", "", s.location, s.getEffectiveFormality(data) } @@ -490,25 +514,9 @@ func (s *Service) getEffectiveContextExtra(data any) map[string]any { } return v.Extra case map[string]any: - if len(v) == 0 { - return nil - } - extra := make(map[string]any, len(v)) - for key, value := range v { - switch key { - case "Context", "Gender", "Location", "Formality": - continue - case "Extra", "extra", "Extras", "extras": - mergeContextExtra(extra, value) - continue - default: - extra[key] = value - } - } - if len(extra) == 0 { - return nil - } - return extra + return contextMapValues(v) + case map[string]string: + return contextMapValues(v) default: return nil } @@ -563,6 +571,16 @@ func (s *Service) getEffectiveFormality(data any) Formality { } } } + if m, ok := data.(map[string]string); ok { + if f, ok := mapValueString(m, "Formality"); ok { + switch core.Lower(f) { + case "formal": + return FormalityFormal + case "informal": + return FormalityInformal + } + } + } return s.formality } @@ -690,6 +708,8 @@ func missingKeyArgs(args []any) map[string]any { switch v := args[0].(type) { case map[string]any: return v + case map[string]string: + return contextMapValues(v) case *TranslationContext: return missingKeyContextArgs(v) case *Subject: diff --git a/service_test.go b/service_test.go index f608281..b0aec75 100644 --- a/service_test.go +++ b/service_test.go @@ -128,6 +128,32 @@ func TestServiceTMapContextNestedExtra(t *testing.T) { } } +func TestServiceTMapContextStringExtras(t *testing.T) { + svc, err := New() + if err != nil { + t.Fatalf("New() failed: %v", err) + } + SetDefault(svc) + + svc.AddMessages("en", map[string]string{ + "welcome._greeting": "hello", + "welcome._greeting._region._europe": "bonjour", + "welcome._greeting._region._americas": "howdy", + }) + + if got := svc.T("welcome", map[string]string{"Context": "greeting"}); got != "hello" { + t.Fatalf("T(welcome, map[string]string{Context:greeting}) = %q, want %q", got, "hello") + } + + if got := svc.T("welcome", map[string]string{"Context": "greeting", "region": "europe"}); got != "bonjour" { + t.Fatalf("T(welcome, map[string]string{Context:greeting region:europe}) = %q, want %q", got, "bonjour") + } + + if got := svc.T("welcome", map[string]string{"Context": "greeting", "region": "americas"}); got != "howdy" { + t.Fatalf("T(welcome, map[string]string{Context:greeting region:americas}) = %q, want %q", got, "howdy") + } +} + func TestServiceRaw(t *testing.T) { svc, err := New() if err != nil {